diff --git a/php/kindeditor_demo/css/article.css b/php/kindeditor_demo/css/article.css new file mode 100755 index 0000000..d7c1a58 --- /dev/null +++ b/php/kindeditor_demo/css/article.css @@ -0,0 +1,125 @@ +/*** 清楚间距 ***/ +*{ + margin: 0; + padding: 0; +} +/*** 设置字体--更新字体--字体抗锯齿 ***/ +body{ + font-family: 'Avenir Next'; + color: #000; + background: rgba(225,225,225,0.3); + -webkit-font-smoothing:antialiased;/**字体抗锯齿**/ +} + +/*** 链接重新设置 ***/ +a{ + color:#FFF; + text-decoration: none; + display: inline-block; + height: inherit; +} +a:hover{color:#f15a22;} +/****背景图片自适应*****/ +/*.main-code +{ + background: #444 url(../../../static/img/back.jpg); + background-attachment: fixed; + background-repeat: no-repeat; + background-size: cover; + background-position: center center; +}*/ + +.left-nav +{ + background: #444 url(../images/back.jpg); + /*background-attachment: fixed;*/ + background-repeat: no-repeat; + background-size: cover; + background-position: center center; + width: 20%; + height: 100%; + position:fixed; + top:0px; + left:0px; +} +.left-nav .left-summary + { + color: #FFFFFF; + font-size: 18px; + margin-left: 15px; + margin-top: 60%; + } + .left-nav .left-summary h5 + { + padding: 20px 0px; + } +.code-list{ + background: #FFFFFF; + float: right; + width: 80%; + color: #000; +} +.whow-search +{ + color: #fff; + border-color: #49be38;background: #4FC7BD;border-radius: 5px;width: 40px;text-align:center;margin:3px 3px;padding: 2px 3px; + position:fixed; + top:0px; + right:5px; + +} +.whow-search:hover{border-color: #418A84;background: #418A84;} +.code-search +{ + + color: #fff; + border-color: #49be38; + border-bottom: 4px solid; + background:#E7F0F0;border-radius: 3px;width: 80%;height:50px;text-align:center; + position:fixed; + top:0px; + right:0px; +} +.code-search>span{ + display:inline-block; + height: 40px; + line-height: 40px; + margin: 0 auto; + text-align: center; + padding: 0 5px; +} +.input-style{ + padding: 5px 15px; + font-size: 16px; + width: 160px; + border-radius: 10px; + background: #fff; + color: #535d92; + height: 20px; + line-height: 20px; + border: none; + outline:none; +} +.code-search .to-search{ + padding-left: 5px; +} +.code-search .hide-search{ + color: #fff; + height: 20px; + line-height: 20px; + padding: 0; + border-color: #49be38;background: #4FC7BD;border-radius: 5px;width: 40px;text-align:center;margin:3px 3px;padding: 0 3px; + position:fixed; + top:0px; + right:5px; +} +.code-search .hide-search:hover{border-color: #418A84;background: #418A84;} +.code-list-warper{width: 90%;padding-left: 5px;margin-top: 60px;} +.code-list-detail{border-top:1px solid #CCC;padding: 8px 0;clear: both;} +.list-left{width: 60%;float: left;margin: 5px 10px;} +.list-left span{padding-left: 40px;letter-spacing: 1px;font-size: 18px;} +.list-left h5{padding:3px;} +.list-left b{font-size: 16px;color: #ccc;margin: 0px 5px;} +.list-right{width: 30%;float: right;} +.list-right>a{float: right;margin-right: 20px;} +.list-right img{width: 150px;height: 80px;margin: 5px auto;} diff --git a/php/kindeditor_demo/demo_action.php b/php/kindeditor_demo/demo_action.php new file mode 100755 index 0000000..ed2b99f --- /dev/null +++ b/php/kindeditor_demo/demo_action.php @@ -0,0 +1,7 @@ +"; + echo "文章标题是:--------".$_POST['article_title']; + echo "
"; + echo "文章内容是是:-----".$_POST['article_content']; \ No newline at end of file diff --git a/php/kindeditor_demo/demo_add_article.html b/php/kindeditor_demo/demo_add_article.html new file mode 100755 index 0000000..50ee851 --- /dev/null +++ b/php/kindeditor_demo/demo_add_article.html @@ -0,0 +1,171 @@ + + + + + + + + + + + + + +kindeditor在qq风格上做了修改 + + +
+
+
+

Kindeditor

+
+

用法解释

+

官网

+
+
+
+ +
+ 发布文章 +
+
+ 注:这个demo 实在qq风格的基础上做了改造 +
+ 113行可以对图标进行添加或删除,比如不需要百度地图删掉 'baidumap',  即可 +
+
+
TITLE:
+
+ CONTENT:
+ + +
+
+ +
+ +
+
+ + diff --git a/php/kindeditor_demo/images/back.jpg b/php/kindeditor_demo/images/back.jpg new file mode 100755 index 0000000..4217295 Binary files /dev/null and b/php/kindeditor_demo/images/back.jpg differ diff --git a/php/kindeditor_demo/js/jquery-1.7.2.min.js b/php/kindeditor_demo/js/jquery-1.7.2.min.js new file mode 100755 index 0000000..16ad06c --- /dev/null +++ b/php/kindeditor_demo/js/jquery-1.7.2.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.2 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="
"+""+"
",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="
t
",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( +a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f +.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/.gitignore b/php/kindeditor_demo/kindeditor/.gitignore new file mode 100755 index 0000000..6bf256e --- /dev/null +++ b/php/kindeditor_demo/kindeditor/.gitignore @@ -0,0 +1,15 @@ +*~ +~* +*.diff +*.patch +*.bak +.DS_Store +Thumbs.db +.project +.*proj +.svn/ +*.swp +dist/ +node_modules/ +_build/ +attached/* diff --git a/php/kindeditor_demo/kindeditor/Gruntfile.js b/php/kindeditor_demo/kindeditor/Gruntfile.js new file mode 100755 index 0000000..2de20a9 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/Gruntfile.js @@ -0,0 +1,119 @@ + +module.exports = function(grunt) { + +var BANNER = '/* <%= pkg.name %> <%= pkg.version %> (<%= grunt.template.today("yyyy-mm-dd") %>), Copyright (C) kindsoft.net, Licence: http://kindeditor.net/license.php */\r\n'; + +var SRC_FILES = [ + 'src/header.js', + 'src/core.js', + 'src/config.js', + 'src/event.js', + 'src/html.js', + 'src/selector.js', + 'src/node.js', + 'src/range.js', + 'src/cmd.js', + 'src/widget.js', + 'src/edit.js', + 'src/toolbar.js', + 'src/menu.js', + 'src/colorpicker.js', + 'src/uploadbutton.js', + 'src/dialog.js', + 'src/tabs.js', + 'src/ajax.js', + 'src/main.js', + 'src/footer.js', +]; + +var PLUGIN_FILES = [ + 'plugins/anchor/anchor.js', + 'plugins/autoheight/autoheight.js', + 'plugins/baidumap/baidumap.js', + 'plugins/map/map.js', + 'plugins/clearhtml/clearhtml.js', + 'plugins/code/code.js', + 'plugins/emoticons/emoticons.js', + 'plugins/filemanager/filemanager.js', + 'plugins/flash/flash.js', + 'plugins/image/image.js', + 'plugins/insertfile/insertfile.js', + 'plugins/lineheight/lineheight.js', + 'plugins/link/link.js', + 'plugins/map/map.js', + 'plugins/media/media.js', + 'plugins/multiimage/multiimage.js', + 'plugins/pagebreak/pagebreak.js', + 'plugins/plainpaste/plainpaste.js', + 'plugins/preview/preview.js', + 'plugins/quickformat/quickformat.js', + 'plugins/table/table.js', + 'plugins/template/template.js', + 'plugins/wordpaste/wordpaste.js', + 'plugins/fixtoolbar/fixtoolbar.js' +]; + +var pkg = grunt.file.readJSON('package.json'); + +var lang = grunt.option('lang') || 'en'; + +grunt.initConfig({ + pkg : pkg, + concat : { + options : { + process : function(src, filepath) { + src = src.replace(/\$\{VERSION\}/g, pkg.version + ' (' + grunt.template.today('yyyy-mm-dd') + ')'); + src = src.replace(/\$\{THISYEAR\}/g, grunt.template.today('yyyy')); + src = src.replace(/\/\*\*(\r\n|\n)[\s\S]*?\*\//g, ''); + src = src.replace(/(^|\s)\/\/.*$/mg, ''); + src = src.replace(/(\r\n|\n)\/\*\*\/.*(\r\n|\n)/g, ''); + src = src.replace(/[ \t]+$/mg, ''); + src = src.replace(/(\r\n|\n){2,}/g, '$1'); + return src; + } + }, + build : { + src : SRC_FILES.concat('lang/' + lang + '.js').concat(PLUGIN_FILES), + dest : 'kindeditor-all.js' + } + }, + uglify : { + options : { + banner : BANNER, + }, + build : { + src : '<%= pkg.filename %>-all.js', + dest : '<%= pkg.filename %>-all-min.js' + } + }, + compress : { + main : { + options: { + archive: 'dist/<%= pkg.filename %>-<%= pkg.version %>-' + lang + '.zip', + }, + files: [ + {src: ['asp/**'], dest: 'kindeditor/'}, + {src: ['asp.net/**'], dest: 'kindeditor/'}, + {src: ['attached'], dest: 'kindeditor/'}, + {src: ['jsp/**'], dest: 'kindeditor/'}, + {src: ['lang/**'], dest: 'kindeditor/'}, + {src: ['php/**'], dest: 'kindeditor/'}, + {src: ['plugins/**'], dest: 'kindeditor/'}, + {src: ['themes/**'], dest: 'kindeditor/'}, + {src: ['kindeditor*.js'], dest: 'kindeditor/'}, + {src: ['license.txt'], dest: 'kindeditor/'}, + ] + } + } +}); + +grunt.loadNpmTasks('grunt-contrib-concat'); +grunt.loadNpmTasks('grunt-contrib-uglify'); +grunt.loadNpmTasks('grunt-contrib-compress'); + +grunt.registerTask('build', ['concat', 'uglify']); +grunt.registerTask('zip', ['build', 'compress']); + +grunt.registerTask('default', 'build'); + +}; diff --git a/php/kindeditor_demo/kindeditor/README.md b/php/kindeditor_demo/kindeditor/README.md new file mode 100755 index 0000000..ae2c630 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/README.md @@ -0,0 +1,14 @@ +## What is KindEditor? + +KindEditor is a lightweight, Open Source(LGPL), cross browser, web based WYSIWYG HTML editor. KindEditor has the ability to convert standard textareas to rich text editing. + +## Official site + +http://kindeditor.org/ + +## Contributors + +* Timon Lin +* daif alotaibi (http://daif.net/) : Arabic Translation +* fisker (https://github.com/fisker) : QQ style theme +* composite (https://github.com/composite) : Korean Translation \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/changelog.txt b/php/kindeditor_demo/kindeditor/changelog.txt new file mode 100755 index 0000000..fc92257 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/changelog.txt @@ -0,0 +1,663 @@ +####################################################################### +# +# KindEditor 变更记录 +# +####################################################################### + +ver 4.1.11 (2016-03-31) +* 新增: 俄语语言包,感谢Valery Votintsev (http://codersclub.org/)。 +* 改善: 语言包文件名标准化,zh_CN -> zh-CN, zh_TW -> zh-TW。 +* Bugfix: [IE6] 当前页面设置了document.domain,销毁编辑器会报错。 +* Bugfix: 行首全角空格被过滤。 +* Bugfix: 修复多语言包的一些小错误。 +* Bugfix: [IE11] 有些设备报错不能显示,对象不支持attachEvent属性或方法。 +* Bugfix: retina屏幕上按钮裂开。 +* Bugfix: 编辑图片后点击插入图片,弹出两个dialog。 + +ver 4.1.10 (2013-11-23) +* Bugfix: 兼容IE11。 +* Bugfix: [IE6-7] 上传按钮界面错乱。 +* Bugfix: 引入kindeditor-all.js后开启自动高度插件会报错。 +* Bugfix: ®来回切换代码模式后变成(R)。 +* Bugfix: 字体、文字大小、颜色等操作有toogle效果。 +* Bugfix: 非IE设置returnValue和cancelBubble。 +* Bugfix: 特定的字符导致浏览器死循环。 + +ver 4.1.9 (2013-10-08) +* Bugfix: 选中后无法添加超级链接。 +* Bugfix: 自动高度插件无法在多个编辑器上使用。 + +ver 4.1.8 (2013-10-06) +* 新增: kindeditor-all.js包含自动高度插件。 +* 新增: K.html(expr, val),K.appendHtml(expr, val),K.insertHtml(expr, val)接口。 +* 改善: IE9+都使用W3C Range。 +* 改善: 页面加载完成后也可以触发KindEditor.ready。 +* 改善: getAttributeNode已不赞成使用,用getAttribute替代。 +* Bugfix: 有些浏览器上点击边缘,可能无法弹出文件选择框。 +* Bugfix: embed宽高无法用百分比设置。 +* Bugfix: [Firefox] 输入几个文字,切换到源代码模式再切换回来,插入图片报错。 +* Bugfix: 自动高度插件高度只增不减,感谢Github用户wyqbailey贡献。 +* Bugfix: editor.html(val)的val参数为null或undefined时报错。 +* Bugfix: [IE10] 单独调用组件-上传图片弹出框,需要点击两次选择图片按钮才能弹出窗体。 +* Bugfix: 代码模式下输入带连续多个空格的标签,有些浏览器无响应。 +* Bugfix: [IE] 当两个A标签并排在一起中间没有别的内容,修改后面的链接地址时,前面的链接地址也被改掉。 +* Bugfix: 页面同时引入SWFUpload,多图上传会失败。 +* Bugfix: 插入分页符,有时候出现复制HTML代码的现象。 +* Bugfix: 编辑图片后丢失class、id等属性。 +* Bugfix: 在编辑器中输入值,页面提交跳转后,按浏览器的后退按钮,就出现__kindeditor_bookmark_start_0。 +* Bugfix: 全屏后和还原后光标没有选中之前光标的位置。 +* Bugfix: 特定环境下有时候出现两个弹出框。 +* Bugfix: [IE] 编辑表格后焦点跳到顶部。 +* Bugfix: [IE] 先选中图片后居中,再左对齐,光标跳到顶部。 + +ver 4.1.7 (2013-04-21) +* Bugfix: 取消全屏后没有恢复到原来大小,调整窗口大小后宽高变成全屏宽高。 +* Bugfix: [IE] 删除图片、Flash、视频后立即点击图片按钮出错。 +* Bugfix: [IE8] 源代码模式下输入会丢失type属性。 +* Bugfix: [IE] 输入几个文字,切换到源代码模式再切换回来,插入图片报错。 +* Bugfix: 插入5x5表格,A1向下合并两次,再点到A2,向下合并报错。 + +ver 4.1.6 (2013-03-24) +* 新增: 韩国语语言包,感谢Github用户composite贡献。 +* 新增: allowImageRemote初始化参数,可隐藏网络图片标签。 +* 改善: 插入程序代码添加是否为空的判断。 +* Bugfix: [IE9] 在frame里调用编辑器,关闭批量上传dialog时浏览器会崩溃。 +* Bugfix: 插入图片后输入文字,文字加粗后取消加粗,图片会被删除。 +* Bugfix: [IE] 工具栏被图片选中标记覆盖时有时候无法操作,比如居中对齐后再左对齐。 +* Bugfix: 全屏ESC快捷键默认未开启,但图标提示还包含ESC。 +* Bugfix: 图片上传后的url包含&时会被转换成&。 +* Bugfix: [IE] 移除编辑器后点击页面出现没有权限错误。 +* Bugfix: [IE] 输入几个文字,调用editor.html(val)后,插入表情报错。 +* Bugfix: 调用editor.resize(),退出全屏后,高度没恢复成原来的大小。 + +ver 4.1.5 (2013-01-20) +* 新增: zIndex初始化参数,可指定弹出层的z-index。 +* Bugfix: 复制粘贴3.x版本生成的文章时,可能会出现多余的空行。 +* Bugfix: 非IE浏览器插入图片或粘贴文本后,可视范围没有自动滚动到光标当前显示的位置。 +* Bugfix: [IE] 工具栏被图片选中标记覆盖时不能操作。 +* Bugfix: [Firefox] 每次按回车都会显示TypeError。 +* Bugfix: [Chrome] 纯文本粘贴1个空行会变成没有空行或者2个空行。 +* Bugfix: [IE9] input标签会丢失checked属性。 +* Bugfix: [IE8-] 未能隐藏display为none的input/select/button。 + +ver 4.1.4 (2012-11-11) +* 改善: 弹出框能够跟随滚动条滚动居中显示。 +* Bugfix: 服务器没有配置默认index.html时,百度动态地图无法加载。 +* Bugfix: 点击图片属性、超级链接属性时,冒号变成%3A。 +* Bugfix: 当页面里面有jQuery的uploadify插件时,无法连续上传。 +* Bugfix: URL包含中文时,就会变成乱码。 +* Bugfix: [Firefox] 编辑链接后回车换行,在新的段落输入内容带上面那个链接。 +* Bugfix: 繁体语言包缺少uploadSuccess属性。 +* Bugfix: [Firefox] 编辑3.x版本生成的文章时,可能会出现多余的空行。 + +ver 4.1.3 (2012-10-14) +* 新增: 百度地图可插入iframe动态地图。 +* 新增: pagebreakHtml初始化参数,可指定分页符HTML。 +* 改善: 重复执行K.create时只创建一次。 +* Bugfix: [IE] 只显示本地上传Tab时,打开图片弹出框报错。 +* Bugfix: 点击全屏后再切换回来,有时候出现JS错误。 +* Bugfix: K.addUnit(val, unit)第二个参数不起作用。 +* Bugfix: &会转义成&这样超链接就不能访问。 +* Bugfix: 表情预览失效。 +* Bugfix: [IE9] 多文件上传时不显示上传按钮。 +* Bugfix: [Chrome] 创建弹出框时,Console提示没有访问权限。 +* Bugfix: URL包含$字符时,生成错误的HTML代码。 + +ver 4.1.2 (2012-07-21) +* 新增: K.remove(expr)函数,可移除多个编辑器,expr为选择器或DOM对象。 +* 新增: K.sync(expr)函数,可同步多个编辑器,expr为选择器或DOM对象。 +* 新增: K.create(expr)、K(expr)等函数可以直接传入jQuery对象。 +* 新增: filePostName初始化参数,可指定上传文件form名称。 +* 新增: fillDescAfterUploadImage初始化参数,true时图片上传成功后切换到图片编辑标签。 +* 新增: afterSelectFile初始化参数,从图片空间选择后执行的回调函数。 +* 新增: K.NodeClass,K.RangeClass,K.CmdClass,K.EditClass,K.MenuClass等接口。 +* 新增: plugin.imageDialog(options)添加showLocal和showRemote参数,值为false时分别隐藏网络图片和本地上传。 +* 新增: afterUpload新增data和name参数,分别为后端返回的JSON数据和插件名称。 +* 变更: fullscreenShortcut默认值改成false,默认不启用ESC快捷键全屏。 +* 改善: 多图上传时,允许用户post自定义参数到服务器。 +* Bugfix: [Firefox] 居中后输入几个文字回车换行,内容被全选。 +* Bugfix: 批量上传无法执行afterUpload这个回调,普通上传可以执行。 +* Bugfix: 页面中存在其它SWFUpload,批量上传出现冲突。 +* Bugfix: IE8怪异模式下先打开弹出框关闭,用滚轮到顶或到底,会出现脚本错误。 +* Bugfix: 图片src为图片数据(base64 data)时,无法正常显示。 +* Bugfix: 在pre标签里无法粘贴内容。 +* Bugfix: KNode.show()和hide(),display都变成block。 +* Bugfix: 版权标识©来回切换代码模式后变成(C)。 +* Bugfix: 重新创建KNode后,data方法无法取得数据。 +* Bugfix: K.create函数未找到目标textarea时报错。 +* Bugfix: 右下角拖动,松开鼠标后还可以继续拖动。 +* Bugfix: 右键编辑表格,插入行和列时有时候错乱。 + +ver 4.1.1 (2012-06-10) +* 新增: extraFileUploadParams初始化参数,文件上传时,支持添加别的参数一并传到服务器。 +* 变更: filterMode默认值改成true,根据htmlTags配置过滤HTML代码。 +* Bugfix: [Chrome] 粘贴内容代码中出现white-space:nowrap导致不换行。 +* Bugfix: [IE6] 本地图片上传按钮错位。 +* Bugfix: 开启过滤模式后,预览内容显示KindEditor。 + +ver 4.1 (2012-05-12) +* 新增: 批量图片上传功能(multiimage)。 +* 新增:地图默认用百度地图(baidumap)。 +* 新增: QQ邮箱风格(贡献者:https://github.com/fisker)。 +* 新增: formatUploadUrl初始化参数,false时不会自动格式化上传后的URL。 +* 新增: fullscreenShortcut初始化参数,false时禁用ESC全屏快捷键。 +* 改善: uploadbutton新增form、target参数,上传图片时可提交其它控件。 +* 改善: K().children()直接返回KNode对象,原来是返回Array。 +* 改善: K.create()支持多个textarea,新增KindEditor.instances。 +* 改善: Opera 最新版本支持BR换行。 +* 改善: 当前页面的语言方向为rtl时,编辑区域也自动设置rtl。 +* 改善: PHP写入临时文件失败,提示详细错误。 +* Bugfix: [IE9] 上传图片的弹出窗口,最下方的“确定”“取消”会错位,跑到跟“图片说明”文本框的后面。 +* Bugfix: FF、Chrome、Opera等行首全角空格被过滤,只有IE没问题。 +* Bugfix: 图片正在上传时,连续点击确定按钮,会重复提交表单。 +* Bugfix: [WEBKIT] 在BR换行模式下,需要两次回车才能换行。 +* Bugfix: [IE9] 在BR换行模式下,在编辑器中回车之后,光标仍然还在本行,不会移动到下一行。 +* Bugfix: noscript里的HTML代码会被转移字符。 +* Bugfix: [ASP] 文件管理对大小写敏感,大写的文件扩展名会识别不出图片。 +* Bugfix: 浏览文件窗口里的目录和文件图标被拉伸,看起来比较模糊。 +* Bugfix: 带有超链接的图片删除以后,源代码里面还有A标签。 +* Bugfix: 通过文件管理器插入本地附件时,URL可能出现连续两个斜线。 + +ver 4.0.6 (2012-03-18) +* 新增: imageTabIndex初始化参数,可设置插入图片弹出层的默认显示标签。 +* 新增: allowFileUpload初始化参数,可设置是否显示插入文件弹出层里的上传按钮。 +* 新增: KNode类增加eq方法。 +* 改善: 改进弹出框样式。 +* 改善: 上传图片不选择文件提交时,在浏览器端验证并提示。 +* 改善: 优化自动排版,块元素的第一个子节点是图片时不加缩进。 +* 改善: 编辑表格时,点击文档会关闭取色器。 +* Bugfix: [IE] 先选中图片,编辑图片后关闭Dialog,有时候会出现脚本错误。 +* Bugfix: 修改plugins目录名,无法显示plugins目录下的图片。 +* Bugfix: [IE] 上传图片后,进度条一直处于加载状态。 +* Bugfix: [IE] 上传文件失败后,进度条一直处于加载状态。 +* Bugfix: form添加onsubmit="return false;",提交表单,编辑器转到代码模式就出错。 +* Bugfix: [FF] 按下全屏按钮,恢复到原来大小后没有滚动条。 +* Bugfix: 自动获取图片尺寸时,有时候得到的尺寸不准确。 +* Bugfix: [IE] 在跨域的frame里调用编辑器,会出现权限错误。 +* Bugfix: 全屏后form失去自动提交,reset功能也失效。 +* Bugfix: 已经引入的default.css带时间戳时会重复加载CSS。 + +ver 4.0.5 (2012-01-15) +* Bugfix: 页面添加 content="IE=EmulateIE7" 后,修改颜色、行距之类的操作全部失效。 +* Bugfix: 后退(Ctrl+Z)时光标错乱。 +* Bugfix: 通过粘贴纯文本框粘贴时,所有空格都变成 。 +* Bugfix: pasteType参数为1时,粘贴内容,多个空格变成一个空格。 +* Bugfix: [FF] 上传图片后,总是出现正在加载的样式。 +* Bugfix: [WEBKIT] event.layerX and event.layerY are broken and deprecated in WebKit. +* Bugfix: pasteType为1(纯文本粘贴模式)时,粘贴的内容会换行。 +* Bugfix: 在iOS5上无法使用编辑器。 +* Bugfix: 单独调用dialog时默认不显示阴影。 +* Bugfix: 初始化编辑器时,在afterChange回调函数里无法得到this.edit对象。 + +ver 4.0.4 (2011-12-11) +* 新增: 阿拉伯语语言包。 +* 改善: 上传文件时显示上传中提示。 +* 改善: JSON解析失败时,通过弹出层显示服务器返回的HTML页面。 +* 改善: [IE] 弹出框支持阴影效果。 +* Bugfix: 浏览器使用有些插件时,上传文件提示不正确。 +* Bugfix: 单独调用图片功能时,点击重置大小图标报错。 +* Bugfix: 设置了参数filterMode:true,分页符就会丢失样式。 +* Bugfix: [FF] 撤销全屏后页面会滚动到顶部。 +* Bugfix: [ASP] demo.asp没有指定编码,导致提交后HTML出现乱码。 +* Bugfix: 单独调用上传按钮时,无法与旁边输入框对齐。 +* Bugfix: [WEBKIT] 在图片、视频、flash等前一个光标处右键,在不选中节点的状态下也能弹出修改属性。 +* Bugfix: [IE] 编辑器无内容,加粗,切换到代码模式,再回到可视化模式,加粗,JS报错。 +* Bugfix: [IE] 插入,会自动变为 。 +* Bugfix: [WEBKIT] 点击粗体后丢失光标。 +* Bugfix: [OPERA] 切换到代码模式后不显示部分工具栏图标。 +* Bugfix: del标签被定义在块级元素里,导致格式化HTML时自动换行。 +* Bugfix: 开启过滤模式,获取HTML时删除线被过滤。 +* Bugfix: [IE] 两张相邻图片添加超级链接,修改其中一个链接,另外一个链接也会被修改。 +* Bugfix: 内嵌脚本的小于号会被转义导致脚本错误。 +* Bugfix: 分页符在不同浏览器下生成的HTML代码不一致。 +* Bugfix: [IE6-7] 插入URL里有大写字符的图片,右键点击选择图片属性,更改图片属性后图片不能显示。 + +ver 4.0.3 (2011-11-04) +* Bugfix: [IE] 残留range.dump()调试代码,导致粘贴时报错。 +* Bugfix: [IE] 存在menu全局变量,可能发生冲突。 +* Bugfix: [IE] 单元格里没有内容时显示不正常。 +* Bugfix: 连续按粗体按钮时会生成很多strong。 +* Bugfix: 初始化编辑器后,按下粗体按钮,焦点不在

标签里。 +* Bugfix: [WEBKIT] 设定图片右对齐后,无法选取图片节点。 +* Bugfix: [IE] 回车,按下tab键,光标在下一行显示。 +* Bugfix: [IE] textarea的高度小于工具栏高度时JS报错。 + +ver 4.0.2 (2011-10-30) +* 新增: 上传按钮新增afterError回调函数,可定制JSON错误。 +* Bugfix: [FF] 在页面上设置iframe {overflow:hidden;} ,编辑区域不出现滚动条。 +* Bugfix: 浏览服务器插件,文件名很长的时候会换行。 +* Bugfix: [IE6-7] 在form里引入js的时候出现JS错误。 +* Bugfix: [IE] 当编辑器为空时,输入任意字符,然后点击表单的重置按钮,再点击页面空白处,出现JS错误。 +* Bugfix: [IE8] 设置X-UA-Compatible=IE7,有时候无法加载编辑器。 +* Bugfix: a标签同时有name和href属性时,丢失name以外的属性。 +* Bugfix: 连续调用多个ready函数时,第4个ready无法执行。 +* Bugfix: 插入多媒体后,右键点击不会弹出菜单。 +* Bugfix: 启用纯文本黏贴后,段落首尾都会出现>符号。 +* Bugfix: [IE] 点击标题、字体、文字大小,编辑区域失去选中状态。 +* Bugfix: [FF,WEBKIT] 连续换行几次,切换到源代码,再切换到可视化模式,没有换行效果。 +* Bugfix: [WEBKIT] 选择几个文字,点击上标或下标功能,上下标格式不会被应用。 +* Bugfix: 加载编辑器后残留多余的div标签。 +* Bugfix: 页面上包含跨域iframe的时候JS报错。 +* Bugfix: 页面刷新后,与第一次访问加载的编译器高度不一致。 +* Bugfix: [IE6] 弹出层无法遮住selectbox。 +* Bugfix: [FF] 提交后退后,编辑器数据不保存。 +* Bugfix: 选择粗体,取消粗体再应用粗体(即点两下粗体),则发现粗体、倾斜、下划线功能失效,无法选择。 +* Bugfix: [WEBKIT] 置入Issue 269中的HTML,全选,点击删除格式,又出现一个图片,图片变为两个。 +* Bugfix: 与MooTools类库有冲突。 +* Bugfix: [IE] 选中粘贴过来的文本,进行格式操作时位置出现偏移。 +* Bugfix: [IE] 后退前进时有时候报错。 + +ver 4.0.1 (2011-10-07) +* 改善: image插件,通过editor.plugin.imageDialog()可以单独调用图片弹出框。 +* 改善: filemanager插件,Ajax请求时显示Loading效果。 +* 改善: 工具栏图标改成png8格式。 +* Bugfix: 不能用style的width和height设置编辑器大小。 +* Bugfix: 从MS WORD里面拷贝过来的表格,表格的颜色会丢掉。 +* Bugfix: [IE] 关闭弹出层后光标自动跳转到顶部。 +* Bugfix: 添加链接时有时候出现__kindeditor_temp_url__。 +* Bugfix: [IE] 点击工具栏后,编辑区域失去选中状态。 +* Bugfix: 网速比较慢的时候,连续点击一个图标,弹出多个弹出框。 +* Bugfix: 删除格式时不能删除段落缩进属性。 +* Bugfix: 拖拉改变Flash大小,点击源代码再点回来,Flash长宽自动恢复成预设值。 + +ver 4.0 (2011-09-26) +* 新增: 锚点功能。 +* 新增: 增加loadStyleMode属性,默认情况下自动加载CSS文件。 +* 新增: 编辑器对象增加isDirty方法,判断编辑器内容是否有修改。 +* 改善: 粘贴MS Word时自动清理Word专用格式代码,生成干净的HTML代码。 +* 改善: 弹出框(dialog)里的输入框添加了基本验证。 +* 改善: 超级链接不允许包含HTML代码。 +* 改善: uploadJson URL支持GET参数。 +* 优化: 后退撤销,粘贴性能。 +* BUG: 修复了allowImageUpload为false时,无法插入网络图片的问题。 +* BUG: [WEBKIT] 修复了粘贴内容时顺序相反的问题。 +* BUG: 修复了进行修改操作,再选择一段带有样式的文字,再进行撤销操作,首先撤销的是选取操作,然后才会撤销修改的问题。 +* BUG: 修复了设置basePath参数后,themesPath、langPath、pluginsPath参数不起作用的问题。 +* BUG: 修复了图片和超级连接URL输入双引号时,HTML代码出现错乱的问题。 +* BUG: [IE] 修复了反复执行后退和前进时有时候出现脚本错误的问题。 +* BUG: [IE] 修复了连续选择相同文件上传时,第二次开始无法上传的问题。 +* BUG: [IE] 修复了textarea在p标签里时,无法创建编辑器的问题。 +* BUG: 修复了filterMode为true时,没有过滤script和style内容的问题。 +* BUG: [WEBKIT] 修复了粘贴内容后光标消失的问题。 +* BUG: [IE7] 修复了上传按钮出现偏移的问题。 +* BUG: [IE] 修复了innerHTML有时候抛出异常的问题。 +* BUG: 修复了清除HTML代码时过滤rowspan和colspan,导致表格被破坏的问题。 +* BUG: 修复了在框架(frameset)下面,点击编辑器的源代码按钮后,再点击其它连接变弹出显示的问题。 +* BUG: 修复了在非IE浏览器上,插入表格后,鼠标无法移到表格下面输入文字的问题。 +* BUG: [WEBKIT] 修复了回车换行后标题属性丢失的问题。 +* BUG: [WEBKIT] 修复了粘贴到单元格时有时候粘贴错位的问题。 +* BUG: 修复了删除格式时有时候丢失文字的问题。 +* BUG: [IE] 修复了在HTML里有inline-block时有时候_getStartEnd报错的问题。 +* BUG: 修复了打开地图后立即关闭窗口时,无法关闭的问题。 +* BUG: 修复了insertHtml插入注释开头的HTML时,注释被过滤的问题。 + +ver 4.0 beta (2011-08-17) +* BUG: 修复了域名包含端口时在IE上发生错误的问题。 +* BUG: 修复了在IE上通过工具栏的undo/redo按钮进行undo/redo时无法后退的问题。 +* BUG: 修复了在FF和IE上加载编辑器后生成一个history的问题。 +* BUG: 修复了在IE上点击右键自动插入 的问题。 +* BUG: 修复了在IE上文本在table标签前时,原生range转换成标准range后出现偏移的问题。 +* BUG: 修复了在WEBKIT系列浏览器上在全屏模式下,弹出的插入图片、超链接等对话框,输入框内无法粘贴内容的问题。 +* BUG: 修复了在pre标签里回车加入空行无效的问题。 +* BUG: 修复了切换到代码模式后,按全屏报错的问题。 +* BUG: 修复了点击工具栏时有时候弹出来几个相同dialog的问题。 +* BUG: 修复了在IE上项目编号无论选在到哪里都是第一行加编号的问题。 +* BUG: 修复了焦点处于被合并的单元格,右键菜单,向上添加一行,表格错乱的问题。 +* BUG: 修复了焦点处于被合并的单元格的上一个单元格,右键菜单,向下合并单元格,表格错乱的问题。 +* BUG: 修复了在IE上点击编辑区域时内存一直增加的问题。 + +ver 4.0 alpha (2011-08-16) +* 初期版本,重新编写所有代码。 +* 新增: 插入程序代码、预览、插入地图、调整行距、一键排版、清理HTML代码、插入分页符、插入附件、插入模板功能。 +* 新增: Flash、多媒体编辑功能,Flash、多媒体上传功能。 +* 新增: 表格单元格的合并和拆分功能。 +* 新增: ESC键切换全屏模式。 +* 改善: 后退/前进(undo/redo)时保持选中状态。 +* 改善: 大部分组件实现模块化,可以单独调用。 +* 改善: 改进了HTML格式化功能。 +* 改善: 粘贴纯文本时按照换行设置(newlineTag)换行。 +* 改善: 滚动页面时dialog自动居中。 +* 改善: 在移动设备上只能使用代码模式。 +* 改善: 修改图片尺寸时自动保持比例。 +* BUG: 修复了在页面上设置document.domain时发生错误的问题。 +* BUG: 修复了跨域调用编辑器时无法使用dialog的问题。 +* BUG: 修复了range的collapsed为true时删除格式不起作用的问题。 +* BUG: [WEBKIT] 修复了range的collapsed为true时字体、颜色等无效的问题。 +* BUG: 修复了在不同浏览器上加粗、斜体、下划线、删除线生成出来的HTML代码不一致的问题。 +* BUG: 修复了全选后有时候不能清除格式的问题。 +* BUG: 修复了工具栏经常受全局CSS影响的问题。(改用DIV布局) +* BUG: 修复了直接拷贝页面自动执行js代码的问题。 +* BUG: 修复了页面底部显示右键菜单被挡住的问题。 +* BUG: 修复了在HTML里存在不规则属性("="")时过滤不掉其它属性的问题。 +* BUG: 修复了处理被合并过的单元格时发生错误的问题。 + +ver 3.5.6 (2011-10-04) +* 增加: 新增afterDrag属性(回调函数),拖动改变编辑器大小后执行。 +* 增加: 新增afterUpload属性(回调函数),上传成功后执行。 +* BUG: 修复了工具栏受全局a:hover的影响的问题。 +* BUG: 修复了在全屏模式下编辑器可以被拖动的问题。 +* BUG: [ASP]不改变文件名并上传中文名文件时文件名出现乱码。 +* BUG: [IE9]删除格式功能有时候不起作用。 +* BUG: [IE9]添加样式时有时候报错。 + +ver 3.5.5 (2011-05-22) +* 增加: 新增单元格编辑功能。 +* 改善: 改进输入框和按钮的外观。 +* 改善: 打开dialog后自动选中第一个输入框。 +* 改善: 用CSS实现dialog的阴影。 +* 改善: 插入图片时不设置border="0"属性。 +* BUG: 修改了在IE9上上传图片后原来的内容全部消失的问题。 +* BUG: 修改了在FF4上有时候无法插入图片的问题。 +* BUG: 修改了在IE6上插入图片后,在图片前出现一个空格的问题。 +* BUG: 修改了在IE上使用清除格式功能来删除一段加粗的文字时发生JS错误的问题。(只有压缩后的min有这个问题) + +ver 3.5.4 (2011-05-01) +* 改善: 直接兼容IE9。 +* BUG: 修改了在源代码模式下输入JS代码后切换到可视化模式时会执行JS代码的问题。 +* BUG: 修改了在IE上编辑区域里的选中select控件时出现JS错误的问题。 +* BUG: 修改了在IE上通过KE.insertHtml函数输入URL时丢失标签的问题。 +* BUG: 修改了在一个页面调用多个编辑器时重复加载相同CSS的问题。 +* BUG: 修改了在一个页面包含多个kindeditor.js时无法打开dialog的问题。 +* BUG: 移除了工具栏里的两对多余的tr标签。 + +ver 3.5.3 (2011-04-09) +* 增加: 新增useContextmenu属性,值为true时使用自定义右键菜单,false时屏蔽自定义右键菜单,默认值为true。 +* 增加: 新增syncType属性,值为"auto"时每次修改时都会同步,"form"时提交form时同步,""时不会自动同步,默认值为"form"。 +* 增加: 新增tabIndex属性,可设置编辑器的tabindex。 +* 增加: 新增afterChange属性(回调函数),编辑器内容发生变化后执行的函数。 +* 增加: 新增afterTab属性(回调函数),按下TAB键后执行的函数,默认情况下插入4个空格。 +* 增加: 新增afterFocus属性(回调函数),编辑器获得焦点(onfocus)时执行的函数。 +* 增加: 新增afterBlur属性(回调函数),编辑器失去焦点(onblur)时执行的函数。 +* 增加: 新增KE.sync函数,将编辑器数据设回到原来的textarea里,与KE.util.setData函数功能相同。 +* 增加: 新增KE.blur函数,让编辑器失去焦点。 +* 改变: 将autoSetDataMode的默认值改成false,默认情况下自动寻找所属form,并将KE.sync绑定到该form的submit事件里。 +* 改善: fileManagerJson支持GET参数。 +* 改善: 动态设置上传图片保存URL(save_url),在不同深度的页面调用编辑器不会出错。 +* 改善: 当编辑器属性newlineTag为p时,粘贴纯文本换行使用p标签。 +* 改善: 编辑器id支持[a-z0-9_]以外的特殊字符。 +* 改善: 上传图片按日期目录保存。 +* 改善: 在IE6和IE7上浏览器原生菜单包含复制粘贴选项。 +* BUG: 在IE上通过showModalDialog显示编辑器时无法输入内容。 +* BUG: 修改了删除列时单元格错位的问题。 +* BUG: 修改了在Firefox下点击dialog的按钮后没有按下去的效果的问题。 +* BUG: 有些浏览器无法解析[\w-:],需对“-”进行转义[\w\-:]。 +* BUG: 执行KE.html后有时候全选整个编辑区域。 +* BUG: 在Mac OS X的Firefox上无法显示右键菜单。 +* BUG: script标签内的JavaScript代码字符串里包含HTML代码时,该字符串也被格式化。 +* BUG: 修改了ASP浏览图片程序无法进入子目录的问题。 +* BUG: 修改了通过TAB键移动焦点时焦点移动到工具栏图标上的问题。 + +ver 3.5.2 (2010-12-02) +* BUG: 修改了在IE下拖动调整大小不够顺畅的问题。 +* BUG: 修改了在IE下JS的src为"kindeditor.js"时无法加载CSS文件的问题。 +* BUG: 提高上传图片JSON格式兼容性,防止某些时候因服务器输出额外的数据而导致JSON解析失败的问题。 +* BUG: 修改了在IE上某些情况下添加样式偏移的问题。 +* BUG: 修改了在IE下焦点在图片后面时按下TAB键JS报错的问题。 +* BUG: 修改了KE.util.setOpacity的opacity为2和20时结果相同的问题。 +* BUG: 修改了在IE6下高度小于0时出现脚本错误的问题。 + +ver 3.5.1 (2010-07-18) +* BUG: 修改了表格左侧插入列时单元格移位的问题。 +* BUG: 修改了在Firefox上设置全局CSS后高度计算不正确的问题。 +* BUG: 修改了ASP上传程序无法上传大写扩展名文件的问题。 +* BUG: 修改了在Firefox上调用KE.html函数在某些情况下JS报错的问题。 +* BUG: 修改了在IE6、IE7上只读模式下不显示内容的问题。 +* BUG: 修改了JSP演示程序提交中文数据后出现乱码的问题。 +* BUG: 修改了通过insertHtml插入HTML时URL自动变成绝对域名的问题。 +* BUG: 修改了在IE上用BR换行时回车换行自动选中下面内容的问题。 +* BUG: 修改了设置表格背景颜色后不能取消颜色的问题。 + +ver 3.5 (2010-06-20) +* 增加: 增加了表格编辑功能。 +* 增加: 引入了多国语言机制。 +* 增加: 标题、字体、文字大小、颜色可以反映当前状态。 +* 增加: 右键菜单支持图标和分割线。 +* 增加: 表情功能增加分页和预览。 +* 增加: 增加了弹出框阴影效果。 +* 增加: 增加了新接口。(KE.html,KE.text,KE.selectedHtml,KE.insertHtml,KE.appendHtml,KE.isEmpty等) +* 改善: 编辑器底部显示向下拖动指示图标。 +* 改善: 点击编辑器外的页面其它部位时关闭菜单。 +* 改善: 移除编辑器时将编辑器内容设置到原来的textarea。 +* 改善: 从外部粘贴内容时自动将font转换成span标签。 +* 改善: ASP.NET程序改成ashx,使用时不需要编译。 +* BUG: 改善了文章内容比较多时速度比较慢的问题。 +* BUG: 修改了在IE上选中图片或表格后无法用backspace键删除的问题。 +* BUG: 修改了在Firefox上全屏后浏览器一直处于加载状态的问题。 +* BUG: 修改了在非IE上DOMContentLoaded事件不起作用的问题。 +* BUG: 修改了删除编辑器时没有销毁事件的问题。 +* BUG: 修改了设置成无颜色时其它样式也被删除的问题。 +* BUG: 修改了拖动时拖到浏览器外面放开鼠标后会粘住的问题。 +* BUG: 修改了在Firefox上pre标签自动生成br标签的问题。 +* BUG: 修改了在IE6上用KE.cmd.wrap方法设置class属性后没有效果的问题。 +* BUG: 修改了在P标签内没选中内容时无法插入超级链接的问题。 +* BUG: 修改了使用快捷键加粗体、斜体、下划线时没有同步的问题。 + +ver 3.4.4 (2010-06-01) +* BUG: 修改了在IE上焦点自动移动到编辑区域的问题。 +* BUG: 修改了在IE上打开类型无法修改成当前窗口的问题。 +* BUG: 修改了全选后无法取消超级链接的问题。 +* BUG: 修改了切换代码模式时编辑器轻微抖动的问题。 +* BUG: 修改了在IE上切换代码模式时有时候不出现滚动条的问题。 +* BUG: 修改了在Chrome 5.0上反复切换代码模式有时候出现崩溃页面的问题。 +* 改善: 显示菜单后再点将关闭此菜单。 + +ver 3.4.3 (2010-05-26) +* BUG: 修改了重复编辑超级链接时每次都添加&的问题。 +* BUG: 修改了在IE上右键菜单没有复制、剪切项目的问题。 +* BUG: 修改了在IE上没有格式化代码的问题。 +* BUG: 修改了PHP上传程序日期格式不正确的问题。 +* BUG: 修改了在IE上代码模式下全屏本地URL自动变成绝对URL的问题。 +* BUG: 修改了在代码模式下KE.util.setFullHtml函数不显示HTML内容的问题。 +* BUG: 修改了在MARQUEE元素里回车换行出现JS错误的问题。 +* BUG: 修改了通过菜单剪切、粘贴时不触发KE.event.input事件的问题。 +* BUG: 修改了在IE上焦点离开编辑区域后没有记住最后的range位置的问题。 +* BUG: 修改了在源代码模式下undo/redo能看到临时HTML代码的问题。 +* BUG: 修改了在IE上输入的HTML开头是 + + + +.. index:: langType + +.. _langType: + +langType +-------------------------------------------------------- +指定语言,可设置"en"、"zh-CN",需要引入lang/[langType].js。 + +* 数据类型: String +* 默认值: "zh-CN" + +示例: + +.. sourcecode:: html + + + + + + +.. index:: designMode + +.. _designMode: + +designMode +-------------------------------------------------------- +可视化模式或代码模式 + +* 数据类型: Boolean +* 默认值: true + +.. index:: fullscreenMode + +.. _fullscreenMode: + +fullscreenMode +-------------------------------------------------------- +true时加载编辑器后变成全屏模式。 + +* 数据类型: Boolean +* 默认值: false + +.. index:: basePath + +.. _basePath: + +basePath +-------------------------------------------------------- +指定编辑器的根目录路径。 + +* 数据类型: String +* 默认值: 根据kindeditor.js文件名自动获取 + +.. index:: themesPath + +.. _themesPath: + +themesPath +-------------------------------------------------------- +指定编辑器的themes目录路径。 + +* 数据类型: String +* 默认值: basePath + 'themes/' + +.. index:: pluginsPath + +.. _pluginsPath: + +pluginsPath +-------------------------------------------------------- +指定编辑器的plugins目录路径。 + +* 数据类型: String +* 默认值: basePath + 'plugins/' + +.. index:: langPath + +.. _langPath: + +langPath +-------------------------------------------------------- +指定编辑器的lang目录路径。 + +* 数据类型: String +* 默认值: basePath + 'lang/' + +.. index:: minChangeSize + +.. _minChangeSize: + +minChangeSize +-------------------------------------------------------- +undo/redo文字输入最小变化长度,当输入的文字变化小于这个长度时不会添加到undo记录里。 + +* 数据类型: String +* 默认值: 5 + +.. index:: urlType + +.. _urlType: + +urlType +-------------------------------------------------------- +改变站内本地URL,可设置""、"relative"、"absolute"、"domain"。空为不修改URL,relative为相对路径,absolute为绝对路径,domain为带域名的绝对路径。 + +* 数据类型: String +* 默认值: "" + +.. index:: newlineTag + +.. _newlineTag: + +newlineTag +-------------------------------------------------------- +设置回车换行标签,可设置"p"、"br"。 + +* 数据类型: String +* 默认值: "p" + +.. index:: pasteType + +.. _pasteType: + +pasteType +-------------------------------------------------------- +设置粘贴类型,0:禁止粘贴, 1:纯文本粘贴, 2:HTML粘贴 + +* 数据类型: Int +* 默认值: 2 + +.. index:: dialogAlignType + +.. _dialogAlignType: + +dialogAlignType +-------------------------------------------------------- +设置弹出框(dialog)的对齐类型,可设置""、"page",指定page时按当前页面居中,指定空时按编辑器居中。 + +* 数据类型: String +* 默认值: "page" + +.. index:: shadowMode + +.. _shadowMode: + +shadowMode +-------------------------------------------------------- +true时弹出层(dialog)显示阴影。 + +* 数据类型: Boolean +* 默认值: true + +.. index:: zIndex + +.. _zIndex: + +zIndex +-------------------------------------------------------- +指定弹出层的基准z-index。 + +* 数据类型: Int +* 默认值: 811213 + +.. index:: useContextmenu + +.. _useContextmenu: + +useContextmenu +-------------------------------------------------------- +true时使用右键菜单,false时屏蔽右键菜单。 + +* 数据类型: Boolean +* 默认值: true + +.. index:: syncType + +.. _syncType: + +syncType +-------------------------------------------------------- +同步数据的方式,可设置""、"form",值为form时提交form时自动同步,空时不会自动同步。 + +* 数据类型: String +* 默认值: "form" + +.. index:: indentChar + +.. _indentChar: + +indentChar +-------------------------------------------------------- +:ref:`wellFormatMode` 为true时,HTML代码缩进字符。 + +* 数据类型: String +* 默认值: "\\t" + +.. index:: cssPath + +.. _cssPath: + +cssPath +-------------------------------------------------------- +指定编辑器iframe document的CSS文件,用于设置可视化区域的样式。 + +* 数据类型: String或Array +* 默认值: 空 + +.. index:: cssData + +.. _cssData: + +cssData +-------------------------------------------------------- +指定编辑器iframe document的CSS数据,用于设置可视化区域的样式。 + +* 数据类型: String +* 默认值: 空 + +.. index:: bodyClass + +.. _bodyClass: + +bodyClass +-------------------------------------------------------- +指定编辑器iframe document body的className。 + +* 数据类型: String +* 默认值: "ke-content" + +.. index:: colorTable + +.. _colorTable: + +colorTable +-------------------------------------------------------- +指定取色器里的颜色。 + +* 数据类型: Array +* 默认值: + +.. sourcecode:: js + + [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ] + +.. index:: afterCreate + +.. _afterCreate: + +afterCreate +-------------------------------------------------------- +设置编辑器创建后执行的回调函数。 + +* 数据类型: Function +* 默认值: 无 + +.. index:: afterChange + +.. _afterChange: + +afterChange +-------------------------------------------------------- +编辑器内容发生变化后执行的回调函数。 + +* 数据类型: Function +* 默认值: 无 + +.. index:: afterTab + +.. _afterTab: + +afterTab +-------------------------------------------------------- +按下TAB键后执行的的回调函数。 + +* 数据类型: Function +* 默认值: 插入4个空格的函数 + +.. index:: afterFocus + +.. _afterFocus: + +afterFocus +-------------------------------------------------------- +编辑器聚焦(focus)时执行的回调函数。 + +* 数据类型: Function +* 默认值: 无 + +.. index:: afterBlur + +.. _afterBlur: + +afterBlur +-------------------------------------------------------- +编辑器失去焦点(blur)时执行的回调函数。 + +* 数据类型: Function +* 默认值: 无 + +.. index:: afterUpload + +.. _afterUpload: + +afterUpload +-------------------------------------------------------- +上传文件后执行的回调函数。 + +* 数据类型: Function +* 默认值: 无 + +.. sourcecode:: js + + KindEditor.ready(function(K) { + K.create('#id', { + afterUpload : function(url) { + alert(url); + } + }); + }); + +.. index:: uploadJson + +.. _uploadJson: + +uploadJson +-------------------------------------------------------- +指定上传文件的服务器端程序。 + +* 数据类型: String +* 默认值: basePath + 'php/upload_json.php' + +.. index:: fileManagerJson + +.. _fileManagerJson: + +fileManagerJson +-------------------------------------------------------- +指定浏览远程图片的服务器端程序。 + +* 数据类型: String +* 默认值: basePath + 'php/file_manager_json.php' + +.. index:: allowPreviewEmoticons + +.. _allowPreviewEmoticons: + +allowPreviewEmoticons +-------------------------------------------------------- +true时鼠标放在表情上可以预览表情。 + +* 数据类型: Boolean +* 默认值: true + +.. index:: allowImageUpload + +.. _allowImageUpload: + +allowImageUpload +-------------------------------------------------------- +true时显示图片上传按钮。 + +* 数据类型: Boolean +* 默认值: true + +.. index:: allowFlashUpload + +.. _allowFlashUpload: + +allowFlashUpload +-------------------------------------------------------- +true时显示Flash上传按钮。 + +* 数据类型: Boolean +* 默认值: true + +.. index:: allowMediaUpload + +.. _allowMediaUpload: + +allowMediaUpload +-------------------------------------------------------- +true时显示视音频上传按钮。 + +* 数据类型: Boolean +* 默认值: true + +.. index:: allowFileUpload + +.. _allowFileUpload: + +allowFileUpload +-------------------------------------------------------- +true时显示文件上传按钮。 + +* 数据类型: Boolean +* 默认值: true + +.. note:: + + 4.0.6版本开始支持。 + +.. index:: allowFileManager + +.. _allowFileManager: + +allowFileManager +-------------------------------------------------------- +true时显示浏览远程服务器按钮。 + +* 数据类型: Boolean +* 默认值: false + +.. index:: fontSizeTable + +.. _fontSizeTable: + +fontSizeTable +-------------------------------------------------------- +指定文字大小。 + +* 数据类型: Array +* 默认值: + +.. sourcecode:: js + + ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'] + +.. index:: imageTabIndex + +.. _imageTabIndex: + +imageTabIndex +-------------------------------------------------------- +图片弹出层的默认显示标签索引。 + +* 数据类型: Int +* 默认值: 0 + +.. note:: + + 4.0.6版本开始支持。 + +.. index:: formatUploadUrl + +.. _formatUploadUrl: + +formatUploadUrl +-------------------------------------------------------- +false时不会自动格式化上传后的URL。 + +* 数据类型: Boolean +* 默认值: true + +.. note:: + + 4.1版本开始支持。 + +.. index:: fullscreenShortcut + +.. _fullscreenShortcut: + +fullscreenShortcut +-------------------------------------------------------- +false时禁用ESC全屏快捷键。 + +* 数据类型: Boolean +* 默认值: false + +.. note:: + + 4.1版本开始支持,从4.1.2版本开始默认值为false。 + +.. index:: extraFileUploadParams + +.. _extraFileUploadParams: + +extraFileUploadParams +-------------------------------------------------------- +上传图片、Flash、视音频、文件时,支持添加别的参数一并传到服务器。 + +* 数据类型: Array +* 默认值: {} + +.. sourcecode:: js + + KindEditor.ready(function(K) { + K.create('#id', { + extraFileUploadParams : { + item_id : 1000, + category_id : 1 + } + }); + }); + +.. note:: + + 4.1.1版本开始支持。 + +.. index:: filePostName + +.. _filePostName: + +filePostName +-------------------------------------------------------- +指定上传文件form名称。 + +* 数据类型: String +* 默认值: imgFile + +.. note:: + + 4.1.2版本开始支持。 + +.. index:: fillDescAfterUploadImage + +.. _fillDescAfterUploadImage: + +fillDescAfterUploadImage +-------------------------------------------------------- +true时图片上传成功后切换到图片编辑标签,false时插入图片后关闭弹出框。 + +* 数据类型: Boolean +* 默认值: false + +.. note:: + + 4.1.2版本开始支持。 + +.. index:: afterSelectFile + +.. _afterSelectFile: + +afterSelectFile +-------------------------------------------------------- +从图片空间选择文件后执行的回调函数。 + +* 数据类型: Function +* 默认值: 无 + +.. note:: + + 4.1.2版本开始支持。 + +.. index:: pagebreakHtml + +.. _pagebreakHtml: + +pagebreakHtml +-------------------------------------------------------- +可指定分页符HTML。 + +* 数据类型: String +* 默认值: `


` + +.. note:: + + 4.1.3版本开始支持。 + +.. index:: allowImageRemote + +.. _allowImageRemote: + +allowImageRemote +-------------------------------------------------------- +true时显示网络图片标签,false时不显示。 + +* 数据类型: Boolean +* 默认值: true + +.. note:: + + 4.1.6版本开始支持。 + +.. index:: autoHeightMode + +.. _autoHeightMode: + +autoHeightMode +-------------------------------------------------------- +值为true,并引入autoheight.js插件时自动调整高度。 + +* 数据类型: Boolean +* 默认值: false + +.. note:: + + 4.1.8版本开始支持。 + +.. index:: fixToolBar + +.. _fixToolBar: + +fixToolBar +-------------------------------------------------------- +值为true,并引入fixtoolbar.js插件时固定工具栏位置。 + +* 数据类型: Boolean +* 默认值: false + diff --git a/php/kindeditor_demo/kindeditor/docs/plugin.rst b/php/kindeditor_demo/kindeditor/docs/plugin.rst new file mode 100755 index 0000000..d67af07 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/plugin.rst @@ -0,0 +1,80 @@ +添加自定义插件 +======================================================== + +1. 添加"hello"插件 +-------------------------------------------------------- + +1) 添加plugins/hello/hello.js文件。 + +.. sourcecode:: js + + KindEditor.plugin('hello', function(K) { + var editor = this, name = 'hello'; + // 点击图标时执行 + editor.clickToolbar(name, function() { + editor.insertHtml('你好'); + }); + }); + +2) 定义语言,在页面的 + + + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/docs/qna.rst b/php/kindeditor_demo/kindeditor/docs/qna.rst new file mode 100755 index 0000000..033a2df --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/qna.rst @@ -0,0 +1,39 @@ +常见问题 +======================================================== + +.. contents:: + :depth: 2 + +编辑器好像是UTF-8编码的,可以在GB2312页面上使用吗? +-------------------------------------------------------- +可以使用。有两种方法,一种方法是引入kindeditor.js文件时将script的charset属性设置成utf-8。 + +还有一种方法是直接将html/js/css文件编码都转换成GB2312编码(用Notepad++、editPlus等文本编辑器就可以转换编码),不过转换格式后升级比较困难,建议使用第一种方法。 + +.. sourcecode:: html + + + +我取不到编辑器数据,直接取得textarea的value也没用。 +-------------------------------------------------------- +KindEditor的可视化操作在新创建的iframe上执行,代码模式下的textarea框也是新创建的,所以最后提交前需要执行 :ref:`KEditor.sync` 将HTML数据设置到原来的textarea。 + +KindEditor在默认情况下自动寻找textarea所属的form元素,找到form后onsubmit事件里添加editor.sync()函数,所以用form方式提交数据,不需要手动执行editor.sync()函数。 + +.. sourcecode:: js + + // 将编辑器的HTML数据同步到textarea + editor.sync(); + +为什么有些标签被过滤? +-------------------------------------------------------- +KindEditor默认采用白名单过滤方式,可用 :ref:`htmlTags` 参数定义要保留的标签和属性。当然也可以用 :ref:`filterMode` 参数关闭过滤模式,保留所有标签。 + +.. sourcecode:: js + + // 关闭过滤模式,保留所有标签 + KindEditor.options.filterMode = false; + + KindEditor.ready(function(K)) { + K.create('#editor_id'); + } diff --git a/php/kindeditor_demo/kindeditor/docs/range.rst b/php/kindeditor_demo/kindeditor/docs/range.rst new file mode 100755 index 0000000..1ac0500 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/range.rst @@ -0,0 +1,643 @@ +Range API +======================================================== + +.. contents:: + :depth: 2 + +.. index:: K.range + +.. _K.range: + +K.range(mixed) +-------------------------------------------------------- +创建或选取KRange对象,KRange是原生Range的封装,包含大部分W3C Range接口,此外还有包含KRange和原生Range之间的转换功能。 + +* 参数: + * document|range mixed: document或原生range +* 返回: KRange对象 + +示例: + +.. sourcecode:: js + + range = K.range(document); + range = K.range(originalRange); + +.. note:: + + DOM Level 2 Range Reference: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html + +.. index:: START_TO_START + +.. _START_TO_START: + +K.START_TO_START +-------------------------------------------------------- +调用 :ref:`KRange.compareBoundaryPoints` 时使用。 + +.. index:: START_TO_END + +.. _START_TO_END: + +K.START_TO_END +-------------------------------------------------------- +调用 :ref:`KRange.compareBoundaryPoints` 时使用。 + +.. index:: END_TO_END + +.. _END_TO_END: + +K.END_TO_END +-------------------------------------------------------- +调用 :ref:`KRange.compareBoundaryPoints` 时使用。 + +.. index:: END_TO_START + +.. _END_TO_START: + +K.END_TO_START +-------------------------------------------------------- +调用 :ref:`KRange.compareBoundaryPoints` 时使用。 + +.. index:: startContainer + +.. _KRange.startContainer: + +startContainer +-------------------------------------------------------- +range的开始节点。 + +.. index:: startOffset + +.. _KRange.startOffset: + +startOffset +-------------------------------------------------------- +range的开始节点位置。 + +.. index:: endContainer + +.. _KRange.endContainer: + +endContainer +-------------------------------------------------------- +range的结束节点。 + +.. index:: endOffset + +.. _KRange.endOffset: + +endOffset +-------------------------------------------------------- +range的结束节点的位置。 + +.. index:: collapsed + +.. _KRange.collapsed: + +collapsed +-------------------------------------------------------- +range的折叠状态,当range处于折叠状态时true,否则false。。 + +.. index:: commonAncestor + +.. _KRange.commonAncestor: + +commonAncestor() +-------------------------------------------------------- +取得KRange的共同祖先。 + +* 参数: 无 +* 返回: Element + +示例: + +.. sourcecode:: js + + var range = K.range(document); + var element = range.commonAncestor(); + +.. index:: setStart + +.. _KRange.setStart: + +setStart(node , offset) +-------------------------------------------------------- +设置KRange的开始节点和位置。 + +* 参数: + * Node node: 任意节点 + * Int offset: 位置 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.setStart(document.body, 1); + +.. index:: setEnd + +.. _KRange.setEnd: + +setEnd(node , offset) +-------------------------------------------------------- +设置KRange的结束节点和位置。 + +* 参数: + * Node node: 任意节点 + * Int offset: 位置 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.setEnd(document.body, 2); + +.. index:: setStartBefore + +.. _KRange.setStartBefore: + +setStartBefore(node) +-------------------------------------------------------- +将Node的开始位置设置成Range的开始位置。 + +* 参数: + * Node node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.setStartBefore(K('div#id')[0]); + +.. index:: setStartAfter + +.. _KRange.setStartAfter: + +setStartAfter(node) +-------------------------------------------------------- +将Node的结束位置设置成Range的开始位置。 + +* 参数: + * Node node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.setStartAfter(K('div#id')[0]); + +.. index:: setEndBefore + +.. _KRange.setEndBefore: + +setEndBefore(node) +-------------------------------------------------------- +将Node的开始位置设置成Range的结束位置。 + +* 参数: + * Node node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.setEndBefore(K('div#id')[0]); + +.. index:: setEndAfter + +.. _KRange.setEndAfter: + +setEndAfter(node) +-------------------------------------------------------- +将Node的结束位置设置成Range的结束位置。 + +* 参数: + * Node node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.setEndAfter(K('div#id')[0]); + +.. index:: selectNode + +.. _KRange.selectNode: + +selectNode(node) +-------------------------------------------------------- +将Node的开始位置和结束位置分别设置成Range的开始位置和结束位置。 + +* 参数: + * Node node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNode(K('div#id')[0]); + +.. index:: selectNodeContents + +.. _KRange.selectNodeContents: + +selectNodeContents(node) +-------------------------------------------------------- +将Node的子节点的开始位置和结束位置分别设置成Range的开始位置和结束位置。对于文本节点和无结束符的元素,相当于使用selectNode。 + +* 参数: + * Node node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + +.. index:: collapse + +.. _KRange.collapse: + +collapse(toStart) +-------------------------------------------------------- +折叠KRange,当toStart为true时向前折叠,false时向后折叠。 + +* 参数: + * Boolean toStart: 折叠方向 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + range.collapse(true); + +.. index:: compareBoundaryPoints + +.. _KRange.compareBoundaryPoints: + +compareBoundaryPoints(how , range) +-------------------------------------------------------- +根据how参数比较2个range的边界。 + +* 参数: + * Int how: 位置信息,可设置K.START_TO_START、K.START_TO_END、K.END_TO_END、K.END_TO_START。 + * Range range: 目标Range +* 返回: 当this range在目标range的左侧时返回-1,在目标range的右侧时返回1,相同时返回0。 + +how参数的方向规则: + +* K.START_TO_START:比较目标range的开始位置和this range的开始位置。 +* K.START_TO_END:比较目标range的开始位置和this range的结束位置。 +* K.END_TO_END:比较目标range的结束位置和this range的结束位置。 +* K.END_TO_START:比较目标range的结束位置和this range的开始位置。 + +示例: + +.. sourcecode:: js + + var range1 = K.range(document); + range1.selectNode(K('div#id')[0]); + var range2 = K.range(document); + range2.selectNode(K('div#id p')[0]); + var cmp = range1.compareBoundaryPoints(K.START_TO_START, range2); + +.. index:: cloneRange + +.. _KRange.cloneRange: + +cloneRange() +-------------------------------------------------------- +复制KRange。 + +* 参数: 无 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + var newRange = range.cloneRange(); + +.. index:: toString + +.. _KRange.toString: + +toString() +-------------------------------------------------------- +返回KRange的文本内容。 + +* 参数: 无 +* 返回: String + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + var text = range.toString(); + +.. index:: cloneContents + +.. _KRange.cloneContents: + +cloneContents() +-------------------------------------------------------- +复制并返回KRange的内容。 + +* 参数: 无 +* 返回: documentFragment + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + var fragment = range.cloneContents(); + +.. index:: deleteContents + +.. _KRange.deleteContents: + +deleteContents() +-------------------------------------------------------- +删除KRange的内容。 + +* 参数: 无 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + range.deleteContents(); + +.. index:: extractContents + +.. _KRange.extractContents: + +extractContents() +-------------------------------------------------------- +删除并返回KRange的内容。 + +* 参数: 无 +* 返回: documentFragment + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('div#id')[0]); + var fragment = range.extractContents(); + +.. index:: insertNode + +.. _KRange.insertNode: + +insertNode(node) +-------------------------------------------------------- +将指定Node插入到KRange的开始位置。 + +* 参数: + * Node node: 任意Node或documentFragment +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('#id1')[0]); + range.insertNode(K('#id2')[0]); + +.. index:: surroundContents + +.. _KRange.surroundContents: + +surroundContents(node) +-------------------------------------------------------- +用指定Node围住KRange的内容。 + +* 参数: + * Element node: 任意节点 +* 返回: KRange + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('#id1')[0]); + range.surroundContents(K('#id2')[0]); + +.. index:: isControl + +.. _KRange.isControl: + +isControl() +-------------------------------------------------------- +判断当前KRange是否可选择的Contral Range。 + +* 参数: 无 +* 返回: Boolean + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('#id1')[0]); + var bool = range.isControl(); + +.. index:: get + +.. _KRange.get: + +get([hasControlRange]) +-------------------------------------------------------- +将KRange转换成原生Range并返回。 + +* 参数: + * Boolean hasControlRange: 是否包含Contral Range +* 返回: Range + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('#id1')[0]); + var originalRange = range.get(); + +.. index:: html + +.. _KRange.html: + +html() +-------------------------------------------------------- +返回KRange内容的HTML。 + +* 参数: 无 +* 返回: HTML string + +示例: + +.. sourcecode:: js + + var range = K.range(document); + range.selectNodeContents(K('#id1')[0]); + var html = range.html(); + +.. index:: down + +.. _KRange.down: + +down() +-------------------------------------------------------- +降低range的位置。 + +* 参数: 无 +* 返回: KRange + +示例: + +.. sourcecode:: js + + //

123abcdef

+ range.setStart(strong, 1); + range.down(); + console.log(range.startContainer, range.startOffset); // print "abc", 0 + +.. index:: up + +.. _KRange.up: + +up() +-------------------------------------------------------- +提高range的位置。 + +* 参数: 无 +* 返回: KRange + +示例: + +.. sourcecode:: js + + //

123abcdef

+ range.setStart("abc", 0); + range.up(); + console.log(range.startContainer, range.startOffset); // print strong, 1 + +.. index:: enlarge + +.. _KRange.enlarge: + +enlarge() +-------------------------------------------------------- +扩大边界。 + +* 参数: 无 +* 返回: KRange + +示例: + +.. sourcecode:: js + + //

123abcdef

+ range.setStart("123", 0); + range.setEnd("abc", 3); + range.enlarge(); + console.log(range.startContainer, range.startOffset); // print p, 0 + console.log(range.endContainer, range.endOffset); // print p, 1 + +.. index:: shrink + +.. _KRange.shrink: + +shrink() +-------------------------------------------------------- +缩小边界。 + +* 参数: 无 +* 返回: KRange + +示例: + +.. sourcecode:: js + + //

123abc

+ range.setStart(p, 0); + range.setEnd(p, 1); + range.shrink(); + console.log(range.startContainer, range.startOffset); // print "123", 0 + console.log(range.endContainer, range.endOffset); // print "abc", 3 + +.. index:: createBookmark + +.. _KRange.createBookmark: + +createBookmark([serialize]) +-------------------------------------------------------- +创建bookmark。(插入临时节点标记位置) + +* 参数: + * Boolean serialize: bookmark类型,默认值为false,true时bookmark包含临时节点的ID,false时bookmark包含临时节点的Element。 +* 返回: bookmark + +示例: + +.. sourcecode:: js + + bookmark = range.createBookmark(); + console.log(bookmark); // print {start: startNode, end: endNode} + + bookmark = range.createBookmark(true); + console.log(bookmark); // print {start: 'start_node_id', end: 'end_node_id'} + +.. index:: moveToBookmark + +.. _KRange.moveToBookmark: + +moveToBookmark(bookmark) +-------------------------------------------------------- +根据bookmark重新设置range。 + +* 参数: + * Object bookmark: 通过 :ref:`KRange.createBookmark` 得到的bookmark +* 返回: KRange + +示例: + +.. sourcecode:: js + + bookmark = range.createBookmark(); + // 在这里执行一些改变DOM的处理 + // ... + range.moveToBookmark(bookmark); + diff --git a/php/kindeditor_demo/kindeditor/docs/selector.rst b/php/kindeditor_demo/kindeditor/docs/selector.rst new file mode 100755 index 0000000..1d6bbb2 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/selector.rst @@ -0,0 +1,59 @@ +选择器(Selector) API +======================================================== + +.. contents:: + :depth: 2 + +.. index:: query + +.. _query: + +K.query(expr [, root]) +-------------------------------------------------------- +根据expr在root范围内查找DOM元素,并返回第一个元素。没找到则返回null。 + +* 参数: + * string expr: 选择器表达式 + * element root: 根元素,默认值为document +* 返回: DOM元素 + +.. sourcecode:: js + + var div = K.query('#id div'); + var span = K.query('span.class', div); + +.. note:: + + 目前仅支持以下表达式: + + * \*: any element + * E: an element of type E + * E[foo]: an E element with a "foo" attribute + * E[foo="bar"]: an E element whose "foo" attribute value is exactly equal to "bar" + * E.warning: an E element whose class is "warning" (the document language specifies how class is determined) + * E#myid: an E element with ID equal to "myid" + * E F: an F element descendant of an E element + * E > F: an F element child of an E element + +参考文档: http://www.w3.org/TR/css3-selectors/ + +.. index:: queryAll + +.. _queryAll: + +K.queryAll(expr [, root]) +-------------------------------------------------------- +根据expr在root范围内查找DOM元素,并返回所有元素,如果没找到则返回空数组。 + +* 参数: + * string expr: 选择器表达式 + * element root: 根元素,默认值为document +* 返回: array + +示例: + +.. sourcecode:: js + + var divArray = K.queryAll('#id div'); + var spanArray = K.queryAll('span.class', div); + diff --git a/php/kindeditor_demo/kindeditor/docs/tabs.rst b/php/kindeditor_demo/kindeditor/docs/tabs.rst new file mode 100755 index 0000000..64f9609 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/tabs.rst @@ -0,0 +1,42 @@ +Tabs API +======================================================== + +.. contents:: + :depth: 2 + +.. index:: tabs + +.. _K.tabs: + +K.tabs(options) +-------------------------------------------------------- +创建Tabs。 + +* 参数: + * object options: 配置信息 +* 返回: KTabs +* 继承: KWidget ( :ref:`K.widget` ) + +示例: + +.. sourcecode:: js + + var tabs = K.tabs({ + parent : '#tabs', + afterSelect : function(i) { + K('#tab' + (i + 1)).html('选中了标签#' + (i + 1)); + } + }); + tabs.add({ + title : '标签#1', + panel : '#tab1' + }); + tabs.add({ + title : '标签#2', + panel : '#tab2' + }); + tabs.add({ + title : '标签#3', + panel : '#tab3' + }); + tabs.select(0); diff --git a/php/kindeditor_demo/kindeditor/docs/theme.rst b/php/kindeditor_demo/kindeditor/docs/theme.rst new file mode 100755 index 0000000..e0a16d1 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/theme.rst @@ -0,0 +1,40 @@ +更改编辑器外观 +======================================================== + +1. 添加"example1"风格 +-------------------------------------------------------- + +1) 添加themes/example1/example1.css,在这个文件里定义覆盖default.css里的CSS。 + +.. sourcecode:: css + + .ke-container-example1 { + display: block; + border: 1px solid #CCC; + background-color: #FFF; + overflow: hidden; + } + .ke-container-example1 .ke-toolbar { + border-bottom: 1px solid #CCC; + background-color: #FFF; + padding: 2px 5px; + overflow: hidden; + } + /* 在这里继续定义其它CSS */ + +2) 调用编辑器时,引入example1.css,并指定themeType。 + +.. sourcecode:: html + + + + + + diff --git a/php/kindeditor_demo/kindeditor/docs/upgrade.rst b/php/kindeditor_demo/kindeditor/docs/upgrade.rst new file mode 100755 index 0000000..9cd14b5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/upgrade.rst @@ -0,0 +1,68 @@ +3.x升级到4.x版本 +======================================================== + +1. 替换文件 +----------------------------------------------------------------- +移除3.x版本文件。 + +.. sourcecode:: html + + + +添加4.x版本文件。 + +.. sourcecode:: html + + + + +2. 替换javascript代码 +----------------------------------------------------------------- + +移除3.x版本代码。 + +.. sourcecode:: html + + + +添加4.x版本代码。 + +.. sourcecode:: html + + + +.. note :: + + * 4.x修改过一些参数名,所以3.x的初始化参数不一定直接兼容4.x,具体参数请参考 :doc:`option` 。 + * 4.x通过K.create返回的editor对象调用编辑器API,具体方法请参考 :doc:`editor` 。 + * 4.x插件采用js动态加载机制,uploadJson和fileManagerJson是相对于当前页面的路径,使用相对路径时需要注意。 + * 如果需要在其它函数内调用editor对象,可以将editor对象设置成全局变量。 + +.. sourcecode:: html + + + + + diff --git a/php/kindeditor_demo/kindeditor/docs/upload.rst b/php/kindeditor_demo/kindeditor/docs/upload.rst new file mode 100755 index 0000000..304bfa9 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/upload.rst @@ -0,0 +1,59 @@ +上传文件 +======================================================== +KindEditor默认提供ASP、ASP.NET、PHP、JSP上传程序,这些程序是演示程序,建议不要直接在实际项目中使用。 +如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。 + +选择程序语言 +----------------------------------------------------------------- + +.. sourcecode:: js + + // ASP + KindEditor.ready(function(K) { + K.create('#textarea_id', { + uploadJson : '../asp/upload_json.asp', + fileManagerJson : '../asp/file_manager_json.asp', + allowFileManager : true + }); + }); + // ASP.NET + KindEditor.ready(function(K) { + K.create('#textarea_id', { + uploadJson : '../asp.net/upload_json.ashx', + fileManagerJson : '../asp.net/file_manager_json.ashx', + allowFileManager : true + }); + }); + // JSP + KindEditor.ready(function(K) { + K.create('#textarea_id', { + uploadJson : '../jsp/upload_json.jsp', + fileManagerJson : '../jsp/file_manager_json.jsp', + allowFileManager : true + }); + }); + +.. note:: + + 具体使用方法请参见各语言(asp、asp.net、php、jsp)目录下的demo.xxx文件。 + +POST参数 +----------------------------------------------------------------- +* imgFile: 文件form名称 +* dir: 上传类型,分别为image、flash、media、file + +返回格式(JSON) +----------------------------------------------------------------- + +.. sourcecode:: js + + //成功时 + { + "error" : 0, + "url" : "http://www.example.com/path/to/file.ext" + } + //失败时 + { + "error" : 1, + "message" : "错误信息" + } \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/docs/uploadbutton.rst b/php/kindeditor_demo/kindeditor/docs/uploadbutton.rst new file mode 100755 index 0000000..96af5ee --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/uploadbutton.rst @@ -0,0 +1,37 @@ +上传按钮(UplaodButton) API +======================================================== + +.. contents:: + :depth: 2 + +.. index:: uploadbutton + +.. _K.uploadbutton: + +K.uploadbutton(options) +-------------------------------------------------------- +创建上传按钮。 + +* 参数: + * object options: 配置信息 +* 返回: KUploadButton + +示例: + +.. sourcecode:: js + + var uploadbutton = K.uploadbutton({ + button : K('#ke-upload-button')[0], + fieldName : 'imgFile', + url : '../php/upload_json.php', + afterUpload : function(data) { + if (data.error === 0) { + alert(data.url); + } else { + alert(data.message); + } + } + }); + uploadbutton.fileBox.change(function(e) { + uploadbutton.submit(); + }); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/docs/usage.rst b/php/kindeditor_demo/kindeditor/docs/usage.rst new file mode 100755 index 0000000..81fb2bd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/usage.rst @@ -0,0 +1,97 @@ +编辑器使用方法 +======================================================== + +1. 下载编辑器 +----------------------------------------------------------------- +下载 KindEditor 最新版本,下载之后打开 examples/index.html 就可以看到演示。 + +下载页面: http://www.kindsoft.net/down.php + +2. 部署编辑器 +----------------------------------------------------------------- + +解压 kindeditor-x.x.x.zip 文件,将所有文件上传到您的网站程序目录里,例如:http://您的域名/editor/ + +.. note:: + + 您可以根据需求删除以下目录后上传到服务器。 + + * asp - ASP程序 + * asp.net - ASP.NET程序 + * php - PHP程序 + * jsp - JSP程序 + * examples - 演示文件 + +3. 修改HTML页面 +----------------------------------------------------------------- + +1) 在需要显示编辑器的位置添加textarea输入框。 + +.. sourcecode:: html + + + +.. note:: + + * id在当前页面必须是唯一的值。 + * 在textarea里设置HTML内容即可实现编辑,在这里需要注意的是,如果从服务器端程序(ASP、PHP、ASP.NET等)直接显示内容,则必须转换HTML特殊字符(>,<,&,")。具体请参考各语言目录下面的demo.xxx程序,目前支持ASP、ASP.NET、PHP、JSP。 + * 在有些浏览器上不设宽度和高度可能显示有问题,所以最好设一下宽度和高度。宽度和高度可用inline样式设置,也可用 :doc:`option` 设置。 + +2) 在该HTML页面添加以下脚本。 + +.. sourcecode:: html + + + + + +.. note :: + + * 第一个参数可用其它CSS选择器,匹配多个textarea时只在第一个元素上加载编辑器。 + * 通过K.create函数的第二个参数,可以对编辑器进行配置,具体参数请参考 :doc:`option` 。 + +.. sourcecode:: js + + var options = { + cssPath : '/css/index.css', + filterMode : true + }; + var editor = K.create('textarea[name="content"]', options); + +4. 获取HTML数据 +----------------------------------------------------------------- + +.. sourcecode:: js + + // 取得HTML内容 + html = editor.html(); + + // 同步数据后可以直接取得textarea的value + editor.sync(); + html = document.getElementById('editor_id').value; // 原生API + html = K('#editor_id').val(); // KindEditor Node API + html = $('#editor_id').val(); // jQuery + + // 设置HTML内容 + editor.html('HTML内容'); + +.. note :: + + * KindEditor的可视化操作在新创建的iframe上执行,代码模式下的textarea框也是新创建的,所以最后提交前需要执行 :ref:`KEditor.sync` 将HTML数据设置到原来的textarea。 + * KindEditor在默认情况下自动寻找textarea所属的form元素,找到form后onsubmit事件里添加sync函数,所以用form方式提交数据,不需要手动执行sync()函数。 + * KindEditor默认采用白名单过滤方式,可用 :ref:`htmlTags` 参数定义要保留的标签和属性。当然也可以用 :ref:`filterMode` 参数关闭过滤模式,保留所有标签。 + +.. sourcecode:: js + + // 关闭过滤模式,保留所有标签 + KindEditor.options.filterMode = false; + + KindEditor.ready(function(K)) { + K.create('#editor_id'); + } diff --git a/php/kindeditor_demo/kindeditor/docs/widget.rst b/php/kindeditor_demo/kindeditor/docs/widget.rst new file mode 100755 index 0000000..0d88f0f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/docs/widget.rst @@ -0,0 +1,33 @@ +Widget API +======================================================== + +.. contents:: + :depth: 2 + +.. index:: widget + +.. _K.widget: + +K.widget(options) +-------------------------------------------------------- +创建widget。 + +* 参数: + * object options: 配置信息 +* 返回: KWidget + +示例: + +.. sourcecode:: js + + var widget = K.widget({ + z : 100, + width : 200, + height : 100, + html : 'abc123abcabc', + css : { + border : '1px solid #A0A0A0', + background : '#F0F0F0' + } + }); + diff --git a/php/kindeditor_demo/kindeditor/kindeditor-all-min.js b/php/kindeditor_demo/kindeditor/kindeditor-all-min.js new file mode 100755 index 0000000..9d4aacb --- /dev/null +++ b/php/kindeditor_demo/kindeditor/kindeditor-all-min.js @@ -0,0 +1,7 @@ +/* KindEditor 4.1.11 (2016-03-31), Copyright (C) kindsoft.net, Licence: http://kindeditor.net/license.php */ +!function(window,undefined){function _isArray(a){return a?"[object Array]"===Object.prototype.toString.call(a):!1}function _isFunction(a){return a?"[object Function]"===Object.prototype.toString.call(a):!1}function _inArray(a,b){for(var c=0,d=b.length;d>c;c++)if(a===b[c])return c;return-1}function _each(a,b){if(_isArray(a))for(var c=0,d=a.length;d>c&&b.call(a[c],c,a[c])!==!1;c++);else for(var e in a)if(a.hasOwnProperty(e)&&b.call(a[e],e,a[e])===!1)break}function _trim(a){return a.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g,"")}function _inString(a,b,c){return c=c===undefined?",":c,(c+b+c).indexOf(c+a+c)>=0}function _addUnit(a,b){return b=b||"px",a&&/^-?\d+(?:\.\d+)?$/.test(a)?a+b:a}function _removeUnit(a){var b;return a&&(b=/(\d+)/.exec(a))?parseInt(b[1],10):0}function _escape(a){return a.replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function _unescape(a){return a.replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/&/g,"&")}function _toCamel(a){var b=a.split("-");return a="",_each(b,function(b,c){a+=b>0?c.charAt(0).toUpperCase()+c.substr(1):c}),a}function _toHex(a){function b(a){var b=parseInt(a,10).toString(16).toUpperCase();return b.length>1?b:"0"+b}return a.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/gi,function(a,c,d,e){return"#"+b(c)+b(d)+b(e)})}function _toMap(a,b){b=b===undefined?",":b;var c,d={},e=_isArray(a)?a:a.split(b);return _each(e,function(a,b){if(c=/^(\d+)\.\.(\d+)$/.exec(b))for(var e=parseInt(c[1],10);e<=parseInt(c[2],10);e++)d[e.toString()]=!0;else d[b]=!0}),d}function _toArray(a,b){return Array.prototype.slice.call(a,b||0)}function _undef(a,b){return a===undefined?b:a}function _invalidUrl(a){return!a||/[<>"]/.test(a)}function _addParam(a,b){return a.indexOf("?")>=0?a+"&"+b:a+"?"+b}function _extend(a,b,c){c||(c=b,b=null);var d;if(b){var e=function(){};e.prototype=b.prototype,d=new e,_each(c,function(a,b){d[a]=b})}else d=c;d.constructor=a,a.prototype=d,a.parent=b?b.prototype:null}function _json(text){var match;(match=/\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))&&(text=match[0]);var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;if(cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return eval("("+text+")");throw"JSON parse error"}function _getBasePath(){for(var a,b=document.getElementsByTagName("script"),c=0,d=b.length;d>c;c++)if(a=b[c].src||"",/kindeditor[\w\-\.]*\.js/.test(a))return a.substring(0,a.lastIndexOf("/")+1);return""}function _bindEvent(a,b,c){a.addEventListener?a.addEventListener(b,c,_useCapture):a.attachEvent&&a.attachEvent("on"+b,c)}function _unbindEvent(a,b,c){a.removeEventListener?a.removeEventListener(b,c,_useCapture):a.detachEvent&&a.detachEvent("on"+b,c)}function KEvent(a,b){this.init(a,b)}function _getId(a){return a[_eventExpendo]||null}function _setId(a){return a[_eventExpendo]=++_eventId,_eventId}function _removeId(a){try{delete a[_eventExpendo]}catch(b){a.removeAttribute&&a.removeAttribute(_eventExpendo)}}function _bind(a,b,c){if(b.indexOf(",")>=0)return void _each(b.split(","),function(){_bind(a,this,c)});var d=_getId(a);d||(d=_setId(a)),_eventData[d]===undefined&&(_eventData[d]={});var e=_eventData[d][b];e&&e.length>0?_unbindEvent(a,b,e[0]):(_eventData[d][b]=[],_eventData[d].el=a),e=_eventData[d][b],0===e.length&&(e[0]=function(b){var c=b?new KEvent(a,b):undefined;_each(e,function(b,d){b>0&&d&&d.call(a,c)})}),_inArray(c,e)<0&&e.push(c),_bindEvent(a,b,e[0])}function _unbind(a,b,c){if(b&&b.indexOf(",")>=0)return void _each(b.split(","),function(){_unbind(a,this,c)});var d=_getId(a);if(d){if(b===undefined)return void(d in _eventData&&(_each(_eventData[d],function(b,c){"el"!=b&&c.length>0&&_unbindEvent(a,b,c[0])}),delete _eventData[d],_removeId(a)));if(_eventData[d]){var e=_eventData[d][b];if(e&&e.length>0){c===undefined?(_unbindEvent(a,b,e[0]),delete _eventData[d][b]):(_each(e,function(a,b){a>0&&b===c&&e.splice(a,1)}),1==e.length&&(_unbindEvent(a,b,e[0]),delete _eventData[d][b]));var f=0;_each(_eventData[d],function(){f++}),2>f&&(delete _eventData[d],_removeId(a))}}}}function _fire(a,b){if(b.indexOf(",")>=0)return void _each(b.split(","),function(){_fire(a,this)});var c=_getId(a);if(c){var d=_eventData[c][b];_eventData[c]&&d&&d.length>0&&d[0]()}}function _ctrl(a,b,c){b=/^\d{2,}$/.test(b)?b:b.toUpperCase().charCodeAt(0),_bind(a,"keydown",function(d){!d.ctrlKey||d.which!=b||d.shiftKey||d.altKey||(c.call(a),d.stop())})}function _ready(a){function b(){e||(e=!0,a(KindEditor),_readyFinished=!0)}function c(){if(!e){try{document.documentElement.doScroll("left")}catch(a){return void setTimeout(c,100)}b()}}function d(){"complete"===document.readyState&&b()}if(_readyFinished)return void a(KindEditor);var e=!1;if(document.addEventListener)_bind(document,"DOMContentLoaded",b);else if(document.attachEvent){_bind(document,"readystatechange",d);var f=!1;try{f=null==window.frameElement}catch(g){}document.documentElement.doScroll&&f&&c()}_bind(window,"load",b)}function _getCssList(a){for(var b,c={},d=/\s*([\w\-]+)\s*:([^;]*)(;|$)/g;b=d.exec(a);){var e=_trim(b[1].toLowerCase()),f=_trim(_toHex(b[2]));c[e]=f}return c}function _getAttrList(a){for(var b,c={},d=/\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g;b=d.exec(a);){var e=(b[1]||b[2]||b[4]||b[6]).toLowerCase(),f=(b[2]?b[3]:b[4]?b[5]:b[7])||"";c[e]=f}return c}function _addClassToTag(a,b){return a=/\s+class\s*=/.test(a)?a.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/,function(a,c,d,e){return(" "+d+" ").indexOf(" "+b+" ")<0?""===d?c+b+e:c+d+" "+b+e:a}):a.substr(0,a.length-1)+' class="'+b+'">'}function _formatCss(a){var b="";return _each(_getCssList(a),function(a,c){b+=a+":"+c+";"}),b}function _formatUrl(a,b,c,d){function e(a){for(var b=a.split("/"),c=[],d=0,e=b.length;e>d;d++){var f=b[d];".."==f?c.length>0&&c.pop():""!==f&&"."!=f&&c.push(f)}return"/"+c.join("/")}function f(b,c){if(a.substr(0,b.length)===b){for(var e=[],g=0;c>g;g++)e.push("..");var i=".";return e.length>0&&(i+="/"+e.join("/")),"/"==d&&(i+="/"),i+a.substr(b.length)}return(h=/^(.*)\//.exec(b))?f(h[1],++c):void 0}if(b=_undef(b,"").toLowerCase(),"data:"!=a.substr(0,5)&&(a=a.replace(/([^:])\/\//g,"$1/")),_inArray(b,["absolute","relative","domain"])<0)return a;if(c=c||location.protocol+"//"+location.host,d===undefined){var g=location.pathname.match(/^(\/.*)\//);d=g?g[1]:""}var h;if(h=/^(\w+:\/\/[^\/]*)/.exec(a)){if(h[1]!==c)return a}else if(/^\w+:/.test(a))return a;return/^\//.test(a)?a=c+e(a.substr(1)):/^\w+:\/\//.test(a)||(a=c+e(d+"/"+a)),"relative"===b?a=f(c+d,0).substr(2):"absolute"===b&&a.substr(0,c.length)===c&&(a=a.substr(c.length)),a}function _formatHtml(a,b,c,d,e){null==a&&(a=""),c=c||"",d=_undef(d,!1),e=_undef(e," ");var f="xx-small,x-small,small,medium,large,x-large,xx-large".split(",");a=a.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/gi,function(a,b,c,d){return b+c.replace(/<(?:br|br\s[^>]*)>/gi,"\n")+d}),a=a.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/gi,"

"),a=a.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/gi,"$1
$2"),a=a.replace(/\u200B/g,""),a=a.replace(/\u00A9/g,"©"),a=a.replace(/\u00AE/g,"®"),a=a.replace(/\u2003/g," "),a=a.replace(/\u3000/g," "),a=a.replace(/<[^>]+/g,function(a){return a.replace(/\s+/g," ")});var g={};b&&(_each(b,function(a,b){for(var c=a.split(","),d=0,e=c.length;e>d;d++)g[c[d]]=_toMap(b)}),g.script||(a=a.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/gi,"")),g.style||(a=a.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/gi,"")));var h=/(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g,i=[];return a=a.replace(h,function(a,h,j,k,l,m,n){var o=a,p=h||"",q=j||"",r=k.toLowerCase(),s=l||"",t=m?" "+m:"",u=n||"";if(b&&!g[r])return"";if(""===t&&_SINGLE_TAG_MAP[r]&&(t=" /"),_INLINE_TAG_MAP[r]&&(p&&(p=" "),u&&(u=" ")),_PRE_TAG_MAP[r]&&(q?u="\n":p="\n"),d&&"br"==r&&(u="\n"),_BLOCK_TAG_MAP[r]&&!_PRE_TAG_MAP[r])if(d){q&&i.length>0&&i[i.length-1]===r?i.pop():i.push(r),p="\n",u="\n";for(var v=0,w=q?i.length:i.length-1;w>v;v++)p+=e,q||(u+=e);t?i.pop():q||(u+=e)}else p=u="";if(""!==s){var x=_getAttrList(o);if("font"===r){var y={},z="";_each(x,function(a,b){"color"===a&&(y.color=b,delete x[a]),"size"===a&&(y["font-size"]=f[parseInt(b,10)-1]||"",delete x[a]),"face"===a&&(y["font-family"]=b,delete x[a]),"style"===a&&(z=b)}),z&&!/;$/.test(z)&&(z+=";"),_each(y,function(a,b){""!==b&&(/\s/.test(b)&&(b="'"+b+"'"),z+=a+":"+b+";")}),x.style=z}_each(x,function(a,d){if(_FILL_ATTR_MAP[a]&&(x[a]=a),_inArray(a,["src","href"])>=0&&(x[a]=_formatUrl(d,c)),(b&&"style"!==a&&!g[r]["*"]&&!g[r][a]||"body"===r&&"contenteditable"===a||/^kindeditor_\d+$/.test(a))&&delete x[a],"style"===a&&""!==d){var e=_getCssList(d);_each(e,function(a){!b||g[r].style||g[r]["."+a]||delete e[a]});var f="";_each(e,function(a,b){f+=a+":"+b+";"}),x.style=f}}),s="",_each(x,function(a,b){("style"!==a||""!==b)&&(b=b.replace(/"/g,"""),s+=" "+a+'="'+b+'"')})}return"font"===r&&(r="span"),p+"<"+q+r+s+t+">"+u}),a=a.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/gi,function(a,b,c,d){return b+c.replace(/\n/g,'\n')+d}),a=a.replace(/\n\s*\n/g,"\n"),a=a.replace(/\n/g,"\n"),_trim(a)}function _clearMsWord(a,b){return a=a.replace(//gi,"").replace(//gi,"").replace(/]*>[\s\S]*?<\/style>/gi,"").replace(/]*>[\s\S]*?<\/script>/gi,"").replace(/]+>[\s\S]*?<\/w:[^>]+>/gi,"").replace(/]+>[\s\S]*?<\/o:[^>]+>/gi,"").replace(/[\s\S]*?<\/xml>/gi,"").replace(/<(?:table|td)[^>]*>/gi,function(a){return a.replace(/border-bottom:([#\w\s]+)/gi,"border:$1")}),_formatHtml(a,b)}function _mediaType(a){return/\.(rm|rmvb)(\?|$)/i.test(a)?"audio/x-pn-realaudio-plugin":/\.(swf|flv)(\?|$)/i.test(a)?"application/x-shockwave-flash":"video/x-ms-asf-plugin"}function _mediaClass(a){return/realaudio/i.test(a)?"ke-rm":/flash/i.test(a)?"ke-flash":"ke-media"}function _mediaAttrs(a){return _getAttrList(unescape(a))}function _mediaEmbed(a){var b="0&&(g+="width:"+c+"px;"),/\D/.test(d)?g+="height:"+d+";":d>0&&(g+="height:"+d+"px;");var h=''}function _tmpl(a,b){var c=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return b?c(b):c}function _contains(a,b){if(9==a.nodeType&&9!=b.nodeType)return!0;for(;b=b.parentNode;)if(b==a)return!0;return!1}function _getAttr(a,b){b=b.toLowerCase();var c=null;if(_GET_SET_ATTRIBUTE||"script"==a.nodeName.toLowerCase())try{c=a.getAttribute(b,2)}catch(d){c=a.getAttribute(b,1)}else{var e=a.ownerDocument.createElement("div");e.appendChild(a.cloneNode(!1));var f=_getAttrList(_unescape(e.innerHTML));b in f&&(c=f[b])}return"style"===b&&null!==c&&(c=_formatCss(c)),c}function _queryAll(a,b){function c(a){return"string"!=typeof a?a:a.replace(/([^\w\-])/g,"\\$1")}function d(a){return a.replace(/\\/g,"")}function e(a,b){return"*"===a||a.toLowerCase()===c(b.toLowerCase())}function f(a,b,c){var f=[],g=c.ownerDocument||c,h=g.getElementById(d(a));return h&&e(b,h.nodeName)&&_contains(c,h)&&f.push(h),f}function g(a,b,c){var f,g,h,i,j=c.ownerDocument||c,k=[];if(c.getElementsByClassName)for(f=c.getElementsByClassName(d(a)),g=0,h=f.length;h>g;g++)i=f[g],e(b,i.nodeName)&&k.push(i);else if(j.querySelectorAll)for(f=j.querySelectorAll(("#document"!==c.nodeName?c.nodeName+" ":"")+b+"."+a),g=0,h=f.length;h>g;g++)i=f[g],_contains(c,i)&&k.push(i);else for(f=c.getElementsByTagName(b),a=" "+a+" ",g=0,h=f.length;h>g;g++)if(i=f[g],1==i.nodeType){var l=i.className;l&&(" "+l+" ").indexOf(a)>-1&&k.push(i)}return k}function h(a,b,c){for(var f,g=[],h=c.ownerDocument||c,i=h.getElementsByName(d(a)),j=0,k=i.length;k>j;j++)f=i[j],e(b,f.nodeName)&&_contains(c,f)&&null!==f.getAttribute("name")&&g.push(f);return g}function i(a,b,d,e){for(var f,g=[],h=e.getElementsByTagName(d),i=0,j=h.length;j>i;i++)f=h[i],1==f.nodeType&&(null===b?null!==_getAttr(f,a)&&g.push(f):b===c(_getAttr(f,a))&&g.push(f));return g}function j(a,b){var c,d=[];c=/^((?:\\.|[^.#\s\[<>])+)/.exec(a);var e=c?c[1]:"*";if(c=/#((?:[\w\-]|\\.)+)$/.exec(a))d=f(c[1],e,b);else if(c=/\.((?:[\w\-]|\\.)+)$/.exec(a))d=g(c[1],e,b);else if(c=/\[((?:[\w\-]|\\.)+)\]/.exec(a))d=i(c[1].toLowerCase(),null,e,b);else if(c=/\[((?:[\w\-]|\\.)+)\s*=\s*['"]?((?:\\.|[^'"]+)+)['"]?\]/.exec(a)){var j=c[1].toLowerCase(),k=c[2];d="id"===j?f(k,e,b):"class"===j?g(k,e,b):"name"===j?h(k,e,b):i(j,k,e,b)}else for(var l,m=b.getElementsByTagName(e),n=0,o=m.length;o>n;n++)l=m[n],1==l.nodeType&&d.push(l);return d}var k=a.split(",");if(k.length>1){var l=[];return _each(k,function(){_each(_queryAll(this,b),function(){_inArray(this,l)<0&&l.push(this)})}),l}b=b||document;for(var m,n=[],o=/((?:\\.|[^\s>])+|[\s>])/g;m=o.exec(a);)" "!==m[1]&&n.push(m[1]);var p=[];if(1==n.length)return j(n[0],b);var q,r,s,t,u,v,w,x,y,z,A=!1;for(v=0,lenth=n.length;v"!==q){if(v>0){for(r=[],w=0,y=p.length;y>w;w++)for(t=p[w],s=j(q,t),x=0,z=s.length;z>x;x++)u=s[x],A?t===u.parentNode&&r.push(u):r.push(u);p=r}else p=j(q,b);if(0===p.length)return[]}else A=!0;return p}function _query(a,b){var c=_queryAll(a,b);return c.length>0?c[0]:null}function _get(a){return K(a)[0]}function _getDoc(a){return a?a.ownerDocument||a.document||a:document}function _getWin(a){if(!a)return window;var b=_getDoc(a);return b.parentWindow||b.defaultView}function _setHtml(a,b){if(1==a.nodeType){var c=_getDoc(a);try{a.innerHTML=''+b;var d=c.getElementById("__kindeditor_temp_tag__");d.parentNode.removeChild(d)}catch(e){K(a).empty(),K("@"+b,c).each(function(){a.appendChild(this)})}}}function _hasClass(a,b){return _inString(b,a.className," ")}function _setAttr(a,b,c){_IE&&8>_V&&"class"==b.toLowerCase()&&(b="className"),a.setAttribute(b,""+c)}function _removeAttr(a,b){_IE&&8>_V&&"class"==b.toLowerCase()&&(b="className"),_setAttr(a,b,""),a.removeAttribute(b)}function _getNodeName(a){return a&&a.nodeName?a.nodeName.toLowerCase():""}function _computedCss(a,b){var c=_getWin(a),d=_toCamel(b),e="";if(c.getComputedStyle){var f=c.getComputedStyle(a,null);e=f[d]||f.getPropertyValue(b)||a.style[d]}else a.currentStyle&&(e=a.currentStyle[d]||a.style[d]);return e}function _hasVal(a){return!!_VALUE_TAG_MAP[_getNodeName(a)]}function _docElement(a){return a=a||document,_QUIRKS?a.body:a.documentElement}function _docHeight(a){var b=_docElement(a);return Math.max(b.scrollHeight,b.clientHeight)}function _docWidth(a){var b=_docElement(a);return Math.max(b.scrollWidth,b.clientWidth)}function _getScrollPos(a){a=a||document;var b,c;return _IE||_NEWIE||_OPERA?(b=_docElement(a).scrollLeft,c=_docElement(a).scrollTop):(b=_getWin(a).scrollX,c=_getWin(a).scrollY),{x:b,y:c}}function KNode(a){this.init(a)}function _updateCollapsed(a){return a.collapsed=a.startContainer===a.endContainer&&a.startOffset===a.endOffset,a}function _copyAndDelete(a,b,c){function d(d,e,f){var g,i=d.nodeValue.length;if(b){var j=d.cloneNode(!0);g=e>0?j.splitText(e):j,i>f&&g.splitText(f-e)}if(c){var k=d;if(e>0&&(k=d.splitText(e),a.setStart(d,e)),i>f){var l=k.splitText(f-e);a.setEnd(l,0)}h.push(k)}return g}function e(){c&&a.up().collapse(!0);for(var b=0,d=h.length;d>b;b++){var e=h[b];e.parentNode&&e.parentNode.removeChild(e)}}function f(e,n){for(var o,p=e.firstChild;p;){var q=new KRange(g).selectNode(p);if(j=q.compareBoundaryPoints(_START_TO_END,a),j>=0&&0>=k&&(k=q.compareBoundaryPoints(_START_TO_START,a)),k>=0&&0>=l&&(l=q.compareBoundaryPoints(_END_TO_END,a)),l>=0&&0>=m&&(m=q.compareBoundaryPoints(_END_TO_START,a)),m>=0)return!1;if(o=p.nextSibling,j>0)if(1==p.nodeType)if(k>=0&&0>=l)b&&n.appendChild(p.cloneNode(!0)),c&&h.push(p);else{var r;if(b&&(r=p.cloneNode(!1),n.appendChild(r)),f(p,r)===!1)return!1}else if(3==p.nodeType){var s;if(s=p==i.startContainer?d(p,i.startOffset,p.nodeValue.length):p==i.endContainer?d(p,0,i.endOffset):d(p,0,p.nodeValue.length),b)try{n.appendChild(s)}catch(t){}}p=o}}var g=a.doc,h=[],i=a.cloneRange().down(),j=-1,k=-1,l=-1,m=-1,n=a.commonAncestor(),o=g.createDocumentFragment();if(3==n.nodeType){var p=d(n,a.startOffset,a.endOffset);return b&&o.appendChild(p),e(),b?o:a}f(n,o),c&&a.up().collapse(!0);for(var q=0,r=h.length;r>q;q++){var s=h[q];s.parentNode&&s.parentNode.removeChild(s)}return b?o:a}function _moveToElementText(a,b){for(var c=b;c;){var d=K(c);if("marquee"==d.name||"select"==d.name)return;c=c.parentNode}try{a.moveToElementText(b)}catch(e){}}function _getStartEnd(a,b){var c=a.parentElement().ownerDocument,d=a.duplicate();d.collapse(b);var e=d.parentElement(),f=e.childNodes;if(0===f.length)return{node:e.parentNode,offset:K(e).index()};var g=c,h=0,i=-1,j=a.duplicate();_moveToElementText(j,e);for(var k=0,l=f.length;l>k;k++){var m=f[k];if(i=j.compareEndPoints("StartToStart",d),0===i)return{node:m.parentNode,offset:k};if(1==m.nodeType){var n,o=a.duplicate(),p=K(m),q=m;p.isControl()&&(n=c.createElement("span"),p.after(n),q=n,h+=p.text().replace(/\r\n|\n|\r/g,"").length),_moveToElementText(o,q),j.setEndPoint("StartToEnd",o),i>0?h+=o.text.replace(/\r\n|\n|\r/g,"").length:h=0,n&&K(n).remove()}else 3==m.nodeType&&(j.moveStart("character",m.nodeValue.length),h+=m.nodeValue.length);0>i&&(g=m)}if(0>i&&1==g.nodeType)return{node:e,offset:K(e.lastChild).index()+1};if(i>0)for(;g.nextSibling&&1==g.nodeType;)g=g.nextSibling;if(j=a.duplicate(),_moveToElementText(j,e),j.setEndPoint("StartToEnd",d),h-=j.text.replace(/\r\n|\n|\r/g,"").length,i>0&&3==g.nodeType)for(var r=g.previousSibling;r&&3==r.nodeType;)h-=r.nodeValue.length,r=r.previousSibling;return{node:g,offset:h}}function _getEndRange(a,b){var c=a.ownerDocument||a,d=c.body.createTextRange();if(c==a)return d.collapse(!0),d;if(1==a.nodeType&&a.childNodes.length>0){var e,f,g=a.childNodes;if(0===b?(f=g[0],e=!0):(f=g[b-1],e=!1),!f)return d;if("head"===K(f).name)return 1===b&&(e=!0),2===b&&(e=!1),d.collapse(e),d;if(1==f.nodeType){var h,i=K(f);return i.isControl()&&(h=c.createElement("span"),e?i.before(h):i.after(h),f=h),_moveToElementText(d,f),d.collapse(e),h&&K(h).remove(),d}a=f,b=e?0:f.nodeValue.length}var j=c.createElement("span");return K(a).before(j),_moveToElementText(d,j),d.moveStart("character",b),K(j).remove(),d}function _toRange(a){function b(a){"tr"==K(a.node).name&&(a.node=a.node.cells[a.offset],a.offset=0)}var c,d;if(_IERANGE){if(a.item)return c=_getDoc(a.item(0)),d=new KRange(c),d.selectNode(a.item(0)),d;c=a.parentElement().ownerDocument;var e=_getStartEnd(a,!0),f=_getStartEnd(a,!1);return b(e),b(f),d=new KRange(c),d.setStart(e.node,e.offset),d.setEnd(f.node,f.offset),d}var g=a.startContainer;return c=g.ownerDocument||g,d=new KRange(c),d.setStart(g,a.startOffset),d.setEnd(a.endContainer,a.endOffset),d}function KRange(a){this.init(a)}function _range(a){return a.nodeName?new KRange(a):a.constructor===KRange?a:_toRange(a)}function _nativeCommand(a,b,c){try{a.execCommand(b,!1,c)}catch(d){}}function _nativeCommandValue(a,b){var c="";try{c=a.queryCommandValue(b)}catch(d){}return"string"!=typeof c&&(c=""),c}function _getSel(a){var b=_getWin(a);return _IERANGE?a.selection:b.getSelection()}function _getRng(a){var b,c=_getSel(a);try{b=c.rangeCount>0?c.getRangeAt(0):c.createRange()}catch(d){}return!_IERANGE||b&&(b.item||b.parentElement().ownerDocument===a)?b:null}function _singleKeyMap(a){var b,c,d={};return _each(a,function(a,e){b=a.split(",");for(var f=0,g=b.length;g>f;f++)c=b[f],d[c]=e}),d}function _hasAttrOrCss(a,b){return _hasAttrOrCssByKey(a,b,"*")||_hasAttrOrCssByKey(a,b)}function _hasAttrOrCssByKey(a,b,c){if(c=c||a.name,1!==a.type)return!1;var d=_singleKeyMap(b);if(!d[c])return!1;for(var e=d[c].split(","),f=0,g=e.length;g>f;f++){var h=e[f];if("*"===h)return!0;var i=/^(\.?)([^=]+)(?:=([^=]*))?$/.exec(h),j=i[1]?"css":"attr";h=i[2];var k=i[3]||"";if(""===k&&""!==a[j](h))return!0;if(""!==k&&a[j](h)===k)return!0}return!1}function _removeAttrOrCss(a,b){1==a.type&&(_removeAttrOrCssByKey(a,b,"*"),_removeAttrOrCssByKey(a,b))}function _removeAttrOrCssByKey(a,b,c){if(c=c||a.name,1===a.type){var d=_singleKeyMap(b);if(d[c]){for(var e=d[c].split(","),f=!1,g=0,h=e.length;h>g;g++){var i=e[g];if("*"===i){f=!0;break}var j=/^(\.?)([^=]+)(?:=([^=]*))?$/.exec(i);i=j[2],j[1]?(i=_toCamel(i),a[0].style[i]&&(a[0].style[i]="")):a.removeAttr(i)}f&&a.remove(!0)}}}function _getInnerNode(a){for(var b=a;b.first();)b=b.first();return b}function _isEmptyNode(a){return 1!=a.type||a.isSingle()?!1:""===a.html().replace(/<[^>]+>/g,"")}function _mergeWrapper(a,b){a=a.clone(!0);for(var c=_getInnerNode(a),d=a,e=!1;b;){for(;d;)d.name===b.name&&(_mergeAttrs(d,b.attr(),b.css()),e=!0),d=d.first();e||c.append(b.clone(!1)),e=!1,b=b.first()}return a}function _wrapNode(a,b){if(b=b.clone(!0),3==a.type)return _getInnerNode(b).append(a.clone(!1)),a.replaceWith(b),b;for(var c,d=a;(c=a.first())&&1==c.children().length;)a=c;c=a.first();for(var e=a.doc.createDocumentFragment();c;)e.appendChild(c[0]),c=c.next();return b=_mergeWrapper(d,b),e.firstChild&&_getInnerNode(b).append(e),d.replaceWith(b),b}function _mergeAttrs(a,b,c){_each(b,function(b,c){"style"!==b&&a.attr(b,c)}),_each(c,function(b,c){a.css(b,c)})}function _inPreElement(a){for(;a&&"body"!=a.name;){if(_PRE_TAG_MAP[a.name]||"div"==a.name&&a.hasClass("ke-script"))return!0;a=a.parent()}return!1}function KCmd(a){this.init(a)}function _cmd(a){if(a.nodeName){var b=_getDoc(a);a=_range(b).selectNodeContents(b.body).collapse(!1)}return new KCmd(a)}function _drag(a){var b=a.moveEl,c=a.moveFn,d=a.clickEl||b,e=a.beforeDrag,f=a.iframeFix===undefined?!0:a.iframeFix,g=[document];f&&K("iframe").each(function(){var a=_formatUrl(this.src||"","absolute");if(!/^https?:\/\//.test(a)){var b;try{b=_iframeDoc(this)}catch(c){}if(b){var d=K(this).pos();K(b).data("pos-x",d.x),K(b).data("pos-y",d.y),g.push(b)}}}),d.mousedown(function(a){function f(a){a.preventDefault();var b=K(_getDoc(a.target)),e=_round((b.data("pos-x")||0)+a.pageX-o),f=_round((b.data("pos-y")||0)+a.pageY-p);c.call(d,k,l,m,n,e,f)}function h(a){a.preventDefault()}function i(a){a.preventDefault(),K(g).unbind("mousemove",f).unbind("mouseup",i).unbind("selectstart",h),j.releaseCapture&&j.releaseCapture()}if(0===a.button||1===a.button){a.stopPropagation();var j=d.get(),k=_removeUnit(b.css("left")),l=_removeUnit(b.css("top")),m=b.width(),n=b.height(),o=a.pageX,p=a.pageY;e&&e(),K(g).mousemove(f).mouseup(i).bind("selectstart",h),j.setCapture&&j.setCapture()}})}function KWidget(a){this.init(a)}function _widget(a){return new KWidget(a)}function _iframeDoc(a){return a=_get(a),a.contentDocument||a.contentWindow.document}function _getInitHtml(a,b,c,d){var e=[""===_direction?"":'','',""];return _isArray(c)||(c=[c]),_each(c,function(a,b){b&&e.push('')}),d&&e.push(""),e.push(""),e.join("\n")}function _elementVal(a,b){if(a.hasVal()){if(b===undefined){var c=a.val();return c=c.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/gi,"")}return a.val(b)}return a.html(b)}function KEdit(a){this.init(a)}function _edit(a){return new KEdit(a)}function _selectToolbar(a,b){var c=this,d=c.get(a);if(d){if(d.hasClass("ke-disabled"))return;b(d)}}function KToolbar(a){this.init(a)}function _toolbar(a){return new KToolbar(a)}function KMenu(a){this.init(a)}function _menu(a){return new KMenu(a)}function KColorPicker(a){this.init(a)}function _colorpicker(a){return new KColorPicker(a)}function KUploadButton(a){this.init(a)}function _uploadbutton(a){return new KUploadButton(a)}function _createButton(a){a=a||{};var b=a.name||"",c=K(''),d=K('');return a.click&&d.click(a.click),c.append(d),c}function KDialog(a){this.init(a)}function _dialog(a){return new KDialog(a)}function _tabs(a){var b=_widget(a),c=b.remove,d=a.afterSelect,e=b.div,f=[];e.addClass("ke-tabs").bind("contextmenu,mousedown,mousemove",function(a){a.preventDefault()});var g=K('
    ');return e.append(g),b.add=function(a){var b=K('
  • '+a.title+"
  • ");b.data("tab",a),f.push(b),g.append(b)},b.selectedIndex=0,b.select=function(a){b.selectedIndex=a,_each(f,function(c,d){d.unbind(),c===a?(d.addClass("ke-tabs-li-selected"),K(d.data("tab").panel).show("")):(d.removeClass("ke-tabs-li-selected").removeClass("ke-tabs-li-on").mouseover(function(){K(this).addClass("ke-tabs-li-on")}).mouseout(function(){K(this).removeClass("ke-tabs-li-on")}).click(function(){b.select(c)}),K(d.data("tab").panel).hide())}),d&&d.call(b,a)},b.remove=function(){_each(f,function(){this.remove()}),g.remove(),c.call(b)},b}function _loadScript(a,b){var c=document.getElementsByTagName("head")[0]||(_QUIRKS?document.body:document.documentElement),d=document.createElement("script");c.appendChild(d),d.src=a,d.charset="utf-8",d.onload=d.onreadystatechange=function(){this.readyState&&"loaded"!==this.readyState||(b&&b(),d.onload=d.onreadystatechange=null,c.removeChild(d))}}function _chopQuery(a){var b=a.indexOf("?");return b>0?a.substr(0,b):a}function _loadStyle(a){for(var b=document.getElementsByTagName("head")[0]||(_QUIRKS?document.body:document.documentElement),c=document.createElement("link"),d=_chopQuery(_formatUrl(a,"absolute")),e=K('link[rel="stylesheet"]',b),f=0,g=e.length;g>f;f++)if(_chopQuery(_formatUrl(e[f].href,"absolute"))===d)return;b.appendChild(c),c.href=a,c.rel="stylesheet"}function _ajax(a,b,c,d,e){c=c||"GET",e=e||"json";var f=window.XMLHttpRequest?new window.XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");if(f.open(c,a,!0),f.onreadystatechange=function(){if(4==f.readyState&&200==f.status&&b){var a=_trim(f.responseText);"json"==e&&(a=_json(a)),b(a)}},"POST"==c){var g=[];_each(d,function(a,b){g.push(encodeURIComponent(a)+"="+encodeURIComponent(b))});try{f.setRequestHeader("Content-Type","application/x-www-form-urlencoded")}catch(h){}f.send(g.join("&"))}else f.send(null)}function _plugin(a,b){return a===undefined?_plugins:b?void(_plugins[a]=b):_plugins[a]}function _parseLangKey(a){var b,c="core";return(b=/^(\w+)\.(\w+)$/.exec(a))&&(c=b[1],a=b[2]),{ns:c,key:a}}function _lang(a,b){if(b=b===undefined?K.options.langType:b,"string"==typeof a){if(!_language[b])return"no language";var c=a.length-1;if("."===a.substr(c))return _language[b][a.substr(0,c)];var d=_parseLangKey(a);return _language[b][d.ns][d.key]}_each(a,function(a,c){var d=_parseLangKey(a);_language[b]||(_language[b]={}),_language[b][d.ns]||(_language[b][d.ns]={}),_language[b][d.ns][d.key]=c})}function _getImageFromRange(a,b){if(!a.collapsed){a=a.cloneRange().up();var c=a.startContainer,d=a.startOffset;if(_WEBKIT||a.isControl()){var e=K(c.childNodes[d]);if(e&&"img"==e.name)return b(e)?e:void 0}}}function _bindContextmenuEvent(){var a=this,b=a.edit.doc;K(b).contextmenu(function(b){if(a.menu&&a.hideMenu(),!a.useContextmenu)return void b.preventDefault();if(0!==a._contextmenus.length){var c=0,d=[];for(_each(a._contextmenus,function(){return"-"==this.title?void d.push(this):void(this.cond&&this.cond()&&(d.push(this),this.width&&this.width>c&&(c=this.width)))});d.length>0&&"-"==d[0].title;)d.shift();for(;d.length>0&&"-"==d[d.length-1].title;)d.pop();var e=null;if(_each(d,function(a){"-"==this.title&&"-"==e.title&&delete d[a],e=this}),d.length>0){b.preventDefault();var f=K(a.edit.iframe).pos(),g=_menu({x:f.x+b.clientX,y:f.y+b.clientY,width:c,css:{visibility:"hidden"},shadowMode:a.shadowMode});_each(d,function(){this.title&&g.addItem(this)});var h=_docElement(g.doc),i=g.div.height();b.clientY+i>=h.clientHeight-100&&g.pos(g.x,_removeUnit(g.y)-i),g.div.css("visibility","visible"),a.menu=g}}})}function _bindNewlineEvent(){function a(a){for(var b=K(a.commonAncestor());b&&(1!=b.type||b.isStyle());)b=b.parent();return b.name}var b=this,c=b.edit.doc,d=b.newlineTag;if(!(_IE&&"br"!==d||_GECKO&&3>_V&&"p"!==d||_OPERA&&9>_V)){var e=_toMap("h1,h2,h3,h4,h5,h6,pre,li"),f=_toMap("p,h1,h2,h3,h4,h5,h6,pre,li,blockquote");K(c).keydown(function(g){if(!(13!=g.which||g.shiftKey||g.ctrlKey||g.altKey)){b.cmd.selection();var h=a(b.cmd.range);if("marquee"!=h&&"select"!=h)return"br"!==d||e[h]?void(f[h]||_nativeCommand(c,"formatblock","

    ")):(g.preventDefault(),void b.insertHtml("
    "+(_IE&&9>_V?"":"​")))}}),K(c).keyup(function(e){if(!(13!=e.which||e.shiftKey||e.ctrlKey||e.altKey)&&"br"!=d){if(_GECKO){var g=b.cmd.commonAncestor("p"),h=b.cmd.commonAncestor("a");return void(h&&""==h.text()&&(h.remove(!0),b.cmd.range.selectNodeContents(g[0]).collapse(!0),b.cmd.select()))}b.cmd.selection();var i=a(b.cmd.range);if("marquee"!=i&&"select"!=i){f[i]||_nativeCommand(c,"formatblock","

    ");var j=b.cmd.commonAncestor("div");if(j){for(var k=K("

    "),l=j[0].firstChild;l;){var m=l.nextSibling;k.append(l),l=m}j.before(k),j.remove(),b.cmd.range.selectNodeContents(k[0]),b.cmd.select()}}}})}}function _bindTabEvent(){var a=this,b=a.edit.doc;K(b).keydown(function(c){if(9==c.which){if(c.preventDefault(),a.afterTab)return void a.afterTab.call(a,c);var d=a.cmd,e=d.range;e.shrink(),e.collapsed&&1==e.startContainer.nodeType&&(e.insertNode(K("@ ",b)[0]),d.select()),a.insertHtml("    ")}})}function _bindFocusEvent(){var a=this;K(a.edit.textarea[0],a.edit.win).focus(function(b){a.afterFocus&&a.afterFocus.call(a,b)}).blur(function(b){a.afterBlur&&a.afterBlur.call(a,b)})}function _removeBookmarkTag(a){return _trim(a.replace(/]*id="?__kindeditor_bookmark_\w+_\d+__"?[^>]*><\/span>/gi,""))}function _removeTempTag(a){return a.replace(/]+class="?__kindeditor_paste__"?[^>]*>[\s\S]*?<\/div>/gi,"")}function _addBookmarkToStack(a,b){if(0===a.length)return void a.push(b);var c=a[a.length-1];_removeBookmarkTag(b.html)!==_removeBookmarkTag(c.html)&&a.push(b)}function _undoToRedo(a,b){var c,d,e=this,f=e.edit,g=f.doc.body;if(0===a.length)return e;f.designMode?(c=e.cmd.range,d=c.createBookmark(!0),d.html=g.innerHTML):d={html:g.innerHTML},_addBookmarkToStack(b,d); +var h=a.pop();return _removeBookmarkTag(d.html)===_removeBookmarkTag(h.html)&&a.length>0&&(h=a.pop()),f.designMode?(f.html(h.html),h.start&&(c.moveToBookmark(h),e.select())):K(g).html(_removeBookmarkTag(h.html)),e}function KEditor(a){function b(a,b){KEditor.prototype[a]===undefined&&(c[a]=b),c.options[a]=b}var c=this;c.options={},_each(a,function(c){b(c,a[c])}),_each(K.options,function(a,d){c[a]===undefined&&b(a,d)});var d=K(c.srcElement||"').css("width","100%"),c.tabIndex=isNaN(parseInt(a.tabIndex,10))?c.srcElement.attr("tabindex"):parseInt(a.tabIndex,10),c.iframe.attr("tabindex",c.tabIndex),c.textarea.attr("tabindex",c.tabIndex),c.width&&c.setWidth(c.width),c.height&&c.setHeight(c.height),c.designMode?c.textarea.hide():c.iframe.hide(),h&&c.iframe.bind("load",function(){c.iframe.unbind("load"),_IE?b():setTimeout(b,0)}),c.div.append(c.iframe),c.div.append(c.textarea),c.srcElement.hide(),!h&&b()},setWidth:function(a){var b=this;return a=_addUnit(a),b.width=a,b.div.css("width",a),b},setHeight:function(a){var b=this;return a=_addUnit(a),b.height=a,b.div.css("height",a),b.iframe.css("height",a),(_IE&&8>_V||_QUIRKS)&&(a=_addUnit(_removeUnit(a)-2)),b.textarea.css("height",a),b},remove:function(){var a=this,b=a.doc;K(b.body).unbind(),K(b).unbind(),K(a.win).unbind(),a._mousedownHandler&&K(document).unbind("mousedown",a._mousedownHandler),_elementVal(a.srcElement,a.html()),a.srcElement.show(),a.iframe.unbind(),a.textarea.unbind(),KEdit.parent.remove.call(a)},html:function(a,b){var c=this,d=c.doc;if(c.designMode){var e=d.body;return a===undefined?(a=b?""+e.parentNode.innerHTML+"":e.innerHTML,c.beforeGetHtml&&(a=c.beforeGetHtml(a)),_GECKO&&"
    "==a&&(a=""),a):(c.beforeSetHtml&&(a=c.beforeSetHtml(a)),_IE&&_V>=9&&(a=a.replace(/(<.*?checked=")checked(".*>)/gi,"$1$2")),K(e).html(a),c.afterSetHtml&&c.afterSetHtml(),c)}return a===undefined?c.textarea.val():(c.textarea.val(a),c)},design:function(a){var b,c=this;if(a===undefined?!c.designMode:a){if(!c.designMode){b=c.html(),c.designMode=!0,c.textarea.hide(),c.html(b);var d=c.iframe,e=_removeUnit(c.height);d.height(e-2),d.show(),setTimeout(function(){d.height(e)},0)}}else c.designMode&&(b=c.html(),c.designMode=!1,c.html(b),c.iframe.hide(),c.textarea.show());return c.focus()},focus:function(){var a=this;return a.designMode?a.win.focus():a.textarea[0].focus(),a},blur:function(){var a=this;if(_IE){var b=K('',a.div);a.div.append(b),b[0].focus(),b.remove()}else a.designMode?a.win.blur():a.textarea[0].blur();return a},afterChange:function(a){function b(b){setTimeout(function(){a(b)},1)}var c=this,d=c.doc,e=d.body;return K(d).keyup(function(b){b.ctrlKey||b.altKey||!_CHANGE_KEY_MAP[b.which]||a(b)}),K(d).mouseup(a).contextmenu(a),K(c.win).blur(a),K(e).bind("paste",b),K(e).bind("cut",b),c}}),K.EditClass=KEdit,K.edit=_edit,K.iframeDoc=_iframeDoc,_extend(KToolbar,KWidget,{init:function(a){function b(a){var b=K(a);return b.hasClass("ke-outline")?b:b.hasClass("ke-toolbar-icon")?b.parent():void 0}function c(a,c){var d=b(a.target);if(d){if(d.hasClass("ke-disabled"))return;if(d.hasClass("ke-selected"))return;d[c]("ke-on")}}var d=this;KToolbar.parent.init.call(d,a),d.disableMode=_undef(a.disableMode,!1),d.noDisableItemMap=_toMap(_undef(a.noDisableItems,[])),d._itemMap={},d.div.addClass("ke-toolbar").bind("contextmenu,mousedown,mousemove",function(a){a.preventDefault()}).attr("unselectable","on"),d.div.mouseover(function(a){c(a,"addClass")}).mouseout(function(a){c(a,"removeClass")}).click(function(a){var c=b(a.target);if(c){if(c.hasClass("ke-disabled"))return;d.options.click.call(this,a,c.attr("data-name"))}})},get:function(a){return this._itemMap[a]?this._itemMap[a]:this._itemMap[a]=K("span.ke-icon-"+a,this.div).parent()},select:function(a){return _selectToolbar.call(this,a,function(a){a.addClass("ke-selected")}),self},unselect:function(a){return _selectToolbar.call(this,a,function(a){a.removeClass("ke-selected").removeClass("ke-on")}),self},enable:function(a){var b=this,c=a.get?a:b.get(a);return c&&(c.removeClass("ke-disabled"),c.opacity(1)),b},disable:function(a){var b=this,c=a.get?a:b.get(a);return c&&(c.removeClass("ke-selected").addClass("ke-disabled"),c.opacity(.5)),b},disableAll:function(a,b){var c=this,d=c.noDisableItemMap;return b&&(d=_toMap(b)),(a===undefined?!c.disableMode:a)?(K("span.ke-outline",c.div).each(function(){var a=K(this),b=a[0].getAttribute("data-name",2);d[b]||c.disable(a)}),c.disableMode=!0):(K("span.ke-outline",c.div).each(function(){var a=K(this),b=a[0].getAttribute("data-name",2);d[b]||c.enable(a)}),c.disableMode=!1),c}}),K.ToolbarClass=KToolbar,K.toolbar=_toolbar,_extend(KMenu,KWidget,{init:function(a){var b=this;a.z=a.z||811213,KMenu.parent.init.call(b,a),b.centerLineMode=_undef(a.centerLineMode,!0),b.div.addClass("ke-menu").bind("click,mousedown",function(a){a.stopPropagation()}).attr("unselectable","on")},addItem:function(a){var b=this;if("-"===a.title)return void b.div.append(K('
    '));var c=K('
    '),d=K('
    '),e=K('
    '),f=_addUnit(a.height),g=_undef(a.iconClass,"");b.div.append(c),f&&(c.css("height",f),e.css("line-height",f));var h;return b.centerLineMode&&(h=K('
    '),f&&h.css("height",f)),c.mouseover(function(){K(this).addClass("ke-menu-item-on"),h&&h.addClass("ke-menu-item-center-on")}).mouseout(function(){K(this).removeClass("ke-menu-item-on"),h&&h.removeClass("ke-menu-item-center-on")}).click(function(b){a.click.call(K(this)),b.stopPropagation()}).append(d),h&&c.append(h),c.append(e),a.checked&&(g="ke-icon-checked"),""!==g&&d.html(''),e.html(a.title),b},remove:function(){var a=this;return a.options.beforeRemove&&a.options.beforeRemove.call(a),K(".ke-menu-item",a.div[0]).unbind(),KMenu.parent.remove.call(a),a}}),K.MenuClass=KMenu,K.menu=_menu,_extend(KColorPicker,KWidget,{init:function(a){var b=this;a.z=a.z||811213,KColorPicker.parent.init.call(b,a);var c=a.colors||[["#E53333","#E56600","#FF9900","#64451D","#DFC5A4","#FFE500"],["#009900","#006600","#99BB00","#B8D100","#60D978","#00D5FF"],["#337FE5","#003399","#4C33E5","#9933E5","#CC33E5","#EE33EE"],["#FFFFFF","#CCCCCC","#999999","#666666","#333333","#000000"]];b.selectedColor=(a.selectedColor||"").toLowerCase(),b._cells=[],b.div.addClass("ke-colorpicker").bind("click,mousedown",function(a){a.stopPropagation()}).attr("unselectable","on");var d=b.doc.createElement("table");b.div.append(d),d.className="ke-colorpicker-table",d.cellPadding=0,d.cellSpacing=0,d.border=0;var e=d.insertRow(0),f=e.insertCell(0);f.colSpan=c[0].length,b._addAttr(f,"","ke-colorpicker-cell-top");for(var g=0;g
    ').css("background-color",b)):a.html(d.options.noColor),K(a).attr("unselectable","on"),d._cells.push(a)},remove:function(){var a=this;return _each(a._cells,function(){this.unbind()}),KColorPicker.parent.remove.call(a),a}}),K.ColorPickerClass=KColorPicker,K.colorpicker=_colorpicker,_extend(KUploadButton,{init:function(a){var b=this,c=K(a.button),d=a.fieldName||"file",e=a.url||"",f=c.val(),g=a.extraParams||{},h=c[0].className||"",i=a.target||"kindeditor_upload_iframe_"+(new Date).getTime();a.afterError=a.afterError||function(a){alert(a)};var j=[];for(var k in g)j.push('');var l=['
    ',a.target?"":'',a.form?'
    ':'
    ','',j.join(""),'',"",'',a.form?"
    ":"","
    "].join(""),m=K(l,c.doc);c.hide(),c.before(m),b.div=m,b.button=c,b.iframe=a.target?K('iframe[name="'+i+'"]'):K("iframe",m),b.form=a.form?K(a.form):K("form",m),b.fileBox=K(".ke-upload-file",m);var n=a.width||K(".ke-button-common",m).width();K(".ke-upload-area",m).width(n),b.options=a},submit:function(){var a=this,b=a.iframe;return b.bind("load",function(){b.unbind();var c=document.createElement("form");a.fileBox.before(c),K(c).append(a.fileBox),c.reset(),K(c).remove(!0);var d,e=K.iframeDoc(b),f=e.getElementsByTagName("pre")[0],g="";g=f?f.innerHTML:e.body.innerHTML,g=_unescape(g),b[0].src="javascript:false";try{d=K.json(g)}catch(h){a.options.afterError.call(a,""+e.body.parentNode.innerHTML+"")}d&&a.options.afterUpload.call(a,d)}),a.form[0].submit(),a},remove:function(){var a=this;return a.fileBox&&a.fileBox.unbind(),a.iframe.remove(),a.div.remove(),a.button.show(),a}}),K.UploadButtonClass=KUploadButton,K.uploadbutton=_uploadbutton,_extend(KDialog,KWidget,{init:function(a){var b=this,c=_undef(a.shadowMode,!0);a.z=a.z||811213,a.shadowMode=!1,a.autoScroll=_undef(a.autoScroll,!0),KDialog.parent.init.call(b,a);var d=a.title,e=K(a.body,b.doc),f=a.previewBtn,g=a.yesBtn,h=a.noBtn,i=a.closeBtn,j=_undef(a.showMask,!0);b.div.addClass("ke-dialog").bind("click,mousedown",function(a){a.stopPropagation()});var k=K('
    ').appendTo(b.div);_IE&&7>_V?b.iframeMask=K('').appendTo(b.div):c&&K('
    ').appendTo(b.div);var l=K('
    ');k.append(l),l.html(d),b.closeIcon=K('').click(i.click),l.append(b.closeIcon),b.draggable({clickEl:l,beforeDrag:a.beforeDrag});var m=K('
    ');k.append(m),m.append(e);var n=K('');if((f||g||h)&&k.append(n),_each([{btn:f,name:"preview"},{btn:g,name:"yes"},{btn:h,name:"no"}],function(){if(this.btn){var a=_createButton(this.btn);a.addClass("ke-dialog-"+this.name),n.append(a)}}),b.height&&m.height(_removeUnit(b.height)-l.height()-n.height()),b.div.width(b.div.width()),b.div.height(b.div.height()),b.mask=null,j){var o=_docElement(b.doc),p=Math.max(o.scrollWidth,o.clientWidth),q=Math.max(o.scrollHeight,o.clientHeight);b.mask=_widget({x:0,y:0,z:b.z-1,cls:"ke-dialog-mask",width:p,height:q})}b.autoPos(b.div.width(),b.div.height()),b.footerDiv=n,b.bodyDiv=m,b.headerDiv=l,b.isLoading=!1},setMaskIndex:function(a){var b=this;b.mask.div.css("z-index",a)},showLoading:function(a){a=_undef(a,"");var b=this,c=b.bodyDiv;return b.loading=K('
    '+a+"
    ").width(c.width()).height(c.height()).css("top",b.headerDiv.height()+"px"),c.css("visibility","hidden").after(b.loading),b.isLoading=!0,b},hideLoading:function(){return this.loading&&this.loading.remove(),this.bodyDiv.css("visibility","visible"),this.isLoading=!1,this},remove:function(){var a=this;return a.options.beforeRemove&&a.options.beforeRemove.call(a),a.mask&&a.mask.remove(),a.iframeMask&&a.iframeMask.remove(),a.closeIcon.unbind(),K("input",a.div).unbind(),K("button",a.div).unbind(),a.footerDiv.unbind(),a.bodyDiv.unbind(),a.headerDiv.unbind(),K("iframe",a.div).each(function(){K(this).remove()}),KDialog.parent.remove.call(a),a}}),K.DialogClass=KDialog,K.dialog=_dialog,K.tabs=_tabs,K.loadScript=_loadScript,K.loadStyle=_loadStyle,K.ajax=_ajax;var _plugins={},_language={};KEditor.prototype={lang:function(a){return _lang(a,this.langType)},loadPlugin:function(a,b){var c=this,d=this._pluginStatus;return d||(d=this._pluginStatus={}),_plugins[a]?_isFunction(_plugins[a])?(d[a]||(_plugins[a].call(c,KindEditor),d[a]="inited"),b&&b.call(c),c):(setTimeout(function(){c.loadPlugin(a,b)},100),c):(_plugins[a]="loading",_loadScript(c.pluginsPath+a+"/"+a+".js?ver="+encodeURIComponent(K.DEBUG?_TIME:_VERSION),function(){setTimeout(function(){_plugins[a]&&c.loadPlugin(a,b)},0)}),c)},handler:function(a,b){var c=this;return c._handlers[a]||(c._handlers[a]=[]),_isFunction(b)?(c._handlers[a].push(b),c):(_each(c._handlers[a],function(){b=this.call(c,b)}),b)},clickToolbar:function(a,b){var c=this,d="clickToolbar"+a;return b===undefined?c._handlers[d]?c.handler(d):(c.loadPlugin(a,function(){c.handler(d)}),c):c.handler(d,b)},updateState:function(){var a=this;return _each("justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,insertunorderedlist,subscript,superscript,bold,italic,underline,strikethrough".split(","),function(b,c){a.cmd.state(c)?a.toolbar.select(c):a.toolbar.unselect(c)}),a},addContextmenu:function(a){return this._contextmenus.push(a),this},afterCreate:function(a){return this.handler("afterCreate",a)},beforeRemove:function(a){return this.handler("beforeRemove",a)},beforeGetHtml:function(a){return this.handler("beforeGetHtml",a)},beforeSetHtml:function(a){return this.handler("beforeSetHtml",a)},afterSetHtml:function(a){return this.handler("afterSetHtml",a)},create:function(){function a(){return 0===i.height()?void setTimeout(a,100):void b.resize(d,e,!1)}var b=this,c=b.fullscreenMode;if(b.isCreated)return b;if(b.srcElement.data("kindeditor"))return b;b.srcElement.data("kindeditor","true"),_docElement().style.overflow=c?"hidden":"";var d=c?_docElement().clientWidth+"px":b.width,e=c?_docElement().clientHeight+"px":b.height;(_IE&&8>_V||_QUIRKS)&&(e=_addUnit(_removeUnit(e)+2));var f=b.container=K(b.layout);c?K(document.body).append(f):b.srcElement.before(f);var g=K(".toolbar",f),h=K(".edit",f),i=b.statusbar=K(".statusbar",f);f.removeClass("container").addClass("ke-container ke-container-"+b.themeType).css("width",d),c?(f.css({position:"absolute",left:0,top:0,"z-index":811211}),_GECKO||(b._scrollPos=_getScrollPos()),window.scrollTo(0,0),K(document.body).css({height:"1px",overflow:"hidden"}),K(document.body.parentNode).css("overflow","hidden"),b._fullscreenExecuted=!0):(b._fullscreenExecuted&&(K(document.body).css({height:"",overflow:""}),K(document.body.parentNode).css("overflow","")),b._scrollPos&&window.scrollTo(b._scrollPos.x,b._scrollPos.y));var j=[];K.each(b.items,function(a,c){"|"==c?j.push(''):"/"==c?j.push('
    '):(j.push(''),j.push(''))});var k=b.toolbar=_toolbar({src:g,html:j.join(""),noDisableItems:b.noDisableItems,click:function(a,c){if(a.stop(),b.menu){var d=b.menu.name;if(b.hideMenu(),d===c)return}b.clickToolbar(c)}}),l=_removeUnit(e)-k.div.height(),m=b.edit=_edit({height:l>0&&_removeUnit(e)>b.minHeight?l:b.minHeight,src:h,srcElement:b.srcElement,designMode:b.designMode,themesPath:b.themesPath,bodyClass:b.bodyClass,cssPath:b.cssPath,cssData:b.cssData,beforeGetHtml:function(a){return a=b.beforeGetHtml(a),a=_removeBookmarkTag(_removeTempTag(a)),_formatHtml(a,b.filterMode?b.htmlTags:null,b.urlType,b.wellFormatMode,b.indentChar)},beforeSetHtml:function(a){return a=_formatHtml(a,b.filterMode?b.htmlTags:null,"",!1),b.beforeSetHtml(a)},afterSetHtml:function(){b.edit=m=this,b.afterSetHtml()},afterCreate:function(){if(b.edit=m=this,b.cmd=m.cmd,b._docMousedownFn=function(){b.menu&&b.hideMenu()},K(m.doc,document).mousedown(b._docMousedownFn),_bindContextmenuEvent.call(b),_bindNewlineEvent.call(b),_bindTabEvent.call(b),_bindFocusEvent.call(b),m.afterChange(function(){m.designMode&&(b.updateState(),b.addBookmark(),b.options.afterChange&&b.options.afterChange.call(b))}),m.textarea.keyup(function(a){a.ctrlKey||a.altKey||!_INPUT_KEY_MAP[a.which]||b.options.afterChange&&b.options.afterChange.call(b)}),b.readonlyMode&&b.readonly(),b.isCreated=!0,""===b.initContent&&(b.initContent=b.html()),b._undoStack.length>0){var a=b._undoStack.pop();a.start&&(b.html(a.html),m.cmd.range.moveToBookmark(a),b.select())}b.afterCreate(),b.options.afterCreate&&b.options.afterCreate.call(b)}});return i.removeClass("statusbar").addClass("ke-statusbar").append('').append(''),b._fullscreenResizeHandler&&(K(window).unbind("resize",b._fullscreenResizeHandler),b._fullscreenResizeHandler=null),a(),c?(b._fullscreenResizeHandler=function(){b.isCreated&&b.resize(_docElement().clientWidth,_docElement().clientHeight,!1)},K(window).bind("resize",b._fullscreenResizeHandler),k.select("fullscreen"),i.first().css("visibility","hidden"),i.last().css("visibility","hidden")):(_GECKO&&K(window).bind("scroll",function(){b._scrollPos=_getScrollPos()}),b.resizeType>0?_drag({moveEl:f,clickEl:i,moveFn:function(a,c,d,e,f,g){e+=g,b.resize(null,e)}}):i.first().css("visibility","hidden"),2===b.resizeType?_drag({moveEl:f,clickEl:i.last(),moveFn:function(a,c,d,e,f,g){d+=f,e+=g,b.resize(d,e)}}):i.last().css("visibility","hidden")),b},remove:function(){var a=this;return a.isCreated?(a.beforeRemove(),a.srcElement.data("kindeditor",""),a.menu&&a.hideMenu(),_each(a.dialogs,function(){a.hideDialog()}),K(document).unbind("mousedown",a._docMousedownFn),a.toolbar.remove(),a.edit.remove(),a.statusbar.last().unbind(),a.statusbar.unbind(),a.container.remove(),a.container=a.toolbar=a.edit=a.menu=null,a.dialogs=[],a.isCreated=!1,a):a},resize:function(a,b,c){var d=this;return c=_undef(c,!0),a&&(/%/.test(a)||(a=_removeUnit(a),a=a/gi,"").replace(/ /gi," ")):b.html(_escape(a))},isEmpty:function(){return""===_trim(this.text().replace(/\r\n|\n|\r/,""))},isDirty:function(){return _trim(this.initContent.replace(/\r\n|\n|\r|t/g,""))!==_trim(this.html().replace(/\r\n|\n|\r|t/g,""))},selectedHtml:function(){var a=this.isCreated?this.cmd.range.html():"";return a=_removeBookmarkTag(_removeTempTag(a))},count:function(a){var b=this;return a=(a||"html").toLowerCase(),"html"===a?b.html().length:"text"===a?b.text().replace(/<(?:img|embed).*?>/gi,"K").replace(/\r\n|\n|\r/g,"").length:0},exec:function(a){a=a.toLowerCase();var b=this,c=b.cmd,d=_inArray(a,"selectall,copy,paste,print".split(","))<0;return d&&b.addBookmark(!1),c[a].apply(c,_toArray(arguments,1)),d&&(b.updateState(),b.addBookmark(!1),b.options.afterChange&&b.options.afterChange.call(b)),b},insertHtml:function(a,b){return this.isCreated?(a=this.beforeSetHtml(a),this.exec("inserthtml",a,b),this):this},appendHtml:function(a){if(this.html(this.html()+a),this.isCreated){var b=this.cmd;b.range.selectNodeContents(b.doc.body).collapse(!1),b.select()}return this},sync:function(){return _elementVal(this.srcElement,this.html()),this},focus:function(){return this.isCreated?this.edit.focus():this.srcElement[0].focus(),this},blur:function(){return this.isCreated?this.edit.blur():this.srcElement[0].blur(),this},addBookmark:function(a){a=_undef(a,!0);var b,c=this,d=c.edit,e=d.doc.body,f=_removeTempTag(e.innerHTML);if(a&&c._undoStack.length>0){var g=c._undoStack[c._undoStack.length-1];if(Math.abs(f.length-_removeBookmarkTag(g.html).length)0){var c=b.dialogs[0],d=b.dialogs[b.dialogs.length-1];c.setMaskIndex(d.z+2),a.z=d.z+3,a.showMask=!1}var e=_dialog(a);return b.dialogs.push(e),e},hideDialog:function(){var a=this;if(a.dialogs.length>0&&a.dialogs.pop().remove(),a.dialogs.length>0){var b=a.dialogs[0],c=a.dialogs[a.dialogs.length-1];b.setMaskIndex(c.z-1)}return a},errorDialog:function(a){var b=this,c=b.createDialog({width:750,title:b.lang("uploadError"),body:'
    '}),d=K("iframe",c.div),e=K.iframeDoc(d);return e.open(),e.write(a),e.close(),K(e.body).css("background-color","#FFF"),d[0].contentWindow.focus(),b}},_instances=[],K.remove=function(a){_eachEditor(a,function(a){this.remove(),_instances.splice(a,1)})},K.sync=function(a){_eachEditor(a,function(){this.sync()})},K.html=function(a,b){_eachEditor(a,function(){this.html(b)})},K.insertHtml=function(a,b){_eachEditor(a,function(){this.insertHtml(b)})},K.appendHtml=function(a,b){_eachEditor(a,function(){this.appendHtml(b)})},_IE&&7>_V&&_nativeCommand(document,"BackgroundImageCache",!0),K.EditorClass=KEditor,K.editor=_editor,K.create=_create,K.instances=_instances,K.plugin=_plugin,K.lang=_lang,_plugin("core",function(a){var b=this,c={undo:"Z",redo:"Y",bold:"B",italic:"I",underline:"U",print:"P",selectall:"A"};if(b.afterSetHtml(function(){b.options.afterChange&&b.options.afterChange.call(b)}),b.afterCreate(function(){if("form"==b.syncType){for(var c=a(b.srcElement),d=!1;c=c.parent();)if("form"==c.name){d=!0;break}if(d){c.bind("submit",function(){b.sync(),a(window).bind("unload",function(){b.edit.textarea.remove()})});var e=a('[type="reset"]',c);e.click(function(){b.html(b.initContent),b.cmd.selection()}),b.beforeRemove(function(){c.unbind(),e.unbind()})}}}),b.clickToolbar("source",function(){b.edit.designMode?(b.toolbar.disableAll(!0),b.edit.design(!1),b.toolbar.select("source")):(b.toolbar.disableAll(!1),b.edit.design(!0),b.toolbar.unselect("source"),_GECKO?setTimeout(function(){b.cmd.selection()},0):b.cmd.selection()),b.designMode=b.edit.designMode}),b.afterCreate(function(){b.designMode||b.toolbar.disableAll(!0).select("source")}),b.clickToolbar("fullscreen",function(){b.fullscreen()}),b.fullscreenShortcut){var d=!1;b.afterCreate(function(){if(a(b.edit.doc,b.edit.textarea).keyup(function(a){27==a.which&&setTimeout(function(){b.fullscreen()},0)}),d){if(_IE&&!b.designMode)return;b.focus()}d||(d=!0)})}_each("undo,redo".split(","),function(a,d){c[d]&&b.afterCreate(function(){_ctrl(this.edit.doc,c[d],function(){b.clickToolbar(d)})}),b.clickToolbar(d,function(){b[d]()})}),b.clickToolbar("formatblock",function(){var a=b.lang("formatblock.formatBlock"),c={h1:28,h2:24,h3:18,H4:14,p:12},d=b.cmd.val("formatblock"),e=b.createMenu({name:"formatblock",width:"en"==b.langType?200:150});_each(a,function(a,f){var g="font-size:"+c[a]+"px;";"h"===a.charAt(0)&&(g+="font-weight:bold;"),e.addItem({title:''+f+"",height:c[a]+12,checked:d===a||d===f,click:function(){b.select().exec("formatblock","<"+a+">").hideMenu()}})})}),b.clickToolbar("fontname",function(){var a=b.cmd.val("fontname"),c=b.createMenu({name:"fontname",width:150});_each(b.lang("fontname.fontName"),function(d,e){c.addItem({title:''+e+"",checked:a===d.toLowerCase()||a===e.toLowerCase(),click:function(){b.exec("fontname",d).hideMenu()}})})}),b.clickToolbar("fontsize",function(){var a=b.cmd.val("fontsize"),c=b.createMenu({name:"fontsize",width:150});_each(b.fontSizeTable,function(d,e){c.addItem({title:''+e+"",height:_removeUnit(e)+12,checked:a===e,click:function(){b.exec("fontsize",e).hideMenu()}})})}),_each("forecolor,hilitecolor".split(","),function(a,c){b.clickToolbar(c,function(){b.createMenu({name:c,selectedColor:b.cmd.val(c)||"default",colors:b.colorTable,click:function(a){b.exec(c,a).hideMenu()}})})}),_each("cut,copy,paste".split(","),function(a,c){b.clickToolbar(c,function(){b.focus();try{b.exec(c,null)}catch(a){alert(b.lang(c+"Error"))}})}),b.clickToolbar("about",function(){var a='
    KindEditor '+_VERSION+'
    Copyright © kindsoft.net All rights reserved.
    ';b.createDialog({name:"about",width:350,title:b.lang("about"),body:a})}),b.plugin.getSelectedLink=function(){return b.cmd.commonAncestor("a")},b.plugin.getSelectedImage=function(){return _getImageFromRange(b.edit.cmd.range,function(a){return!/^ke-\w+$/i.test(a[0].className)})},b.plugin.getSelectedFlash=function(){return _getImageFromRange(b.edit.cmd.range,function(a){return"ke-flash"==a[0].className})},b.plugin.getSelectedMedia=function(){return _getImageFromRange(b.edit.cmd.range,function(a){return"ke-media"==a[0].className||"ke-rm"==a[0].className})},b.plugin.getSelectedAnchor=function(){return _getImageFromRange(b.edit.cmd.range,function(a){return"ke-anchor"==a[0].className})},_each("link,image,flash,media,anchor".split(","),function(a,c){var d=c.charAt(0).toUpperCase()+c.substr(1);_each("edit,delete".split(","),function(a,e){b.addContextmenu({title:b.lang(e+d),click:function(){b.loadPlugin(c,function(){b.plugin[c][e](),b.hideMenu()})},cond:b.plugin["getSelected"+d],width:150,iconClass:"edit"==e?"ke-icon-"+c:undefined}) +}),b.addContextmenu({title:"-"})}),b.plugin.getSelectedTable=function(){return b.cmd.commonAncestor("table")},b.plugin.getSelectedRow=function(){return b.cmd.commonAncestor("tr")},b.plugin.getSelectedCell=function(){return b.cmd.commonAncestor("td")},_each("prop,cellprop,colinsertleft,colinsertright,rowinsertabove,rowinsertbelow,rowmerge,colmerge,rowsplit,colsplit,coldelete,rowdelete,insert,delete".split(","),function(a,c){var d=_inArray(c,["prop","delete"])<0?b.plugin.getSelectedCell:b.plugin.getSelectedTable;b.addContextmenu({title:b.lang("table"+c),click:function(){b.loadPlugin("table",function(){b.plugin.table[c](),b.hideMenu()})},cond:d,width:170,iconClass:"ke-icon-table"+c})}),b.addContextmenu({title:"-"}),_each("selectall,justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,insertunorderedlist,indent,outdent,subscript,superscript,hr,print,bold,italic,underline,strikethrough,removeformat,unlink".split(","),function(a,d){c[d]&&b.afterCreate(function(){_ctrl(this.edit.doc,c[d],function(){b.cmd.selection(),b.clickToolbar(d)})}),b.clickToolbar(d,function(){b.focus().exec(d,null)})}),b.afterCreate(function(){function c(){d.range.moveToBookmark(e),d.select(),_WEBKIT&&(a("div."+h,f).each(function(){a(this).after("
    ").remove(!0)}),a("span.Apple-style-span",f).remove(!0),a("span.Apple-tab-span",f).remove(!0),a("span[style]",f).each(function(){"nowrap"==a(this).css("white-space")&&a(this).remove(!0)}),a("meta",f).remove());var c=f[0].innerHTML;f.remove(),""!==c&&(_WEBKIT&&(c=c.replace(/(
    )\1/gi,"$1")),2===b.pasteType&&(c=c.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/gi,""),/schemas-microsoft-com|worddocument|mso-\w+/i.test(c)?c=_clearMsWord(c,b.filterMode?b.htmlTags:a.options.htmlTags):(c=_formatHtml(c,b.filterMode?b.htmlTags:null),c=b.beforeSetHtml(c))),1===b.pasteType&&(c=c.replace(/ /gi," "),c=c.replace(/\n\s*\n/g,"\n"),c=c.replace(/]*>/gi,"\n"),c=c.replace(/<\/p>]*>/gi,"\n"),c=c.replace(/<[^>]+>/g,""),c=c.replace(/ {2}/g,"  "),"p"==b.newlineTag?/\n/.test(c)&&(c=c.replace(/^/,"

    ").replace(/$/,"

    ").replace(/\n/g,"

    ")):c=c.replace(/\n/g,"
    $&")),b.insertHtml(c,!0))}var d,e,f,g=b.edit.doc,h="__kindeditor_paste__",i=!1;a(g.body).bind("paste",function(j){if(0===b.pasteType)return void j.stop();if(!i){if(i=!0,a("div."+h,g).remove(),d=b.cmd.selection(),e=d.range.createBookmark(),f=a('

    ',g).css({position:"absolute",width:"1px",height:"1px",overflow:"hidden",left:"-1981px",top:a(e.start).pos().y+"px","white-space":"nowrap"}),a(g.body).append(f),_IE){var k=d.range.get(!0);k.moveToElementText(f[0]),k.select(),k.execCommand("paste"),j.preventDefault()}else d.range.selectNodeContents(f[0]),d.select(),f[0].tabIndex=-1,f[0].focus();setTimeout(function(){c(),i=!1},0)}})}),b.beforeGetHtml(function(a){return _IE&&8>=_V&&(a=a.replace(/]*data-ke-input-tag="([^"]*)"[^>]*>([\s\S]*?)<\/div>/gi,function(a,b){return unescape(b)}),a=a.replace(/(]*)?>)/gi,function(a,b,c){return/\s+type="[^"]+"/i.test(a)?a:b+' type="text"'+c})),a.replace(/(<(?:noscript|noscript\s[^>]*)>)([\s\S]*?)(<\/noscript>)/gi,function(a,b,c,d){return b+_unescape(c).replace(/\s+/g," ")+d}).replace(/]*class="?ke-(flash|rm|media)"?[^>]*>/gi,function(a){var b=_getAttrList(a),c=_getCssList(b.style||""),d=_mediaAttrs(b["data-ke-tag"]),e=_undef(c.width,""),f=_undef(c.height,"");return/px/i.test(e)&&(e=_removeUnit(e)),/px/i.test(f)&&(f=_removeUnit(f)),d.width=_undef(b.width,e),d.height=_undef(b.height,f),_mediaEmbed(d)}).replace(/]*class="?ke-anchor"?[^>]*>/gi,function(a){var b=_getAttrList(a);return''}).replace(/]*data-ke-script-attr="([^"]*)"[^>]*>([\s\S]*?)<\/div>/gi,function(a,b,c){return""+unescape(c)+""}).replace(/]*data-ke-noscript-attr="([^"]*)"[^>]*>([\s\S]*?)<\/div>/gi,function(a,b,c){return""+unescape(c)+""}).replace(/(<[^>]*)data-ke-src="([^"]*)"([^>]*>)/gi,function(a,b,c){return a=a.replace(/(\s+(?:href|src)=")[^"]*(")/i,function(a,b,d){return b+_unescape(c)+d}),a=a.replace(/\s+data-ke-src="[^"]*"/i,"")}).replace(/(<[^>]+\s)data-ke-(on\w+="[^"]*"[^>]*>)/gi,function(a,b,c){return b+c})}),b.beforeSetHtml(function(a){return _IE&&8>=_V&&(a=a.replace(/]*>|<(select|button)[^>]*>[\s\S]*?<\/\1>/gi,function(a){var b=_getAttrList(a),c=_getCssList(b.style||"");return"none"==c.display?'
    ':a})),a.replace(/]*type="([^"]+)"[^>]*>(?:<\/embed>)?/gi,function(a){var c=_getAttrList(a);return c.src=_undef(c.src,""),c.width=_undef(c.width,0),c.height=_undef(c.height,0),_mediaImg(b.themesPath+"common/blank.gif",c)}).replace(/]*name="([^"]+)"[^>]*>(?:<\/a>)?/gi,function(a){var c=_getAttrList(a);return c.href!==undefined?a:''}).replace(/]*)>([\s\S]*?)<\/script>/gi,function(a,b,c){return'
    '+escape(c)+"
    "}).replace(/]*)>([\s\S]*?)<\/noscript>/gi,function(a,b,c){return'
    '+escape(c)+"
    "}).replace(/(<[^>]*)(href|src)="([^"]*)"([^>]*>)/gi,function(a,b,c,d,e){return a.match(/\sdata-ke-src="[^"]*"/i)?a:a=b+c+'="'+d+'" data-ke-src="'+_escape(d)+'"'+e}).replace(/(<[^>]+\s)(on\w+="[^"]*"[^>]*>)/gi,function(a,b,c){return b+"data-ke-"+c}).replace(/]*\s+border="0"[^>]*>/gi,function(a){return a.indexOf("ke-zeroborder")>=0?a:_addClassToTag(a,"ke-zeroborder")})})})}}(window),KindEditor.lang({source:"HTML代码",preview:"预览",undo:"后退(Ctrl+Z)",redo:"前进(Ctrl+Y)",cut:"剪切(Ctrl+X)",copy:"复制(Ctrl+C)",paste:"粘贴(Ctrl+V)",plainpaste:"粘贴为无格式文本",wordpaste:"从Word粘贴",selectall:"全选(Ctrl+A)",justifyleft:"左对齐",justifycenter:"居中",justifyright:"右对齐",justifyfull:"两端对齐",insertorderedlist:"编号",insertunorderedlist:"项目符号",indent:"增加缩进",outdent:"减少缩进",subscript:"下标",superscript:"上标",formatblock:"段落",fontname:"字体",fontsize:"文字大小",forecolor:"文字颜色",hilitecolor:"文字背景",bold:"粗体(Ctrl+B)",italic:"斜体(Ctrl+I)",underline:"下划线(Ctrl+U)",strikethrough:"删除线",removeformat:"删除格式",image:"图片",multiimage:"批量图片上传",flash:"Flash",media:"视音频",table:"表格",tablecell:"单元格",hr:"插入横线",emoticons:"插入表情",link:"超级链接",unlink:"取消超级链接",fullscreen:"全屏显示",about:"关于",print:"打印(Ctrl+P)",filemanager:"文件空间",code:"插入程序代码",map:"Google地图",baidumap:"百度地图",lineheight:"行距",clearhtml:"清理HTML代码",pagebreak:"插入分页符",quickformat:"一键排版",insertfile:"插入文件",template:"插入模板",anchor:"锚点",yes:"确定",no:"取消",close:"关闭",editImage:"图片属性",deleteImage:"删除图片",editFlash:"Flash属性",deleteFlash:"删除Flash",editMedia:"视音频属性",deleteMedia:"删除视音频",editLink:"超级链接属性",deleteLink:"取消超级链接",editAnchor:"锚点属性",deleteAnchor:"删除锚点",tableprop:"表格属性",tablecellprop:"单元格属性",tableinsert:"插入表格",tabledelete:"删除表格",tablecolinsertleft:"左侧插入列",tablecolinsertright:"右侧插入列",tablerowinsertabove:"上方插入行",tablerowinsertbelow:"下方插入行",tablerowmerge:"向下合并单元格",tablecolmerge:"向右合并单元格",tablerowsplit:"拆分行",tablecolsplit:"拆分列",tablecoldelete:"删除列",tablerowdelete:"删除行",noColor:"无颜色",pleaseSelectFile:"请选择文件。",invalidImg:"请输入有效的URL地址。\n只允许jpg,gif,bmp,png格式。",invalidMedia:"请输入有效的URL地址。\n只允许swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb格式。",invalidWidth:"宽度必须为数字。",invalidHeight:"高度必须为数字。",invalidBorder:"边框必须为数字。",invalidUrl:"请输入有效的URL地址。",invalidRows:"行数为必选项,只允许输入大于0的数字。",invalidCols:"列数为必选项,只允许输入大于0的数字。",invalidPadding:"边距必须为数字。",invalidSpacing:"间距必须为数字。",invalidJson:"服务器发生故障。",uploadSuccess:"上传成功。",cutError:"您的浏览器安全设置不允许使用剪切操作,请使用快捷键(Ctrl+X)来完成。",copyError:"您的浏览器安全设置不允许使用复制操作,请使用快捷键(Ctrl+C)来完成。",pasteError:"您的浏览器安全设置不允许使用粘贴操作,请使用快捷键(Ctrl+V)来完成。",ajaxLoading:"加载中,请稍候 ...",uploadLoading:"上传中,请稍候 ...",uploadError:"上传错误","plainpaste.comment":"请使用快捷键(Ctrl+V)把内容粘贴到下面的方框里。","wordpaste.comment":"请使用快捷键(Ctrl+V)把内容粘贴到下面的方框里。","code.pleaseInput":"请输入程序代码。","link.url":"URL","link.linkType":"打开类型","link.newWindow":"新窗口","link.selfWindow":"当前窗口","flash.url":"URL","flash.width":"宽度","flash.height":"高度","flash.upload":"上传","flash.viewServer":"文件空间","media.url":"URL","media.width":"宽度","media.height":"高度","media.autostart":"自动播放","media.upload":"上传","media.viewServer":"文件空间","image.remoteImage":"网络图片","image.localImage":"本地上传","image.remoteUrl":"图片地址","image.localUrl":"上传文件","image.size":"图片大小","image.width":"宽","image.height":"高","image.resetSize":"重置大小","image.align":"对齐方式","image.defaultAlign":"默认方式","image.leftAlign":"左对齐","image.rightAlign":"右对齐","image.imgTitle":"图片说明","image.upload":"浏览...","image.viewServer":"图片空间","multiimage.uploadDesc":"允许用户同时上传<%=uploadLimit%>张图片,单张图片容量不超过<%=sizeLimit%>","multiimage.startUpload":"开始上传","multiimage.clearAll":"全部清空","multiimage.insertAll":"全部插入","multiimage.queueLimitExceeded":"文件数量超过限制。","multiimage.fileExceedsSizeLimit":"文件大小超过限制。","multiimage.zeroByteFile":"无法上传空文件。","multiimage.invalidFiletype":"文件类型不正确。","multiimage.unknownError":"发生异常,无法上传。","multiimage.pending":"等待上传","multiimage.uploadError":"上传失败","filemanager.emptyFolder":"空文件夹","filemanager.moveup":"移到上一级文件夹","filemanager.viewType":"显示方式:","filemanager.viewImage":"缩略图","filemanager.listImage":"详细信息","filemanager.orderType":"排序方式:","filemanager.fileName":"名称","filemanager.fileSize":"大小","filemanager.fileType":"类型","insertfile.url":"URL","insertfile.title":"文件说明","insertfile.upload":"上传","insertfile.viewServer":"文件空间","table.cells":"单元格数","table.rows":"行数","table.cols":"列数","table.size":"大小","table.width":"宽度","table.height":"高度","table.percent":"%","table.px":"px","table.space":"边距间距","table.padding":"边距","table.spacing":"间距","table.align":"对齐方式","table.textAlign":"水平对齐","table.verticalAlign":"垂直对齐","table.alignDefault":"默认","table.alignLeft":"左对齐","table.alignCenter":"居中","table.alignRight":"右对齐","table.alignTop":"顶部","table.alignMiddle":"中部","table.alignBottom":"底部","table.alignBaseline":"基线","table.border":"边框","table.borderWidth":"边框","table.borderColor":"颜色","table.backgroundColor":"背景颜色","map.address":"地址: ","map.search":"搜索","baidumap.address":"地址: ","baidumap.search":"搜索","baidumap.insertDynamicMap":"插入动态地图","anchor.name":"锚点名称","formatblock.formatBlock":{h1:"标题 1",h2:"标题 2",h3:"标题 3",h4:"标题 4",p:"正 文"},"fontname.fontName":{SimSun:"宋体",NSimSun:"新宋体",FangSong_GB2312:"仿宋_GB2312",KaiTi_GB2312:"楷体_GB2312",SimHei:"黑体","Microsoft YaHei":"微软雅黑",Arial:"Arial","Arial Black":"Arial Black","Times New Roman":"Times New Roman","Courier New":"Courier New",Tahoma:"Tahoma",Verdana:"Verdana"},"lineheight.lineHeight":[{1:"单倍行距"},{1.5:"1.5倍行距"},{2:"2倍行距"},{2.5:"2.5倍行距"},{3:"3倍行距"}],"template.selectTemplate":"可选模板","template.replaceContent":"替换当前内容","template.fileList":{"1.html":"图片和文字","2.html":"表格","3.html":"项目编号"}},"zh-CN"),KindEditor.options.langType="zh-CN",KindEditor.plugin("anchor",function(a){var b=this,c="anchor",d=b.lang(c+".");b.plugin.anchor={edit:function(){var e=['
    ','
    ','",'',"
    ","
    "].join(""),f=b.createDialog({name:c,width:300,title:b.lang(c),body:e,yesBtn:{name:b.lang("yes"),click:function(){b.insertHtml('').hideDialog().focus()}}}),g=f.div,h=a('input[name="name"]',g),i=b.plugin.getSelectedAnchor();i&&h.val(unescape(i.attr("data-ke-name"))),h[0].focus(),h[0].select()},"delete":function(){b.plugin.getSelectedAnchor().remove()}},b.clickToolbar(c,b.plugin.anchor.edit)}),KindEditor.plugin("autoheight",function(a){function b(){var a=e.edit,b=a.doc.body;a.iframe[0].scroll="no",b.style.overflowY="hidden"}function c(){var b=e.edit,c=b.doc.body;b.iframe.height(f),e.resize(null,Math.max((a.IE?c.scrollHeight:c.offsetHeight)+76,f))}function d(){f=a.removeUnit(e.height),e.edit.afterChange(c),b(),c()}var e=this;if(e.autoHeightMode){var f;e.isCreated?d():e.afterCreate(d)}}),KindEditor.plugin("baidumap",function(a){var b=this,c="baidumap",d=b.lang(c+"."),e=a.undef(b.mapWidth,558),f=a.undef(b.mapHeight,360);b.clickToolbar(c,function(){function g(){h=p[0].contentWindow,i=a.iframeDoc(p)}var h,i,j=['
    ','
    ','
    ',d.address+' ','','',"","
    ",'
    ',' ","
    ",'
    ',"
    ",'
    ',"
    "].join(""),k=b.createDialog({name:c,width:e+42,title:b.lang(c),body:j,yesBtn:{name:b.lang("yes"),click:function(){var a=h.map,c=a.getCenter(),d=c.lng+","+c.lat,g=a.getZoom(),i=[o[0].checked?b.pluginsPath+"baidumap/index.html":"http://api.map.baidu.com/staticimage","?center="+encodeURIComponent(d),"&zoom="+encodeURIComponent(g),"&width="+e,"&height="+f,"&markers="+encodeURIComponent(d),"&markerStyles="+encodeURIComponent("l,A")].join("");o[0].checked?b.insertHtml(''):b.exec("insertimage",i),b.hideDialog().focus()}},beforeRemove:function(){n.remove(),i&&i.write(""),p.remove()}}),l=k.div,m=a('[name="address"]',l),n=a('[name="searchBtn"]',l),o=a('[name="insertDynamicMap"]',k.div),p=a('');p.bind("load",function(){p.unbind("load"),a.IE?g():setTimeout(g,0)}),a(".ke-map",l).replaceWith(p),n.click(function(){h.search(m.val())})})}),KindEditor.plugin("map",function(a){var b=this,c="map",d=b.lang(c+".");b.clickToolbar(c,function(){function e(){f=m[0].contentWindow,g=a.iframeDoc(m)}var f,g,h=['
    ','
    ',d.address+' ','','',"","
    ",'
    ',"
    "].join(""),i=b.createDialog({name:c,width:600,title:b.lang(c),body:h,yesBtn:{name:b.lang("yes"),click:function(){var a=(f.geocoder,f.map),c=a.getCenter().lat()+","+a.getCenter().lng(),d=a.getZoom(),e=a.getMapTypeId(),g="http://maps.googleapis.com/maps/api/staticmap";g+="?center="+encodeURIComponent(c),g+="&zoom="+encodeURIComponent(d),g+="&size=558x360",g+="&maptype="+encodeURIComponent(e),g+="&markers="+encodeURIComponent(c),g+="&language="+b.langType,g+="&sensor=false",b.exec("insertimage",g).hideDialog().focus()}},beforeRemove:function(){l.remove(),g&&g.write(""),m.remove()}}),j=i.div,k=a('[name="address"]',j),l=a('[name="searchBtn"]',j),m=(["",'',"",'',"","",'','
    ',""].join("\n"),a(''));m.bind("load",function(){m.unbind("load"),a.IE?e():setTimeout(e,0)}),a(".ke-map",j).replaceWith(m),l.click(function(){f.search(k.val())})})}),KindEditor.plugin("clearhtml",function(a){var b=this,c="clearhtml";b.clickToolbar(c,function(){b.focus();var c=b.html();c=c.replace(/(]*>)([\s\S]*?)(<\/script>)/gi,""),c=c.replace(/(]*>)([\s\S]*?)(<\/style>)/gi,""),c=a.formatHtml(c,{a:["href","target"],embed:["src","width","height","type","loop","autostart","quality",".width",".height","align","allowscriptaccess"],img:["src","width","height","border","alt","title",".width",".height"],table:["border"],"td,th":["rowspan","colspan"],"div,hr,br,tbody,tr,p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6":[]}),b.html(c),b.cmd.selection(!0),b.addBookmark()})}),KindEditor.plugin("code",function(a){var b=this,c="code";b.clickToolbar(c,function(){var d=b.lang(c+"."),e=['
    ','
    ','","
    ",'',"
    "].join(""),f=b.createDialog({name:c,width:450,title:b.lang(c),body:e,yesBtn:{name:b.lang("yes"),click:function(){var c=a(".ke-code-type",f.div).val(),e=g.val(),h=""===c?"":" lang-"+c,i='
    \n'+a.escape(e)+"
    ";return""===a.trim(e)?(alert(d.pleaseInput),void g[0].focus()):void b.insertHtml(i).hideDialog().focus()}}}),g=a("textarea",f.div);g[0].focus()})}),KindEditor.plugin("emoticons",function(a){var b=this,c="emoticons",d=b.emoticonsPath||b.pluginsPath+"emoticons/images/",e=void 0===b.allowPreviewEmoticons?!0:b.allowPreviewEmoticons,f=1;b.clickToolbar(c,function(){function g(c,e,f){c.mouseover(v?function(){e>r?(v.css("left",0),v.css("right","")):(v.css("left",""),v.css("right",0)),w.attr("src",d+f+".gif"),a(this).addClass("ke-on")}:function(){a(this).addClass("ke-on")}),c.mouseout(function(){a(this).removeClass("ke-on")}),c.click(function(a){b.insertHtml('').hideMenu().focus(),a.stop()})}function h(b,c){var e=document.createElement("table");c.append(e),v&&(a(e).mouseover(function(){v.show("block")}),a(e).mouseout(function(){v.hide()}),t.push(a(e))),e.className="ke-table",e.cellPadding=0,e.cellSpacing=0,e.border=0;for(var f=(b-1)*p+o,h=0;l>h;h++)for(var i=e.insertRow(h),j=0;m>j;j++){var k=a(i.insertCell(j));k.addClass("ke-cell"),g(k,j,f);var n=a('').css("background-position","-"+24*f+"px 0px").css("background-image","url("+d+"static.gif)");k.append(n),t.push(k),f++}return e}function i(){a.each(t,function(){this.unbind()})}function j(a,b){a.click(function(a){i(),y.parentNode.removeChild(y),x.remove(),y=h(b,s),k(b),f=b,a.stop()})}function k(b){x=a('
    '),s.append(x);for(var c=1;q>=c;c++){if(b!==c){var d=a('
    ['+c+"]");j(d,c),x.append(d),t.push(d)}else x.append(a("@["+c+"]"));x.append(a("@ "))}}var l=5,m=9,n=135,o=0,p=l*m,q=Math.ceil(n/p),r=Math.floor(m/2),s=a('
    '),t=[],u=b.createMenu({name:c,beforeRemove:function(){i()}});u.div.append(s);var v,w;e&&(v=a('
    ').css("right",0),w=a(''),s.append(v),v.append(w));var x,y=h(f,s);k(f)})}),KindEditor.plugin("filemanager",function(a){function b(a,b,c){return a+" ("+Math.ceil(b/1024)+"KB, "+c+")"}function c(a,c){c.is_dir?a.attr("title",c.filename):a.attr("title",b(c.filename,c.filesize,c.datetime))}var d=this,e="filemanager",f=a.undef(d.fileManagerJson,d.basePath+"php/file_manager_json.php"),g=d.pluginsPath+e+"/images/",h=d.lang(e+".");d.plugin.filemanagerDialog=function(b){function i(b,c,e){var g="path="+b+"&order="+c+"&dir="+p;t.showLoading(d.lang("ajaxLoading")),a.ajax(a.addParam(f,g+"&"+(new Date).getTime()),function(a){t.hideLoading(),e(a)})}function j(b,c,d,e){var f=a.formatUrl(c.current_url+d.filename,"absolute"),g=encodeURIComponent(c.current_dir_path+d.filename+"/");b.click(d.is_dir?function(){i(g,y.val(),e)}:d.is_photo?function(){r.call(this,f,d.filename)}:function(){r.call(this,f,d.filename)}),z.push(b)}function k(b,c){function d(){"VIEW"==x.val()?i(b.current_dir_path,y.val(),m):i(b.current_dir_path,y.val(),l)}a.each(z,function(){this.unbind()}),w.unbind(),x.unbind(),y.unbind(),b.current_dir_path&&w.click(function(){i(b.moveup_dir_path,y.val(),c)}),x.change(d),y.change(d),v.html("")}function l(b){k(b,l);var c=document.createElement("table");c.className="ke-table",c.cellPadding=0,c.cellSpacing=0,c.border=0,v.append(c);for(var d=b.file_list,e=0,f=d.length;f>e;e++){var i=d[e],m=a(c.insertRow(e));m.mouseover(function(){a(this).addClass("ke-on")}).mouseout(function(){a(this).removeClass("ke-on")});var n=g+(i.is_dir?"folder-16.gif":"file-16.gif"),o=a(''+i.filename+''),p=a(m[0].insertCell(0)).addClass("ke-cell ke-name").append(o).append(document.createTextNode(" "+i.filename));!i.is_dir||i.has_file?(m.css("cursor","pointer"),p.attr("title",i.filename),j(p,b,i,l)):p.attr("title",h.emptyFolder),a(m[0].insertCell(1)).addClass("ke-cell ke-size").html(i.is_dir?"-":Math.ceil(i.filesize/1024)+"KB"),a(m[0].insertCell(2)).addClass("ke-cell ke-datetime").html(i.datetime)}}function m(b){k(b,m);for(var d=b.file_list,e=0,f=d.length;f>e;e++){var i=d[e],l=a('
    ');v.append(l);var n=a('
    ').mouseover(function(){a(this).addClass("ke-on")}).mouseout(function(){a(this).removeClass("ke-on")});l.append(n);var o=b.current_url+i.filename,p=i.is_dir?g+"folder-64.gif":i.is_photo?o:g+"file-64.gif",q=a(''+i.filename+'');!i.is_dir||i.has_file?(n.css("cursor","pointer"),c(n,i),j(n,b,i,m)):n.attr("title",h.emptyFolder),n.append(q),l.append('
    '+i.filename+"
    ")}}var n=a.undef(b.width,650),o=a.undef(b.height,510),p=a.undef(b.dirName,""),q=a.undef(b.viewType,"VIEW").toUpperCase(),r=b.clickFn,s=['
    ','
    ','
    ',' ',''+h.moveup+"","
    ",'
    ',h.viewType+' ",h.orderType+' ","
    ",'
    ',"
    ",'
    ',"
    "].join(""),t=d.createDialog({name:e,width:n,height:o,title:d.lang(e),body:s}),u=t.div,v=a(".ke-plugin-filemanager-body",u),w=(a('[name="moveupImg"]',u),a('[name="moveupLink"]',u)),x=(a('[name="viewServer"]',u),a('[name="viewType"]',u)),y=a('[name="orderType"]',u),z=[];return x.val(q),i("",y.val(),"VIEW"==q?m:l),t}}),KindEditor.plugin("flash",function(a){var b=this,c="flash",d=b.lang(c+"."),e=a.undef(b.allowFlashUpload,!0),f=a.undef(b.allowFileManager,!1),g=a.undef(b.formatUploadUrl,!0),h=a.undef(b.extraFileUploadParams,{}),i=a.undef(b.filePostName,"imgFile"),j=a.undef(b.uploadJson,b.basePath+"php/upload_json.php");b.plugin.flash={edit:function(){var k=['
    ','
    ','",'  ','  ','','',"","
    ",'
    ','",' ',"
    ",'
    ','",' ',"
    ","
    "].join(""),l=b.createDialog({name:c,width:450,title:b.lang(c),body:k,yesBtn:{name:b.lang("yes"),click:function(){var c=a.trim(n.val()),d=p.val(),e=q.val();if("http://"==c||a.invalidUrl(c))return alert(b.lang("invalidUrl")),void n[0].focus();if(!/^\d*$/.test(d))return alert(b.lang("invalidWidth")),void p[0].focus();if(!/^\d*$/.test(e))return alert(b.lang("invalidHeight")),void q[0].focus();var f=a.mediaImg(b.themesPath+"common/blank.gif",{src:c,type:a.mediaType(".swf"),width:d,height:e,quality:"high"});b.insertHtml(f).hideDialog().focus()}}}),m=l.div,n=a('[name="url"]',m),o=a('[name="viewServer"]',m),p=a('[name="width"]',m),q=a('[name="height"]',m);if(n.val("http://"),e){var r=a.uploadbutton({button:a(".ke-upload-button",m)[0],fieldName:i,extraParams:h,url:a.addParam(j,"dir=flash"),afterUpload:function(d){if(l.hideLoading(),0===d.error){var e=d.url;g&&(e=a.formatUrl(e,"absolute")),n.val(e),b.afterUpload&&b.afterUpload.call(b,e,d,c),alert(b.lang("uploadSuccess"))}else alert(d.message)},afterError:function(a){l.hideLoading(),b.errorDialog(a)}});r.fileBox.change(function(){l.showLoading(b.lang("uploadLoading")),r.submit()})}else a(".ke-upload-button",m).hide();f?o.click(function(){b.loadPlugin("filemanager",function(){b.plugin.filemanagerDialog({viewType:"LIST",dirName:"flash",clickFn:function(c){b.dialogs.length>1&&(a('[name="url"]',m).val(c),b.afterSelectFile&&b.afterSelectFile.call(b,c),b.hideDialog())}})})}):o.hide();var s=b.plugin.getSelectedFlash();if(s){var t=a.mediaAttrs(s.attr("data-ke-tag"));n.val(t.src),p.val(a.removeUnit(s.css("width"))||t.width||0),q.val(a.removeUnit(s.css("height"))||t.height||0)}n[0].focus(),n[0].select()},"delete":function(){b.plugin.getSelectedFlash().remove(),b.addBookmark()}},b.clickToolbar(c,b.plugin.flash.edit)}),KindEditor.plugin("image",function(a){var b=this,c="image",d=a.undef(b.allowImageUpload,!0),e=a.undef(b.allowImageRemote,!0),f=a.undef(b.formatUploadUrl,!0),g=a.undef(b.allowFileManager,!1),h=a.undef(b.uploadJson,b.basePath+"php/upload_json.php"),i=a.undef(b.imageTabIndex,0),j=b.pluginsPath+"image/images/",k=a.undef(b.extraFileUploadParams,{}),l=a.undef(b.filePostName,"imgFile"),m=a.undef(b.fillDescAfterUploadImage,!1),n=b.lang(c+".");b.plugin.imageDialog=function(d){function e(a,b){D.val(a),E.val(b),J=a,K=b}var i=(d.imageUrl,a.undef(d.imageWidth,""),a.undef(d.imageHeight,""),a.undef(d.imageTitle,""),a.undef(d.imageAlign,""),a.undef(d.showRemote,!0)),o=a.undef(d.showLocal,!0),p=a.undef(d.tabIndex,0),q=d.clickFn,r="kindeditor_upload_iframe_"+(new Date).getTime(),s=[];for(var t in k)s.push('');var u,v=['
    ','
    ','",'","
    "].join(""),w=o||g?450:400,x=o&&i?300:250,y=b.createDialog({name:c,width:w,height:x,title:b.lang(c),body:v,yesBtn:{name:b.lang("yes"),click:function(){if(!y.isLoading){if(o&&i&&u&&1===u.selectedIndex||!i)return""==I.fileBox.val()?void alert(b.lang("pleaseSelectFile")):(y.showLoading(b.lang("uploadLoading")),I.submit(),void B.val(""));var c=a.trim(A.val()),d=D.val(),e=E.val(),f=G.val(),g="";return H.each(function(){return this.checked?(g=this.value,!1):void 0}),"http://"==c||a.invalidUrl(c)?(alert(b.lang("invalidUrl")),void A[0].focus()):/^\d*$/.test(d)?/^\d*$/.test(e)?void q.call(b,c,f,d,e,0,g):(alert(b.lang("invalidHeight")),void E[0].focus()):(alert(b.lang("invalidWidth")),void D[0].focus())}}},beforeRemove:function(){C.unbind(),D.unbind(),E.unbind(),F.unbind()}}),z=y.div,A=a('[name="url"]',z),B=a('[name="localUrl"]',z),C=a('[name="viewServer"]',z),D=a('.tab1 [name="width"]',z),E=a('.tab1 [name="height"]',z),F=a(".ke-refresh-btn",z),G=a('.tab1 [name="title"]',z),H=a('.tab1 [name="align"]',z);i&&o?(u=a.tabs({src:a(".tabs",z),afterSelect:function(){}}),u.add({title:n.remoteImage,panel:a(".tab1",z)}),u.add({title:n.localImage,panel:a(".tab2",z)}),u.select(p)):i?a(".tab1",z).show():o&&a(".tab2",z).show(); +var I=a.uploadbutton({button:a(".ke-upload-button",z)[0],fieldName:l,form:a(".ke-form",z),target:r,width:60,afterUpload:function(d){if(y.hideLoading(),0===d.error){var e=d.url;f&&(e=a.formatUrl(e,"absolute")),b.afterUpload&&b.afterUpload.call(b,e,d,c),m?(a(".ke-dialog-row #remoteUrl",z).val(e),a(".ke-tabs-li",z)[0].click(),a(".ke-refresh-btn",z).click()):q.call(b,e,d.title,d.width,d.height,d.border,d.align)}else alert(d.message)},afterError:function(a){y.hideLoading(),b.errorDialog(a)}});I.fileBox.change(function(){B.val(I.fileBox.val())}),g?C.click(function(){b.loadPlugin("filemanager",function(){b.plugin.filemanagerDialog({viewType:"VIEW",dirName:"image",clickFn:function(c){b.dialogs.length>1&&(a('[name="url"]',z).val(c),b.afterSelectFile&&b.afterSelectFile.call(b,c),b.hideDialog())}})})}):C.hide();var J=0,K=0;return F.click(function(){var b=a('',document).css({position:"absolute",visibility:"hidden",top:0,left:"-1000px"});b.bind("load",function(){e(b.width(),b.height()),b.remove()}),a(document.body).append(b)}),D.change(function(){J>0&&E.val(Math.round(K/J*parseInt(this.value,10)))}),E.change(function(){K>0&&D.val(Math.round(J/K*parseInt(this.value,10)))}),A.val(d.imageUrl),e(d.imageWidth,d.imageHeight),G.val(d.imageTitle),H.each(function(){return this.value===d.imageAlign?(this.checked=!0,!1):void 0}),i&&0===p&&(A[0].focus(),A[0].select()),y},b.plugin.image={edit:function(){var a=b.plugin.getSelectedImage();b.plugin.imageDialog({imageUrl:a?a.attr("data-ke-src"):"http://",imageWidth:a?a.width():"",imageHeight:a?a.height():"",imageTitle:a?a.attr("title"):"",imageAlign:a?a.attr("align"):"",showRemote:e,showLocal:d,tabIndex:a?0:i,clickFn:function(c,d,e,f,g,h){a?(a.attr("src",c),a.attr("data-ke-src",c),a.attr("width",e),a.attr("height",f),a.attr("title",d),a.attr("align",h),a.attr("alt",d)):b.exec("insertimage",c,d,e,f,g,h),setTimeout(function(){b.hideDialog().focus()},0)}})},"delete":function(){var a=b.plugin.getSelectedImage();"a"==a.parent().name&&(a=a.parent()),a.remove(),b.addBookmark()}},b.clickToolbar(c,b.plugin.image.edit)}),KindEditor.plugin("insertfile",function(a){var b=this,c="insertfile",d=a.undef(b.allowFileUpload,!0),e=a.undef(b.allowFileManager,!1),f=a.undef(b.formatUploadUrl,!0),g=a.undef(b.uploadJson,b.basePath+"php/upload_json.php"),h=a.undef(b.extraFileUploadParams,{}),i=a.undef(b.filePostName,"imgFile"),j=b.lang(c+".");b.plugin.fileDialog=function(k){var l=a.undef(k.fileUrl,"http://"),m=a.undef(k.fileTitle,""),n=k.clickFn,o=['
    ','
    ','",'  ','  ','','',"","
    ",'
    ','",'
    ',"
    ","",""].join(""),p=b.createDialog({name:c,width:450,title:b.lang(c),body:o,yesBtn:{name:b.lang("yes"),click:function(){var c=a.trim(r.val()),d=t.val();return"http://"==c||a.invalidUrl(c)?(alert(b.lang("invalidUrl")),void r[0].focus()):(""===a.trim(d)&&(d=c),void n.call(b,c,d))}}}),q=p.div,r=a('[name="url"]',q),s=a('[name="viewServer"]',q),t=a('[name="title"]',q);if(d){var u=a.uploadbutton({button:a(".ke-upload-button",q)[0],fieldName:i,url:a.addParam(g,"dir=file"),extraParams:h,afterUpload:function(d){if(p.hideLoading(),0===d.error){var e=d.url;f&&(e=a.formatUrl(e,"absolute")),r.val(e),b.afterUpload&&b.afterUpload.call(b,e,d,c),alert(b.lang("uploadSuccess"))}else alert(d.message)},afterError:function(a){p.hideLoading(),b.errorDialog(a)}});u.fileBox.change(function(){p.showLoading(b.lang("uploadLoading")),u.submit()})}else a(".ke-upload-button",q).hide();e?s.click(function(){b.loadPlugin("filemanager",function(){b.plugin.filemanagerDialog({viewType:"LIST",dirName:"file",clickFn:function(c){b.dialogs.length>1&&(a('[name="url"]',q).val(c),b.afterSelectFile&&b.afterSelectFile.call(b,c),b.hideDialog())}})})}):s.hide(),r.val(l),t.val(m),r[0].focus(),r[0].select()},b.clickToolbar(c,function(){b.plugin.fileDialog({clickFn:function(a,c){var d=''+c+"";b.insertHtml(d).hideDialog().focus()}})})}),KindEditor.plugin("lineheight",function(a){var b=this,c="lineheight",d=b.lang(c+".");b.clickToolbar(c,function(){var e="",f=b.cmd.commonNode({"*":".line-height"});f&&(e=f.css("line-height"));var g=b.createMenu({name:c,width:150});a.each(d.lineHeight,function(c,d){a.each(d,function(a,c){g.addItem({title:c,checked:e===a,click:function(){b.cmd.toggle('',{span:".line-height="+a}),b.updateState(),b.addBookmark(),b.hideMenu()}})})})})}),KindEditor.plugin("link",function(a){var b=this,c="link";b.plugin.link={edit:function(){var d=b.lang(c+"."),e='
    ',f=b.createDialog({name:c,width:450,title:b.lang(c),body:e,yesBtn:{name:b.lang("yes"),click:function(){var c=a.trim(h.val());return"http://"==c||a.invalidUrl(c)?(alert(b.lang("invalidUrl")),void h[0].focus()):void b.exec("createlink",c,i.val()).hideDialog().focus()}}}),g=f.div,h=a('input[name="url"]',g),i=a('select[name="type"]',g);h.val("http://"),i[0].options[0]=new Option(d.newWindow,"_blank"),i[0].options[1]=new Option(d.selfWindow,""),b.cmd.selection();var j=b.plugin.getSelectedLink();j&&(b.cmd.range.selectNode(j[0]),b.cmd.select(),h.val(j.attr("data-ke-src")),i.val(j.attr("target"))),h[0].focus(),h[0].select()},"delete":function(){b.exec("unlink",null)}},b.clickToolbar(c,b.plugin.link.edit)}),KindEditor.plugin("media",function(a){var b=this,c="media",d=b.lang(c+"."),e=a.undef(b.allowMediaUpload,!0),f=a.undef(b.allowFileManager,!1),g=a.undef(b.formatUploadUrl,!0),h=a.undef(b.extraFileUploadParams,{}),i=a.undef(b.filePostName,"imgFile"),j=a.undef(b.uploadJson,b.basePath+"php/upload_json.php");b.plugin.media={edit:function(){var k=['
    ','
    ','",'  ','  ','','',"","
    ",'
    ','",'',"
    ",'
    ','",'',"
    ",'
    ','",' ',"
    ","
    "].join(""),l=b.createDialog({name:c,width:450,height:230,title:b.lang(c),body:k,yesBtn:{name:b.lang("yes"),click:function(){var c=a.trim(n.val()),d=p.val(),e=q.val();if("http://"==c||a.invalidUrl(c))return alert(b.lang("invalidUrl")),void n[0].focus();if(!/^\d*$/.test(d))return alert(b.lang("invalidWidth")),void p[0].focus();if(!/^\d*$/.test(e))return alert(b.lang("invalidHeight")),void q[0].focus();var f=a.mediaImg(b.themesPath+"common/blank.gif",{src:c,type:a.mediaType(c),width:d,height:e,autostart:r[0].checked?"true":"false",loop:"true"});b.insertHtml(f).hideDialog().focus()}}}),m=l.div,n=a('[name="url"]',m),o=a('[name="viewServer"]',m),p=a('[name="width"]',m),q=a('[name="height"]',m),r=a('[name="autostart"]',m);if(n.val("http://"),e){var s=a.uploadbutton({button:a(".ke-upload-button",m)[0],fieldName:i,extraParams:h,url:a.addParam(j,"dir=media"),afterUpload:function(d){if(l.hideLoading(),0===d.error){var e=d.url;g&&(e=a.formatUrl(e,"absolute")),n.val(e),b.afterUpload&&b.afterUpload.call(b,e,d,c),alert(b.lang("uploadSuccess"))}else alert(d.message)},afterError:function(a){l.hideLoading(),b.errorDialog(a)}});s.fileBox.change(function(){l.showLoading(b.lang("uploadLoading")),s.submit()})}else a(".ke-upload-button",m).hide();f?o.click(function(){b.loadPlugin("filemanager",function(){b.plugin.filemanagerDialog({viewType:"LIST",dirName:"media",clickFn:function(c){b.dialogs.length>1&&(a('[name="url"]',m).val(c),b.afterSelectFile&&b.afterSelectFile.call(b,c),b.hideDialog())}})})}):o.hide();var t=b.plugin.getSelectedMedia();if(t){var u=a.mediaAttrs(t.attr("data-ke-tag"));n.val(u.src),p.val(a.removeUnit(t.css("width"))||u.width||0),q.val(a.removeUnit(t.css("height"))||u.height||0),r[0].checked="true"===u.autostart}n[0].focus(),n[0].select()},"delete":function(){b.plugin.getSelectedMedia().remove(),b.addBookmark()}},b.clickToolbar(c,b.plugin.media.edit)}),function(a){function b(a){this.init(a)}a.extend(b,{init:function(b){function c(b,c){a(".ke-status > div",b).hide(),a(".ke-message",b).addClass("ke-error").show().html(a.escape(c))}var d=this;b.afterError=b.afterError||function(a){alert(a)},d.options=b,d.progressbars={},d.div=a(b.container).html(['
    ','
    ','
    ','',"
    ",'
    '+b.uploadDesc+"
    ",'','',"","
    ",'
    ',"
    "].join("")),d.bodyDiv=a(".ke-swfupload-body",d.div);var e={debug:!1,upload_url:b.uploadUrl,flash_url:b.flashUrl,file_post_name:b.filePostName,button_placeholder:a(".ke-swfupload-button > input",d.div)[0],button_image_url:b.buttonImageUrl,button_width:b.buttonWidth,button_height:b.buttonHeight,button_cursor:SWFUpload.CURSOR.HAND,file_types:b.fileTypes,file_types_description:b.fileTypesDesc,file_upload_limit:b.fileUploadLimit,file_size_limit:b.fileSizeLimit,post_params:b.postParams,file_queued_handler:function(a){a.url=d.options.fileIconUrl,d.appendFile(a)},file_queue_error_handler:function(c,d){var e="";switch(d){case SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED:e=b.queueLimitExceeded;break;case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT:e=b.fileExceedsSizeLimit;break;case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:e=b.zeroByteFile;break;case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE:e=b.invalidFiletype;break;default:e=b.unknownError}a.DEBUG&&alert(e)},upload_start_handler:function(b){var c=this,d=a('div[data-id="'+b.id+'"]',c.bodyDiv);a(".ke-status > div",d).hide(),a(".ke-progressbar",d).show()},upload_progress_handler:function(a,b,c){var e=Math.round(100*b/c),f=d.progressbars[a.id];f.bar.css("width",Math.round(80*e/100)+"px"),f.percent.html(e+"%")},upload_error_handler:function(b){if(b&&b.filestatus==SWFUpload.FILE_STATUS.ERROR){var e=a('div[data-id="'+b.id+'"]',d.bodyDiv).eq(0);c(e,d.options.errorMessage)}},upload_success_handler:function(b,e){var f=a('div[data-id="'+b.id+'"]',d.bodyDiv).eq(0),g={};try{g=a.json(e)}catch(h){d.options.afterError.call(this,""+e+"")}return 0!==g.error?void c(f,a.DEBUG?g.message:d.options.errorMessage):(b.url=g.url,a(".ke-img",f).attr("src",b.url).attr("data-status",b.filestatus).data("data",g),void a(".ke-status > div",f).hide())}};d.swfu=new SWFUpload(e),a(".ke-swfupload-startupload input",d.div).click(function(){d.swfu.startUpload()})},getUrlList:function(){var b=[];return a(".ke-img",self.bodyDiv).each(function(){var c=a(this),d=c.attr("data-status");d==SWFUpload.FILE_STATUS.COMPLETE&&b.push(c.data("data"))}),b},removeFile:function(b){var c=this;c.swfu.cancelUpload(b);var d=a('div[data-id="'+b+'"]',c.bodyDiv);a(".ke-photo",d).unbind(),a(".ke-delete",d).unbind(),d.remove()},removeFiles:function(){var b=this;a(".ke-item",b.bodyDiv).each(function(){b.removeFile(a(this).attr("data-id"))})},appendFile:function(b){var c=this,d=a('
    ');c.bodyDiv.append(d);var e=a('
    ').mouseover(function(){a(this).addClass("ke-on")}).mouseout(function(){a(this).removeClass("ke-on")});d.append(e);var f=a(''+b.name+'');e.append(f),a('').appendTo(e).click(function(){c.removeFile(b.id)});var g=a('
    ').appendTo(e);a(['
    ','
    ','
    0%
    '].join("")).hide().appendTo(g),a('
    '+c.options.pendingMessage+"
    ").appendTo(g),d.append('
    '+b.name+"
    "),c.progressbars[b.id]={bar:a(".ke-progressbar-bar-inner",e),percent:a(".ke-progressbar-percent",e)}},remove:function(){this.removeFiles(),this.swfu.destroy(),this.div.html("")}}),a.swfupload=function(a,c){return new b(a,c)}}(KindEditor),KindEditor.plugin("multiimage",function(a){var b=this,c="multiimage",d=(a.undef(b.formatUploadUrl,!0),a.undef(b.uploadJson,b.basePath+"php/upload_json.php")),e=b.pluginsPath+"multiimage/images/",f=a.undef(b.imageSizeLimit,"1MB"),g=(a.undef(b.imageFileTypes,"*.jpg;*.gif;*.png"),a.undef(b.imageUploadLimit,20)),h=a.undef(b.filePostName,"imgFile"),i=b.lang(c+".");b.plugin.multiImageDialog=function(j){var k=j.clickFn,l=a.tmpl(i.uploadDesc,{uploadLimit:g,sizeLimit:f}),m=['
    ','
    ',"
    ","
    "].join(""),n=b.createDialog({name:c,width:650,height:510,title:b.lang(c),body:m,previewBtn:{name:i.insertAll,click:function(){k.call(b,p.getUrlList())}},yesBtn:{name:i.clearAll,click:function(){p.removeFiles()}},beforeRemove:function(){(!a.IE||a.V<=8)&&p.remove()}}),o=n.div,p=a.swfupload({container:a(".swfupload",o),buttonImageUrl:e+("zh-CN"==b.langType?"select-files-zh-CN.png":"select-files-en.png"),buttonWidth:"zh-CN"==b.langType?72:88,buttonHeight:23,fileIconUrl:e+"image.png",uploadDesc:l,startButtonValue:i.startUpload,uploadUrl:a.addParam(d,"dir=image"),flashUrl:e+"swfupload.swf",filePostName:h,fileTypes:"*.jpg;*.jpeg;*.gif;*.png;*.bmp",fileTypesDesc:"Image Files",fileUploadLimit:g,fileSizeLimit:f,postParams:a.undef(b.extraFileUploadParams,{}),queueLimitExceeded:i.queueLimitExceeded,fileExceedsSizeLimit:i.fileExceedsSizeLimit,zeroByteFile:i.zeroByteFile,invalidFiletype:i.invalidFiletype,unknownError:i.unknownError,pendingMessage:i.pending,errorMessage:i.uploadError,afterError:function(a){b.errorDialog(a)}});return n},b.clickToolbar(c,function(){b.plugin.multiImageDialog({clickFn:function(c){0!==c.length&&(a.each(c,function(a,c){b.afterUpload&&b.afterUpload.call(b,c.url,c,"multiimage"),b.exec("insertimage",c.url,c.title,c.width,c.height,c.border,c.align)}),setTimeout(function(){b.hideDialog().focus()},0))}})})}),function(){window.SWFUpload=function(a){this.initSWFUpload(a)},SWFUpload.prototype.initSWFUpload=function(a){try{this.customSettings={},this.settings=a,this.eventQueue=[],this.movieName="KindEditor_SWFUpload_"+SWFUpload.movieCount++,this.movieElement=null,SWFUpload.instances[this.movieName]=this,this.initSettings(),this.loadFlash(),this.displayDebugInfo()}catch(b){throw delete SWFUpload.instances[this.movieName],b}},SWFUpload.instances={},SWFUpload.movieCount=0,SWFUpload.version="2.2.0 2009-03-25",SWFUpload.QUEUE_ERROR={QUEUE_LIMIT_EXCEEDED:-100,FILE_EXCEEDS_SIZE_LIMIT:-110,ZERO_BYTE_FILE:-120,INVALID_FILETYPE:-130},SWFUpload.UPLOAD_ERROR={HTTP_ERROR:-200,MISSING_UPLOAD_URL:-210,IO_ERROR:-220,SECURITY_ERROR:-230,UPLOAD_LIMIT_EXCEEDED:-240,UPLOAD_FAILED:-250,SPECIFIED_FILE_ID_NOT_FOUND:-260,FILE_VALIDATION_FAILED:-270,FILE_CANCELLED:-280,UPLOAD_STOPPED:-290},SWFUpload.FILE_STATUS={QUEUED:-1,IN_PROGRESS:-2,ERROR:-3,COMPLETE:-4,CANCELLED:-5},SWFUpload.BUTTON_ACTION={SELECT_FILE:-100,SELECT_FILES:-110,START_UPLOAD:-120},SWFUpload.CURSOR={ARROW:-1,HAND:-2},SWFUpload.WINDOW_MODE={WINDOW:"window",TRANSPARENT:"transparent",OPAQUE:"opaque"},SWFUpload.completeURL=function(a){if("string"!=typeof a||a.match(/^https?:\/\//i)||a.match(/^\//))return a;var b=(window.location.protocol+"//"+window.location.hostname+(window.location.port?":"+window.location.port:""),window.location.pathname.lastIndexOf("/"));return path=0>=b?"/":window.location.pathname.substr(0,b)+"/",path+a},SWFUpload.prototype.initSettings=function(){this.ensureDefault=function(a,b){this.settings[a]=void 0==this.settings[a]?b:this.settings[a]},this.ensureDefault("upload_url",""),this.ensureDefault("preserve_relative_urls",!1),this.ensureDefault("file_post_name","Filedata"),this.ensureDefault("post_params",{}),this.ensureDefault("use_query_string",!1),this.ensureDefault("requeue_on_error",!1),this.ensureDefault("http_success",[]),this.ensureDefault("assume_success_timeout",0),this.ensureDefault("file_types","*.*"),this.ensureDefault("file_types_description","All Files"),this.ensureDefault("file_size_limit",0),this.ensureDefault("file_upload_limit",0),this.ensureDefault("file_queue_limit",0),this.ensureDefault("flash_url","swfupload.swf"),this.ensureDefault("prevent_swf_caching",!0),this.ensureDefault("button_image_url",""),this.ensureDefault("button_width",1),this.ensureDefault("button_height",1),this.ensureDefault("button_text",""),this.ensureDefault("button_text_style","color: #000000; font-size: 16pt;"),this.ensureDefault("button_text_top_padding",0),this.ensureDefault("button_text_left_padding",0),this.ensureDefault("button_action",SWFUpload.BUTTON_ACTION.SELECT_FILES),this.ensureDefault("button_disabled",!1),this.ensureDefault("button_placeholder_id",""),this.ensureDefault("button_placeholder",null),this.ensureDefault("button_cursor",SWFUpload.CURSOR.ARROW),this.ensureDefault("button_window_mode",SWFUpload.WINDOW_MODE.WINDOW),this.ensureDefault("debug",!1),this.settings.debug_enabled=this.settings.debug,this.settings.return_upload_start_handler=this.returnUploadStart,this.ensureDefault("swfupload_loaded_handler",null),this.ensureDefault("file_dialog_start_handler",null),this.ensureDefault("file_queued_handler",null),this.ensureDefault("file_queue_error_handler",null),this.ensureDefault("file_dialog_complete_handler",null),this.ensureDefault("upload_start_handler",null),this.ensureDefault("upload_progress_handler",null),this.ensureDefault("upload_error_handler",null),this.ensureDefault("upload_success_handler",null),this.ensureDefault("upload_complete_handler",null),this.ensureDefault("debug_handler",this.debugMessage),this.ensureDefault("custom_settings",{}),this.customSettings=this.settings.custom_settings,this.settings.prevent_swf_caching&&(this.settings.flash_url=this.settings.flash_url+(this.settings.flash_url.indexOf("?")<0?"?":"&")+"preventswfcaching="+(new Date).getTime()),this.settings.preserve_relative_urls||(this.settings.upload_url=SWFUpload.completeURL(this.settings.upload_url),this.settings.button_image_url=SWFUpload.completeURL(this.settings.button_image_url)),delete this.ensureDefault},SWFUpload.prototype.loadFlash=function(){var a,b;if(null!==document.getElementById(this.movieName))throw"ID "+this.movieName+" is already in use. The Flash Object could not be added";if(a=document.getElementById(this.settings.button_placeholder_id)||this.settings.button_placeholder,void 0==a)throw"Could not find the placeholder element: "+this.settings.button_placeholder_id;b=document.createElement("div"),b.innerHTML=this.getFlashHTML(),a.parentNode.replaceChild(b.firstChild,a),void 0==window[this.movieName]&&(window[this.movieName]=this.getMovieElement())},SWFUpload.prototype.getFlashHTML=function(){var a="";return KindEditor.IE&&KindEditor.V>8&&(a=' classid = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"'),['','','','','','','',""].join("")},SWFUpload.prototype.getFlashVars=function(){var a=this.buildParamString(),b=this.settings.http_success.join(",");return["movieName=",encodeURIComponent(this.movieName),"&uploadURL=",encodeURIComponent(this.settings.upload_url),"&useQueryString=",encodeURIComponent(this.settings.use_query_string),"&requeueOnError=",encodeURIComponent(this.settings.requeue_on_error),"&httpSuccess=",encodeURIComponent(b),"&assumeSuccessTimeout=",encodeURIComponent(this.settings.assume_success_timeout),"&params=",encodeURIComponent(a),"&filePostName=",encodeURIComponent(this.settings.file_post_name),"&fileTypes=",encodeURIComponent(this.settings.file_types),"&fileTypesDescription=",encodeURIComponent(this.settings.file_types_description),"&fileSizeLimit=",encodeURIComponent(this.settings.file_size_limit),"&fileUploadLimit=",encodeURIComponent(this.settings.file_upload_limit),"&fileQueueLimit=",encodeURIComponent(this.settings.file_queue_limit),"&debugEnabled=",encodeURIComponent(this.settings.debug_enabled),"&buttonImageURL=",encodeURIComponent(this.settings.button_image_url),"&buttonWidth=",encodeURIComponent(this.settings.button_width),"&buttonHeight=",encodeURIComponent(this.settings.button_height),"&buttonText=",encodeURIComponent(this.settings.button_text),"&buttonTextTopPadding=",encodeURIComponent(this.settings.button_text_top_padding),"&buttonTextLeftPadding=",encodeURIComponent(this.settings.button_text_left_padding),"&buttonTextStyle=",encodeURIComponent(this.settings.button_text_style),"&buttonAction=",encodeURIComponent(this.settings.button_action),"&buttonDisabled=",encodeURIComponent(this.settings.button_disabled),"&buttonCursor=",encodeURIComponent(this.settings.button_cursor)].join("")},SWFUpload.prototype.getMovieElement=function(){if(void 0==this.movieElement&&(this.movieElement=document.getElementById(this.movieName)),null===this.movieElement)throw"Could not find Flash element";return this.movieElement},SWFUpload.prototype.buildParamString=function(){var a=this.settings.post_params,b=[];if("object"==typeof a)for(var c in a)a.hasOwnProperty(c)&&b.push(encodeURIComponent(c.toString())+"="+encodeURIComponent(a[c].toString()));return b.join("&")},SWFUpload.prototype.destroy=function(){try{this.cancelUpload(null,!1);var a=null;if(a=this.getMovieElement(),a&&"unknown"==typeof a.CallFunction){for(var b in a)try{"function"==typeof a[b]&&(a[b]=null)}catch(c){}try{a.parentNode.removeChild(a)}catch(d){}}return window[this.movieName]=null,SWFUpload.instances[this.movieName]=null,delete SWFUpload.instances[this.movieName],this.movieElement=null,this.settings=null,this.customSettings=null,this.eventQueue=null,this.movieName=null,!0}catch(e){return!1}},SWFUpload.prototype.displayDebugInfo=function(){this.debug(["---SWFUpload Instance Info---\n","Version: ",SWFUpload.version,"\n","Movie Name: ",this.movieName,"\n","Settings:\n"," ","upload_url: ",this.settings.upload_url,"\n"," ","flash_url: ",this.settings.flash_url,"\n"," ","use_query_string: ",this.settings.use_query_string.toString(),"\n"," ","requeue_on_error: ",this.settings.requeue_on_error.toString(),"\n"," ","http_success: ",this.settings.http_success.join(", "),"\n"," ","assume_success_timeout: ",this.settings.assume_success_timeout,"\n"," ","file_post_name: ",this.settings.file_post_name,"\n"," ","post_params: ",this.settings.post_params.toString(),"\n"," ","file_types: ",this.settings.file_types,"\n"," ","file_types_description: ",this.settings.file_types_description,"\n"," ","file_size_limit: ",this.settings.file_size_limit,"\n"," ","file_upload_limit: ",this.settings.file_upload_limit,"\n"," ","file_queue_limit: ",this.settings.file_queue_limit,"\n"," ","debug: ",this.settings.debug.toString(),"\n"," ","prevent_swf_caching: ",this.settings.prevent_swf_caching.toString(),"\n"," ","button_placeholder_id: ",this.settings.button_placeholder_id.toString(),"\n"," ","button_placeholder: ",this.settings.button_placeholder?"Set":"Not Set","\n"," ","button_image_url: ",this.settings.button_image_url.toString(),"\n"," ","button_width: ",this.settings.button_width.toString(),"\n"," ","button_height: ",this.settings.button_height.toString(),"\n"," ","button_text: ",this.settings.button_text.toString(),"\n"," ","button_text_style: ",this.settings.button_text_style.toString(),"\n"," ","button_text_top_padding: ",this.settings.button_text_top_padding.toString(),"\n"," ","button_text_left_padding: ",this.settings.button_text_left_padding.toString(),"\n"," ","button_action: ",this.settings.button_action.toString(),"\n"," ","button_disabled: ",this.settings.button_disabled.toString(),"\n"," ","custom_settings: ",this.settings.custom_settings.toString(),"\n","Event Handlers:\n"," ","swfupload_loaded_handler assigned: ",("function"==typeof this.settings.swfupload_loaded_handler).toString(),"\n"," ","file_dialog_start_handler assigned: ",("function"==typeof this.settings.file_dialog_start_handler).toString(),"\n"," ","file_queued_handler assigned: ",("function"==typeof this.settings.file_queued_handler).toString(),"\n"," ","file_queue_error_handler assigned: ",("function"==typeof this.settings.file_queue_error_handler).toString(),"\n"," ","upload_start_handler assigned: ",("function"==typeof this.settings.upload_start_handler).toString(),"\n"," ","upload_progress_handler assigned: ",("function"==typeof this.settings.upload_progress_handler).toString(),"\n"," ","upload_error_handler assigned: ",("function"==typeof this.settings.upload_error_handler).toString(),"\n"," ","upload_success_handler assigned: ",("function"==typeof this.settings.upload_success_handler).toString(),"\n"," ","upload_complete_handler assigned: ",("function"==typeof this.settings.upload_complete_handler).toString(),"\n"," ","debug_handler assigned: ",("function"==typeof this.settings.debug_handler).toString(),"\n"].join(""))},SWFUpload.prototype.addSetting=function(a,b,c){return this.settings[a]=void 0==b?c:b},SWFUpload.prototype.getSetting=function(a){return void 0!=this.settings[a]?this.settings[a]:""},SWFUpload.prototype.callFlash=function(functionName,argumentArray){argumentArray=argumentArray||[];var movieElement=this.getMovieElement(),returnValue,returnString;try{returnString=movieElement.CallFunction(''+__flash__argumentsToXML(argumentArray,0)+""),returnValue=eval(returnString)}catch(ex){throw"Call to "+functionName+" failed"}return void 0!=returnValue&&"object"==typeof returnValue.post&&(returnValue=this.unescapeFilePostParams(returnValue)),returnValue},SWFUpload.prototype.selectFile=function(){this.callFlash("SelectFile")},SWFUpload.prototype.selectFiles=function(){this.callFlash("SelectFiles")},SWFUpload.prototype.startUpload=function(a){this.callFlash("StartUpload",[a])},SWFUpload.prototype.cancelUpload=function(a,b){b!==!1&&(b=!0),this.callFlash("CancelUpload",[a,b])},SWFUpload.prototype.stopUpload=function(){this.callFlash("StopUpload")},SWFUpload.prototype.getStats=function(){return this.callFlash("GetStats")},SWFUpload.prototype.setStats=function(a){this.callFlash("SetStats",[a])},SWFUpload.prototype.getFile=function(a){return"number"==typeof a?this.callFlash("GetFileByIndex",[a]):this.callFlash("GetFile",[a])},SWFUpload.prototype.addFileParam=function(a,b,c){return this.callFlash("AddFileParam",[a,b,c])},SWFUpload.prototype.removeFileParam=function(a,b){this.callFlash("RemoveFileParam",[a,b])},SWFUpload.prototype.setUploadURL=function(a){this.settings.upload_url=a.toString(),this.callFlash("SetUploadURL",[a])},SWFUpload.prototype.setPostParams=function(a){this.settings.post_params=a,this.callFlash("SetPostParams",[a])},SWFUpload.prototype.addPostParam=function(a,b){this.settings.post_params[a]=b,this.callFlash("SetPostParams",[this.settings.post_params])},SWFUpload.prototype.removePostParam=function(a){delete this.settings.post_params[a],this.callFlash("SetPostParams",[this.settings.post_params])},SWFUpload.prototype.setFileTypes=function(a,b){this.settings.file_types=a,this.settings.file_types_description=b,this.callFlash("SetFileTypes",[a,b])},SWFUpload.prototype.setFileSizeLimit=function(a){this.settings.file_size_limit=a,this.callFlash("SetFileSizeLimit",[a])},SWFUpload.prototype.setFileUploadLimit=function(a){this.settings.file_upload_limit=a,this.callFlash("SetFileUploadLimit",[a])},SWFUpload.prototype.setFileQueueLimit=function(a){this.settings.file_queue_limit=a,this.callFlash("SetFileQueueLimit",[a])},SWFUpload.prototype.setFilePostName=function(a){this.settings.file_post_name=a,this.callFlash("SetFilePostName",[a])},SWFUpload.prototype.setUseQueryString=function(a){this.settings.use_query_string=a,this.callFlash("SetUseQueryString",[a])},SWFUpload.prototype.setRequeueOnError=function(a){this.settings.requeue_on_error=a,this.callFlash("SetRequeueOnError",[a])},SWFUpload.prototype.setHTTPSuccess=function(a){"string"==typeof a&&(a=a.replace(" ","").split(",")),this.settings.http_success=a,this.callFlash("SetHTTPSuccess",[a])},SWFUpload.prototype.setAssumeSuccessTimeout=function(a){this.settings.assume_success_timeout=a,this.callFlash("SetAssumeSuccessTimeout",[a])},SWFUpload.prototype.setDebugEnabled=function(a){this.settings.debug_enabled=a,this.callFlash("SetDebugEnabled",[a])},SWFUpload.prototype.setButtonImageURL=function(a){void 0==a&&(a=""),this.settings.button_image_url=a,this.callFlash("SetButtonImageURL",[a])},SWFUpload.prototype.setButtonDimensions=function(a,b){this.settings.button_width=a,this.settings.button_height=b;var c=this.getMovieElement();void 0!=c&&(c.style.width=a+"px",c.style.height=b+"px"),this.callFlash("SetButtonDimensions",[a,b])},SWFUpload.prototype.setButtonText=function(a){this.settings.button_text=a,this.callFlash("SetButtonText",[a])},SWFUpload.prototype.setButtonTextPadding=function(a,b){this.settings.button_text_top_padding=b,this.settings.button_text_left_padding=a,this.callFlash("SetButtonTextPadding",[a,b])},SWFUpload.prototype.setButtonTextStyle=function(a){this.settings.button_text_style=a,this.callFlash("SetButtonTextStyle",[a])},SWFUpload.prototype.setButtonDisabled=function(a){this.settings.button_disabled=a,this.callFlash("SetButtonDisabled",[a])},SWFUpload.prototype.setButtonAction=function(a){this.settings.button_action=a,this.callFlash("SetButtonAction",[a])},SWFUpload.prototype.setButtonCursor=function(a){this.settings.button_cursor=a,this.callFlash("SetButtonCursor",[a])},SWFUpload.prototype.queueEvent=function(a,b){void 0==b?b=[]:b instanceof Array||(b=[b]);var c=this;if("function"==typeof this.settings[a])this.eventQueue.push(function(){this.settings[a].apply(this,b) +}),setTimeout(function(){c.executeNextEvent()},0);else if(null!==this.settings[a])throw"Event handler "+a+" is unknown or is not a function"},SWFUpload.prototype.executeNextEvent=function(){var a=this.eventQueue?this.eventQueue.shift():null;"function"==typeof a&&a.apply(this)},SWFUpload.prototype.unescapeFilePostParams=function(a){var b,c=/[$]([0-9a-f]{4})/i,d={};if(void 0!=a){for(var e in a.post)if(a.post.hasOwnProperty(e)){b=e;for(var f;null!==(f=c.exec(b));)b=b.replace(f[0],String.fromCharCode(parseInt("0x"+f[1],16)));d[b]=a.post[e]}a.post=d}return a},SWFUpload.prototype.testExternalInterface=function(){try{return this.callFlash("TestExternalInterface")}catch(a){return!1}},SWFUpload.prototype.flashReady=function(){var a=this.getMovieElement();return a?(this.cleanUp(a),void this.queueEvent("swfupload_loaded_handler")):void this.debug("Flash called back ready but the flash movie can't be found.")},SWFUpload.prototype.cleanUp=function(a){try{if(this.movieElement&&"unknown"==typeof a.CallFunction){this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");for(var b in a)try{"function"==typeof a[b]&&(a[b]=null)}catch(c){}}}catch(d){}window.__flash__removeCallback=function(a,b){try{a&&(a[b]=null)}catch(c){}}},SWFUpload.prototype.fileDialogStart=function(){this.queueEvent("file_dialog_start_handler")},SWFUpload.prototype.fileQueued=function(a){a=this.unescapeFilePostParams(a),this.queueEvent("file_queued_handler",a)},SWFUpload.prototype.fileQueueError=function(a,b,c){a=this.unescapeFilePostParams(a),this.queueEvent("file_queue_error_handler",[a,b,c])},SWFUpload.prototype.fileDialogComplete=function(a,b,c){this.queueEvent("file_dialog_complete_handler",[a,b,c])},SWFUpload.prototype.uploadStart=function(a){a=this.unescapeFilePostParams(a),this.queueEvent("return_upload_start_handler",a)},SWFUpload.prototype.returnUploadStart=function(a){var b;if("function"==typeof this.settings.upload_start_handler)a=this.unescapeFilePostParams(a),b=this.settings.upload_start_handler.call(this,a);else if(void 0!=this.settings.upload_start_handler)throw"upload_start_handler must be a function";void 0===b&&(b=!0),b=!!b,this.callFlash("ReturnUploadStart",[b])},SWFUpload.prototype.uploadProgress=function(a,b,c){a=this.unescapeFilePostParams(a),this.queueEvent("upload_progress_handler",[a,b,c])},SWFUpload.prototype.uploadError=function(a,b,c){a=this.unescapeFilePostParams(a),this.queueEvent("upload_error_handler",[a,b,c])},SWFUpload.prototype.uploadSuccess=function(a,b,c){a=this.unescapeFilePostParams(a),this.queueEvent("upload_success_handler",[a,b,c])},SWFUpload.prototype.uploadComplete=function(a){a=this.unescapeFilePostParams(a),this.queueEvent("upload_complete_handler",a)},SWFUpload.prototype.debug=function(a){this.queueEvent("debug_handler",a)},SWFUpload.prototype.debugMessage=function(a){if(this.settings.debug){var b,c=[];if("object"==typeof a&&"string"==typeof a.name&&"string"==typeof a.message){for(var d in a)a.hasOwnProperty(d)&&c.push(d+": "+a[d]);b=c.join("\n")||"",c=b.split("\n"),b="EXCEPTION: "+c.join("\nEXCEPTION: "),SWFUpload.Console.writeLine(b)}else SWFUpload.Console.writeLine(a)}},SWFUpload.Console={},SWFUpload.Console.writeLine=function(a){var b,c;try{b=document.getElementById("SWFUpload_Console"),b||(c=document.createElement("form"),document.getElementsByTagName("body")[0].appendChild(c),b=document.createElement("textarea"),b.id="SWFUpload_Console",b.style.fontFamily="monospace",b.setAttribute("wrap","off"),b.wrap="off",b.style.overflow="auto",b.style.width="700px",b.style.height="350px",b.style.margin="5px",c.appendChild(b)),b.value+=a+"\n",b.scrollTop=b.scrollHeight-b.clientHeight}catch(d){alert("Exception: "+d.name+" Message: "+d.message)}}}(),function(){"function"==typeof SWFUpload&&(SWFUpload.queue={},SWFUpload.prototype.initSettings=function(a){return function(){"function"==typeof a&&a.call(this),this.queueSettings={},this.queueSettings.queue_cancelled_flag=!1,this.queueSettings.queue_upload_count=0,this.queueSettings.user_upload_complete_handler=this.settings.upload_complete_handler,this.queueSettings.user_upload_start_handler=this.settings.upload_start_handler,this.settings.upload_complete_handler=SWFUpload.queue.uploadCompleteHandler,this.settings.upload_start_handler=SWFUpload.queue.uploadStartHandler,this.settings.queue_complete_handler=this.settings.queue_complete_handler||null}}(SWFUpload.prototype.initSettings),SWFUpload.prototype.startUpload=function(a){this.queueSettings.queue_cancelled_flag=!1,this.callFlash("StartUpload",[a])},SWFUpload.prototype.cancelQueue=function(){this.queueSettings.queue_cancelled_flag=!0,this.stopUpload();for(var a=this.getStats();a.files_queued>0;)this.cancelUpload(),a=this.getStats()},SWFUpload.queue.uploadStartHandler=function(a){var b;return"function"==typeof this.queueSettings.user_upload_start_handler&&(b=this.queueSettings.user_upload_start_handler.call(this,a)),b=b===!1?!1:!0,this.queueSettings.queue_cancelled_flag=!b,b},SWFUpload.queue.uploadCompleteHandler=function(a){var b,c=this.queueSettings.user_upload_complete_handler;if(a.filestatus===SWFUpload.FILE_STATUS.COMPLETE&&this.queueSettings.queue_upload_count++,b="function"==typeof c?c.call(this,a)===!1?!1:!0:a.filestatus===SWFUpload.FILE_STATUS.QUEUED?!1:!0){var d=this.getStats();d.files_queued>0&&this.queueSettings.queue_cancelled_flag===!1?this.startUpload():this.queueSettings.queue_cancelled_flag===!1?(this.queueEvent("queue_complete_handler",[this.queueSettings.queue_upload_count]),this.queueSettings.queue_upload_count=0):(this.queueSettings.queue_cancelled_flag=!1,this.queueSettings.queue_upload_count=0)}})}(),KindEditor.plugin("pagebreak",function(a){var b=this,c="pagebreak",d=a.undef(b.pagebreakHtml,'
    ');b.clickToolbar(c,function(){var c=b.cmd,e=c.range;b.focus();var f="br"==b.newlineTag||a.WEBKIT?"":'';if(b.insertHtml(d+f),""!==f){var g=a("#__kindeditor_tail_tag__",b.edit.doc);e.selectNodeContents(g[0]),g.removeAttr("id"),c.select()}})}),KindEditor.plugin("plainpaste",function(a){var b=this,c="plainpaste";b.clickToolbar(c,function(){var d=b.lang(c+"."),e='
    '+d.comment+'
    ',f=b.createDialog({name:c,width:450,title:b.lang(c),body:e,yesBtn:{name:b.lang("yes"),click:function(){var c=g.val();c=a.escape(c),c=c.replace(/ {2}/g,"  "),c="p"==b.newlineTag?c.replace(/^/,"

    ").replace(/$/,"

    ").replace(/\n/g,"

    "):c.replace(/\n/g,"
    $&"),b.insertHtml(c).hideDialog().focus()}}}),g=a("textarea",f.div);g[0].focus()})}),KindEditor.plugin("preview",function(a){var b=this,c="preview";b.clickToolbar(c,function(){var d=(b.lang(c+"."),'

    '),e=b.createDialog({name:c,width:750,title:b.lang(c),body:d}),f=a("iframe",e.div),g=a.iframeDoc(f);g.open(),g.write(b.fullHtml()),g.close(),a(g.body).css("background-color","#FFF"),f[0].contentWindow.focus()})}),KindEditor.plugin("quickformat",function(a){function b(a){for(var b=a.first();b&&b.first();)b=b.first();return b}var c=this,d="quickformat",e=a.toMap("blockquote,center,div,h1,h2,h3,h4,h5,h6,p");c.clickToolbar(d,function(){c.focus();for(var d,f=c.edit.doc,g=c.cmd.range,h=a(f.body).first(),i=[],j=[],k=g.createBookmark(!0);h;){d=h.next();var l=b(h);l&&"img"==l.name||(e[h.name]?(h.html(h.html().replace(/^(\s| | )+/gi,"")),h.css("text-indent","2em")):j.push(h),(!d||e[d.name]||e[h.name]&&!e[d.name])&&(j.length>0&&i.push(j),j=[])),h=d}a.each(i,function(b,c){var d=a('

    ',f);c[0].before(d),a.each(c,function(a,b){d.append(b)})}),g.moveToBookmark(k),c.addBookmark()})}),KindEditor.plugin("table",function(a){function b(a,b){b=b.toUpperCase(),a.css("background-color",b),a.css("color","#000000"===b?"#FFFFFF":"#000000"),a.html(b)}function c(c,d){function f(){a.each(i,function(){this.remove()}),i=[],a(document).unbind("click,mousedown",f),c.unbind("click,mousedown",f)}d.bind("click,mousedown",function(a){a.stopPropagation()}),d.click(function(){f();var d=a(this),g=d.pos(),h=a.colorpicker({x:g.x,y:g.y+d.height(),z:811214,selectedColor:a(this).html(),colors:e.colorTable,noColor:e.lang("noColor"),shadowMode:e.shadowMode,click:function(a){b(d,a),f()}});i.push(h),a(document).bind("click,mousedown",f),c.bind("click,mousedown",f)})}function d(a,b,c){for(var d=0,e=0,f=b.cells.length;f>e&&b.cells[e]!=c;e++)d+=b.cells[e].rowSpan-1;return c.cellIndex-d}var e=this,f="table",g=e.lang(f+"."),h="ke-zeroborder",i=[];e.plugin.table={prop:function(d){var i=['
    ','
    ','",g.rows+'   ',g.cols+' ',"
    ",'
    ','",g.width+'   ','   ",g.height+'   ','","
    ",'
    ','",g.padding+'   ',g.spacing+' ',"
    ",'
    ','",'","
    ",'
    ','",g.borderWidth+'   ',g.borderColor+' ',"
    ",'
    ','",'',"
    ","
    "].join(""),j=e.cmd.range.createBookmark(),k=e.createDialog({name:f,width:500,title:e.lang(f),body:i,beforeRemove:function(){w.unbind()},yesBtn:{name:e.lang("yes"),click:function(){var b=m.val(),c=n.val(),d=o.val(),f=p.val(),g=q.val(),i=r.val(),k=s.val(),l=t.val(),y=u.val(),z=v.val(),A=a(w[0]).html()||"",B=a(w[1]).html()||"";if(0==b||!/^\d+$/.test(b))return alert(e.lang("invalidRows")),void m[0].focus();if(0==c||!/^\d+$/.test(c))return alert(e.lang("invalidRows")),void n[0].focus();if(!/^\d*$/.test(d))return alert(e.lang("invalidWidth")),void o[0].focus();if(!/^\d*$/.test(f))return alert(e.lang("invalidHeight")),void p[0].focus();if(!/^\d*$/.test(k))return alert(e.lang("invalidPadding")),void s[0].focus();if(!/^\d*$/.test(l))return alert(e.lang("invalidSpacing")),void t[0].focus();if(!/^\d*$/.test(z))return alert(e.lang("invalidBorder")),void v[0].focus();if(x)return""!==d?x.width(d+g):x.css("width",""),void 0!==x[0].width&&x.removeAttr("width"),""!==f?x.height(f+i):x.css("height",""),void 0!==x[0].height&&x.removeAttr("height"),x.css("background-color",B),void 0!==x[0].bgColor&&x.removeAttr("bgColor"),""!==k?x[0].cellPadding=k:x.removeAttr("cellPadding"),""!==l?x[0].cellSpacing=l:x.removeAttr("cellSpacing"),""!==y?x[0].align=y:x.removeAttr("align"),""!==z?x.attr("border",z):x.removeAttr("border"),""===z||"0"===z?x.addClass(h):x.removeClass(h),""!==A?x.attr("borderColor",A):x.removeAttr("borderColor"),e.hideDialog().focus(),e.cmd.range.moveToBookmark(j),e.cmd.select(),void e.addBookmark();var C="";""!==d&&(C+="width:"+d+g+";"),""!==f&&(C+="height:"+f+i+";"),""!==B&&(C+="background-color:"+B+";");var D="E;E++){D+="
    ";for(var F=0;c>F;F++)D+="";D+=""}D+="
    "+(a.IE?" ":"
    ")+"
    ",a.IE||(D+="
    "),e.insertHtml(D),e.select().hideDialog().focus(),e.addBookmark()}}}),l=k.div,m=a('[name="rows"]',l).val(3),n=a('[name="cols"]',l).val(2),o=a('[name="width"]',l).val(100),p=a('[name="height"]',l),q=a('[name="widthType"]',l),r=a('[name="heightType"]',l),s=a('[name="padding"]',l).val(2),t=a('[name="spacing"]',l).val(0),u=a('[name="align"]',l),v=a('[name="border"]',l).val(1),w=a(".ke-input-color",l);c(l,w.eq(0)),c(l,w.eq(1)),b(w.eq(0),"#000000"),b(w.eq(1),""),m[0].focus(),m[0].select();var x;if(!d&&(x=e.plugin.getSelectedTable())){m.val(x[0].rows.length),n.val(x[0].rows.length>0?x[0].rows[0].cells.length:0),m.attr("disabled",!0),n.attr("disabled",!0);var y,z=x[0].style.width||x[0].width,A=x[0].style.height||x[0].height;void 0!==z&&(y=/^(\d+)((?:px|%)*)$/.exec(z))?(o.val(y[1]),q.val(y[2])):o.val(""),void 0!==A&&(y=/^(\d+)((?:px|%)*)$/.exec(A))&&(p.val(y[1]),r.val(y[2])),s.val(x[0].cellPadding||""),t.val(x[0].cellSpacing||""),u.val(x[0].align||""),v.val(void 0===x[0].border?"":x[0].border),b(w.eq(0),a.toHex(x.attr("borderColor")||"")),b(w.eq(1),a.toHex(x[0].style.backgroundColor||x[0].bgColor||"")),o[0].focus(),o[0].select()}},cellprop:function(){var d=['
    ','
    ','",g.width+'   ','   ",g.height+'   ','","
    ",'
    ','",g.textAlign+' ",g.verticalAlign+' ","
    ",'
    ','",g.borderWidth+'   ',g.borderColor+' ',"
    ",'
    ','",'',"
    ","
    "].join(""),h=e.cmd.range.createBookmark(),i=e.createDialog({name:f,width:500,title:e.lang("tablecell"),body:d,beforeRemove:function(){t.unbind()},yesBtn:{name:e.lang("yes"),click:function(){var b=k.val(),c=l.val(),d=m.val(),f=n.val(),g=(o.val(),p.val(),q.val()),i=r.val(),j=s.val(),u=a(t[0]).html()||"",w=a(t[1]).html()||"";return/^\d*$/.test(b)?/^\d*$/.test(c)?/^\d*$/.test(j)?(v.css({width:""!==b?b+d:"",height:""!==c?c+f:"","background-color":w,"text-align":g,"vertical-align":i,"border-width":j,"border-style":""!==j?"solid":"","border-color":u}),e.hideDialog().focus(),e.cmd.range.moveToBookmark(h),e.cmd.select(),void e.addBookmark()):(alert(e.lang("invalidBorder")),void s[0].focus()):(alert(e.lang("invalidHeight")),void l[0].focus()):(alert(e.lang("invalidWidth")),void k[0].focus())}}}),j=i.div,k=a('[name="width"]',j).val(100),l=a('[name="height"]',j),m=a('[name="widthType"]',j),n=a('[name="heightType"]',j),o=a('[name="padding"]',j).val(2),p=a('[name="spacing"]',j).val(0),q=a('[name="textAlign"]',j),r=a('[name="verticalAlign"]',j),s=a('[name="border"]',j).val(1),t=a(".ke-input-color",j);c(j,t.eq(0)),c(j,t.eq(1)),b(t.eq(0),"#000000"),b(t.eq(1),""),k[0].focus(),k[0].select();var u,v=e.plugin.getSelectedCell(),w=v[0].style.width||v[0].width||"",x=v[0].style.height||v[0].height||"";(u=/^(\d+)((?:px|%)*)$/.exec(w))?(k.val(u[1]),m.val(u[2])):k.val(""),(u=/^(\d+)((?:px|%)*)$/.exec(x))&&(l.val(u[1]),n.val(u[2])),q.val(v[0].style.textAlign||""),r.val(v[0].style.verticalAlign||"");var y=v[0].style.borderWidth||"";y&&(y=parseInt(y)),s.val(y),b(t.eq(0),a.toHex(v[0].style.borderColor||"")),b(t.eq(1),a.toHex(v[0].style.backgroundColor||"")),k[0].focus(),k[0].select()},insert:function(){this.prop(!0)},"delete":function(){var a=e.plugin.getSelectedTable();e.cmd.range.setStartBefore(a[0]).collapse(!0),e.cmd.select(),a.remove(),e.addBookmark()},colinsert:function(b){var c=e.plugin.getSelectedTable()[0],f=e.plugin.getSelectedRow()[0],g=e.plugin.getSelectedCell()[0],h=g.cellIndex+b;h+=c.rows[0].cells.length-f.cells.length;for(var i=0,j=c.rows.length;j>i;i++){var k=c.rows[i],l=k.insertCell(h);l.innerHTML=a.IE?"":"
    ",h=d(c,k,l)}e.cmd.range.selectNodeContents(g).collapse(!0),e.cmd.select(),e.addBookmark()},colinsertleft:function(){this.colinsert(0)},colinsertright:function(){this.colinsert(1)},rowinsert:function(b){var c=e.plugin.getSelectedTable()[0],d=e.plugin.getSelectedRow()[0],f=e.plugin.getSelectedCell()[0],g=d.rowIndex;1===b&&(g=d.rowIndex+(f.rowSpan-1)+b);for(var h=c.insertRow(g),i=0,j=d.cells.length;j>i;i++){d.cells[i].rowSpan>1&&(j-=d.cells[i].rowSpan-1);var k=h.insertCell(i);1===b&&d.cells[i].colSpan>1&&(k.colSpan=d.cells[i].colSpan),k.innerHTML=a.IE?"":"
    "}for(var l=g;l>=0;l--){var m=c.rows[l].cells;if(m.length>i){for(var n=f.cellIndex;n>=0;n--)m[n].rowSpan>1&&(m[n].rowSpan+=1);break}}e.cmd.range.selectNodeContents(f).collapse(!0),e.cmd.select(),e.addBookmark()},rowinsertabove:function(){this.rowinsert(0)},rowinsertbelow:function(){this.rowinsert(1)},rowmerge:function(){var a=e.plugin.getSelectedTable()[0],b=e.plugin.getSelectedRow()[0],c=e.plugin.getSelectedCell()[0],d=b.rowIndex,f=d+c.rowSpan,g=a.rows[f];if(!(a.rows.length<=f)){var h=c.cellIndex;if(!(g.cells.length<=h)){var i=g.cells[h];c.colSpan===i.colSpan&&(c.rowSpan+=i.rowSpan,g.deleteCell(h),e.cmd.range.selectNodeContents(c).collapse(!0),e.cmd.select(),e.addBookmark())}}},colmerge:function(){var a=(e.plugin.getSelectedTable()[0],e.plugin.getSelectedRow()[0]),b=e.plugin.getSelectedCell()[0],c=(a.rowIndex,b.cellIndex),d=c+1;if(!(a.cells.length<=d)){var f=a.cells[d];b.rowSpan===f.rowSpan&&(b.colSpan+=f.colSpan,a.deleteCell(d),e.cmd.range.selectNodeContents(b).collapse(!0),e.cmd.select(),e.addBookmark())}},rowsplit:function(){var b=e.plugin.getSelectedTable()[0],c=e.plugin.getSelectedRow()[0],f=e.plugin.getSelectedCell()[0],g=c.rowIndex;if(1!==f.rowSpan){for(var h=d(b,c,f),i=1,j=f.rowSpan;j>i;i++){var k=b.rows[g+i],l=k.insertCell(h);f.colSpan>1&&(l.colSpan=f.colSpan),l.innerHTML=a.IE?"":"
    ",h=d(b,k,l)}a(f).removeAttr("rowSpan"),e.cmd.range.selectNodeContents(f).collapse(!0),e.cmd.select(),e.addBookmark()}},colsplit:function(){var b=(e.plugin.getSelectedTable()[0],e.plugin.getSelectedRow()[0]),c=e.plugin.getSelectedCell()[0],d=c.cellIndex;if(1!==c.colSpan){for(var f=1,g=c.colSpan;g>f;f++){var h=b.insertCell(d+f);c.rowSpan>1&&(h.rowSpan=c.rowSpan),h.innerHTML=a.IE?"":"
    "}a(c).removeAttr("colSpan"),e.cmd.range.selectNodeContents(c).collapse(!0),e.cmd.select(),e.addBookmark()}},coldelete:function(){for(var b=e.plugin.getSelectedTable()[0],c=e.plugin.getSelectedRow()[0],d=e.plugin.getSelectedCell()[0],f=d.cellIndex,g=0,h=b.rows.length;h>g;g++){var i=b.rows[g],j=i.cells[f];j.colSpan>1?(j.colSpan-=1,1===j.colSpan&&a(j).removeAttr("colSpan")):i.deleteCell(f),j.rowSpan>1&&(g+=j.rowSpan-1)}0===c.cells.length?(e.cmd.range.setStartBefore(b).collapse(!0),e.cmd.select(),a(b).remove()):e.cmd.selection(!0),e.addBookmark()},rowdelete:function(){for(var b=e.plugin.getSelectedTable()[0],c=e.plugin.getSelectedRow()[0],d=e.plugin.getSelectedCell()[0],f=c.rowIndex,g=d.rowSpan-1;g>=0;g--)b.deleteRow(f+g);0===b.rows.length?(e.cmd.range.setStartBefore(b).collapse(!0),e.cmd.select(),a(b).remove()):e.cmd.selection(!0),e.addBookmark()}},e.clickToolbar(f,e.plugin.table.prop)}),KindEditor.plugin("template",function(a){function b(b){return e+b+"?ver="+encodeURIComponent(a.DEBUG?a.TIME:a.VERSION)}var c=this,d="template",e=(c.lang(d+"."),c.pluginsPath+d+"/html/");c.clickToolbar(d,function(){var e=c.lang(d+"."),f=['
    ','
    ','
    ',e.selectTemplate+"
    ",'
    ',' ","
    ",'
    ',"
    ",'',"
    "].join("");var g=c.createDialog({name:d,width:500,title:c.lang(d),body:html,yesBtn:{name:c.lang("yes"),click:function(){var b=a.iframeDoc(j);c[i[0].checked?"html":"insertHtml"](b.body.innerHTML).hideDialog().focus()}}}),h=a("select",g.div),i=a('[name="replaceFlag"]',g.div),j=a("iframe",g.div);i[0].checked=!0,j.attr("src",b(h.val())),h.change(function(){j.attr("src",b(this.value))})})}),KindEditor.plugin("wordpaste",function(a){var b=this,c="wordpaste";b.clickToolbar(c,function(){var d=b.lang(c+"."),e='
    '+d.comment+'
    ',f=b.createDialog({name:c,width:450,title:b.lang(c),body:e,yesBtn:{name:b.lang("yes"),click:function(){var c=i.body.innerHTML;c=a.clearMsWord(c,b.filterMode?b.htmlTags:a.options.htmlTags),b.insertHtml(c).hideDialog().focus()}}}),g=f.div,h=a("iframe",g),i=a.iframeDoc(h);a.IE||(i.designMode="on"),i.open(),i.write("WordPaste"),i.write(''),a.IE||i.write("
    "),i.write(""),i.close(),a.IE&&(i.body.contentEditable="true"),h[0].contentWindow.focus()})}),KindEditor.plugin("fixtoolbar",function(a){function b(){var b=a(".ke-toolbar"),c=b.pos().y;a(window).bind("scroll",function(){"fixed"==b.css("position")?document.body.scrollTop-c<0&&(b.css("position","static"),b.css("top","auto")):b.pos().y-document.body.scrollTop<0&&(b.css("position","fixed"),b.css("top",0))})}var c=this;c.fixToolBar&&(c.isCreated?b():c.afterCreate(b))}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/kindeditor-all.js b/php/kindeditor_demo/kindeditor/kindeditor-all.js new file mode 100755 index 0000000..1fcc08f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/kindeditor-all.js @@ -0,0 +1,9849 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2016 kindsoft.net +* +* @author Roddy +* @website http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +* @version 4.1.11 (2016-03-31) +*******************************************************************************/ +(function (window, undefined) { + if (window.KindEditor) { + return; + } + + +if (!window.console) { + window.console = {}; +} +if (!console.log) { + console.log = function () {}; +} +var _VERSION = '4.1.11 (2016-03-31)', + _ua = navigator.userAgent.toLowerCase(), + _IE = _ua.indexOf('msie') > -1 && _ua.indexOf('opera') == -1, + _NEWIE = _ua.indexOf('msie') == -1 && _ua.indexOf('trident') > -1, + _GECKO = _ua.indexOf('gecko') > -1 && _ua.indexOf('khtml') == -1, + _WEBKIT = _ua.indexOf('applewebkit') > -1, + _OPERA = _ua.indexOf('opera') > -1, + _MOBILE = _ua.indexOf('mobile') > -1, + _IOS = /ipad|iphone|ipod/.test(_ua), + _QUIRKS = document.compatMode != 'CSS1Compat', + _IERANGE = !window.getSelection, + _matches = /(?:msie|firefox|webkit|opera)[\/:\s](\d+)/.exec(_ua), + _V = _matches ? _matches[1] : '0', + _TIME = new Date().getTime(); +function _isArray(val) { + if (!val) { + return false; + } + return Object.prototype.toString.call(val) === '[object Array]'; +} +function _isFunction(val) { + if (!val) { + return false; + } + return Object.prototype.toString.call(val) === '[object Function]'; +} +function _inArray(val, arr) { + for (var i = 0, len = arr.length; i < len; i++) { + if (val === arr[i]) { + return i; + } + } + return -1; +} +function _each(obj, fn) { + if (_isArray(obj)) { + for (var i = 0, len = obj.length; i < len; i++) { + if (fn.call(obj[i], i, obj[i]) === false) { + break; + } + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (fn.call(obj[key], key, obj[key]) === false) { + break; + } + } + } + } +} +function _trim(str) { + return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, ''); +} +function _inString(val, str, delimiter) { + delimiter = delimiter === undefined ? ',' : delimiter; + return (delimiter + str + delimiter).indexOf(delimiter + val + delimiter) >= 0; +} +function _addUnit(val, unit) { + unit = unit || 'px'; + return val && /^-?\d+(?:\.\d+)?$/.test(val) ? val + unit : val; +} +function _removeUnit(val) { + var match; + return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0; +} +function _escape(val) { + return val.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} +function _unescape(val) { + return val.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/&/g, '&'); +} +function _toCamel(str) { + var arr = str.split('-'); + str = ''; + _each(arr, function(key, val) { + str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1) : val; + }); + return str; +} +function _toHex(val) { + function hex(d) { + var s = parseInt(d, 10).toString(16).toUpperCase(); + return s.length > 1 ? s : '0' + s; + } + return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig, + function($0, $1, $2, $3) { + return '#' + hex($1) + hex($2) + hex($3); + } + ); +} +function _toMap(val, delimiter) { + delimiter = delimiter === undefined ? ',' : delimiter; + var map = {}, arr = _isArray(val) ? val : val.split(delimiter), match; + _each(arr, function(key, val) { + if ((match = /^(\d+)\.\.(\d+)$/.exec(val))) { + for (var i = parseInt(match[1], 10); i <= parseInt(match[2], 10); i++) { + map[i.toString()] = true; + } + } else { + map[val] = true; + } + }); + return map; +} +function _toArray(obj, offset) { + return Array.prototype.slice.call(obj, offset || 0); +} +function _undef(val, defaultVal) { + return val === undefined ? defaultVal : val; +} +function _invalidUrl(url) { + return !url || /[<>"]/.test(url); +} +function _addParam(url, param) { + return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param; +} +function _extend(child, parent, proto) { + if (!proto) { + proto = parent; + parent = null; + } + var childProto; + if (parent) { + var fn = function () {}; + fn.prototype = parent.prototype; + childProto = new fn(); + _each(proto, function(key, val) { + childProto[key] = val; + }); + } else { + childProto = proto; + } + childProto.constructor = child; + child.prototype = childProto; + child.parent = parent ? parent.prototype : null; +} + +function _json(text) { + var match; + if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) { + text = match[0]; + } + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + if (/^[\],:{}\s]*$/. + test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). + replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). + replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + return eval('(' + text + ')'); + } + throw 'JSON parse error'; +} +var _round = Math.round; +var K = { + DEBUG : false, + VERSION : _VERSION, + IE : _IE, + GECKO : _GECKO, + WEBKIT : _WEBKIT, + OPERA : _OPERA, + V : _V, + TIME : _TIME, + each : _each, + isArray : _isArray, + isFunction : _isFunction, + inArray : _inArray, + inString : _inString, + trim : _trim, + addUnit : _addUnit, + removeUnit : _removeUnit, + escape : _escape, + unescape : _unescape, + toCamel : _toCamel, + toHex : _toHex, + toMap : _toMap, + toArray : _toArray, + undef : _undef, + invalidUrl : _invalidUrl, + addParam : _addParam, + extend : _extend, + json : _json +}; +var _INLINE_TAG_MAP = _toMap('a,abbr,acronym,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,img,input,ins,kbd,label,map,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'), + _BLOCK_TAG_MAP = _toMap('address,applet,blockquote,body,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,head,hr,html,iframe,ins,isindex,li,map,menu,meta,noframes,noscript,object,ol,p,pre,script,style,table,tbody,td,tfoot,th,thead,title,tr,ul'), + _SINGLE_TAG_MAP = _toMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'), + _STYLE_TAG_MAP = _toMap('b,basefont,big,del,em,font,i,s,small,span,strike,strong,sub,sup,u'), + _CONTROL_TAG_MAP = _toMap('img,table,input,textarea,button'), + _PRE_TAG_MAP = _toMap('pre,style,script'), + _NOSPLIT_TAG_MAP = _toMap('html,head,body,td,tr,table,ol,ul,li'), + _AUTOCLOSE_TAG_MAP = _toMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'), + _FILL_ATTR_MAP = _toMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'), + _VALUE_TAG_MAP = _toMap('input,button,textarea,select'); + + +function _getBasePath() { + var els = document.getElementsByTagName('script'), src; + for (var i = 0, len = els.length; i < len; i++) { + src = els[i].src || ''; + if (/kindeditor[\w\-\.]*\.js/.test(src)) { + return src.substring(0, src.lastIndexOf('/') + 1); + } + } + return ''; +} +K.basePath = _getBasePath(); +K.options = { + designMode : true, + fullscreenMode : false, + filterMode : true, + wellFormatMode : true, + shadowMode : true, + loadStyleMode : true, + basePath : K.basePath, + themesPath : K.basePath + 'themes/', + langPath : K.basePath + 'lang/', + pluginsPath : K.basePath + 'plugins/', + themeType : 'default', + langType : 'zh-CN', + urlType : '', + newlineTag : 'p', + resizeType : 2, + syncType : 'form', + pasteType : 2, + dialogAlignType : 'page', + useContextmenu : true, + fullscreenShortcut : false, + bodyClass : 'ke-content', + indentChar : '\t', + cssPath : '', + cssData : '', + minWidth : 650, + minHeight : 100, + minChangeSize : 50, + zIndex : 811213, + items : [ + 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste', + 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright', + 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript', + 'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/', + 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', + 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage', + 'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak', + 'anchor', 'link', 'unlink', '|', 'about' + ], + noDisableItems : ['source', 'fullscreen'], + colorTable : [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ], + fontSizeTable : ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'], + htmlTags : { + font : ['id', 'class', 'color', 'size', 'face', '.background-color'], + span : [ + 'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background', + '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height' + ], + div : [ + 'id', 'class', 'align', '.border', '.margin', '.padding', '.text-align', '.color', + '.background-color', '.font-size', '.font-family', '.font-weight', '.background', + '.font-style', '.text-decoration', '.vertical-align', '.margin-left' + ], + table: [ + 'id', 'class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'bordercolor', + '.padding', '.margin', '.border', 'bgcolor', '.text-align', '.color', '.background-color', + '.font-size', '.font-family', '.font-weight', '.font-style', '.text-decoration', '.background', + '.width', '.height', '.border-collapse' + ], + 'td,th': [ + 'id', 'class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor', + '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.font-weight', + '.font-style', '.text-decoration', '.vertical-align', '.background', '.border' + ], + a : ['id', 'class', 'href', 'target', 'name'], + embed : ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess', 'wmode'], + img : ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'], + 'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [ + 'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background', + '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.text-indent', '.margin-left' + ], + pre : ['id', 'class'], + hr : ['id', 'class', '.page-break-after'], + 'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del' : ['id', 'class'], + iframe : ['id', 'class', 'src', 'frameborder', 'width', 'height', '.width', '.height'] + }, + layout : '
    ' +}; + + +var _useCapture = false; + +var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222'); +var _CURSORMOVE_KEY_MAP = _toMap('33..40'); +var _CHANGE_KEY_MAP = {}; +_each(_INPUT_KEY_MAP, function(key, val) { + _CHANGE_KEY_MAP[key] = val; +}); +_each(_CURSORMOVE_KEY_MAP, function(key, val) { + _CHANGE_KEY_MAP[key] = val; +}); + +function _bindEvent(el, type, fn) { + if (el.addEventListener){ + el.addEventListener(type, fn, _useCapture); + } else if (el.attachEvent){ + el.attachEvent('on' + type, fn); + } +} +function _unbindEvent(el, type, fn) { + if (el.removeEventListener){ + el.removeEventListener(type, fn, _useCapture); + } else if (el.detachEvent){ + el.detachEvent('on' + type, fn); + } +} +var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,' + + 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,' + + 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which').split(','); + +function KEvent(el, event) { + this.init(el, event); +} +_extend(KEvent, { + init : function(el, event) { + var self = this, doc = el.ownerDocument || el.document || el; + self.event = event; + _each(_EVENT_PROPS, function(key, val) { + self[val] = event[val]; + }); + if (!self.target) { + self.target = self.srcElement || doc; + } + if (self.target.nodeType === 3) { + self.target = self.target.parentNode; + } + if (!self.relatedTarget && self.fromElement) { + self.relatedTarget = self.fromElement === self.target ? self.toElement : self.fromElement; + } + if (self.pageX == null && self.clientX != null) { + var d = doc.documentElement, body = doc.body; + self.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0); + self.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0); + } + if (!self.which && ((self.charCode || self.charCode === 0) ? self.charCode : self.keyCode)) { + self.which = self.charCode || self.keyCode; + } + if (!self.metaKey && self.ctrlKey) { + self.metaKey = self.ctrlKey; + } + if (!self.which && self.button !== undefined) { + self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : (self.button & 4 ? 2 : 0))); + } + switch (self.which) { + case 186 : + self.which = 59; + break; + case 187 : + case 107 : + case 43 : + self.which = 61; + break; + case 189 : + case 45 : + self.which = 109; + break; + case 42 : + self.which = 106; + break; + case 47 : + self.which = 111; + break; + case 78 : + self.which = 110; + break; + } + if (self.which >= 96 && self.which <= 105) { + self.which -= 48; + } + }, + preventDefault : function() { + var ev = this.event; + if (ev.preventDefault) { + ev.preventDefault(); + } else { + ev.returnValue = false; + } + }, + stopPropagation : function() { + var ev = this.event; + if (ev.stopPropagation) { + ev.stopPropagation(); + } else { + ev.cancelBubble = true; + } + }, + stop : function() { + this.preventDefault(); + this.stopPropagation(); + } +}); +var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {}; +function _getId(el) { + return el[_eventExpendo] || null; +} +function _setId(el) { + el[_eventExpendo] = ++_eventId; + return _eventId; +} +function _removeId(el) { + try { + delete el[_eventExpendo]; + } catch(e) { + if (el.removeAttribute) { + el.removeAttribute(_eventExpendo); + } + } +} +function _bind(el, type, fn) { + if (type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _bind(el, this, fn); + }); + return; + } + var id = _getId(el); + if (!id) { + id = _setId(el); + } + if (_eventData[id] === undefined) { + _eventData[id] = {}; + } + var events = _eventData[id][type]; + if (events && events.length > 0) { + _unbindEvent(el, type, events[0]); + } else { + _eventData[id][type] = []; + _eventData[id].el = el; + } + events = _eventData[id][type]; + if (events.length === 0) { + events[0] = function(e) { + var kevent = e ? new KEvent(el, e) : undefined; + _each(events, function(i, event) { + if (i > 0 && event) { + event.call(el, kevent); + } + }); + }; + } + if (_inArray(fn, events) < 0) { + events.push(fn); + } + _bindEvent(el, type, events[0]); +} +function _unbind(el, type, fn) { + if (type && type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _unbind(el, this, fn); + }); + return; + } + var id = _getId(el); + if (!id) { + return; + } + if (type === undefined) { + if (id in _eventData) { + _each(_eventData[id], function(key, events) { + if (key != 'el' && events.length > 0) { + _unbindEvent(el, key, events[0]); + } + }); + delete _eventData[id]; + _removeId(el); + } + return; + } + if (!_eventData[id]) { + return; + } + var events = _eventData[id][type]; + if (events && events.length > 0) { + if (fn === undefined) { + _unbindEvent(el, type, events[0]); + delete _eventData[id][type]; + } else { + _each(events, function(i, event) { + if (i > 0 && event === fn) { + events.splice(i, 1); + } + }); + if (events.length == 1) { + _unbindEvent(el, type, events[0]); + delete _eventData[id][type]; + } + } + var count = 0; + _each(_eventData[id], function() { + count++; + }); + if (count < 2) { + delete _eventData[id]; + _removeId(el); + } + } +} +function _fire(el, type) { + if (type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _fire(el, this); + }); + return; + } + var id = _getId(el); + if (!id) { + return; + } + var events = _eventData[id][type]; + if (_eventData[id] && events && events.length > 0) { + events[0](); + } +} +function _ctrl(el, key, fn) { + var self = this; + key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0); + _bind(el, 'keydown', function(e) { + if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) { + fn.call(el); + e.stop(); + } + }); +} +var _readyFinished = false; +function _ready(fn) { + if (_readyFinished) { + fn(KindEditor); + return; + } + var loaded = false; + function readyFunc() { + if (!loaded) { + loaded = true; + fn(KindEditor); + _readyFinished = true; + } + } + function ieReadyFunc() { + if (!loaded) { + try { + document.documentElement.doScroll('left'); + } catch(e) { + setTimeout(ieReadyFunc, 100); + return; + } + readyFunc(); + } + } + function ieReadyStateFunc() { + if (document.readyState === 'complete') { + readyFunc(); + } + } + if (document.addEventListener) { + _bind(document, 'DOMContentLoaded', readyFunc); + } else if (document.attachEvent) { + _bind(document, 'readystatechange', ieReadyStateFunc); + var toplevel = false; + try { + toplevel = window.frameElement == null; + } catch(e) {} + if (document.documentElement.doScroll && toplevel) { + ieReadyFunc(); + } + } + _bind(window, 'load', readyFunc); +} +if (window.attachEvent) { + window.attachEvent('onunload', function() { + _each(_eventData, function(key, events) { + if (events.el) { + _unbind(events.el); + } + }); + }); +} +K.ctrl = _ctrl; +K.ready = _ready; + +function _getCssList(css) { + var list = {}, + reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g, + match; + while ((match = reg.exec(css))) { + var key = _trim(match[1].toLowerCase()), + val = _trim(_toHex(match[2])); + list[key] = val; + } + return list; +} +function _getAttrList(tag) { + var list = {}, + reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g, + match; + while ((match = reg.exec(tag))) { + var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(), + val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || ''; + list[key] = val; + } + return list; +} +function _addClassToTag(tag, className) { + if (/\s+class\s*=/.test(tag)) { + tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function($0, $1, $2, $3) { + if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) { + return $2 === '' ? $1 + className + $3 : $1 + $2 + ' ' + className + $3; + } else { + return $0; + } + }); + } else { + tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">'; + } + return tag; +} +function _formatCss(css) { + var str = ''; + _each(_getCssList(css), function(key, val) { + str += key + ':' + val + ';'; + }); + return str; +} +function _formatUrl(url, mode, host, pathname) { + mode = _undef(mode, '').toLowerCase(); + if (url.substr(0, 5) != 'data:') { + url = url.replace(/([^:])\/\//g, '$1/'); + } + if (_inArray(mode, ['absolute', 'relative', 'domain']) < 0) { + return url; + } + host = host || location.protocol + '//' + location.host; + if (pathname === undefined) { + var m = location.pathname.match(/^(\/.*)\//); + pathname = m ? m[1] : ''; + } + var match; + if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) { + if (match[1] !== host) { + return url; + } + } else if (/^\w+:/.test(url)) { + return url; + } + function getRealPath(path) { + var parts = path.split('/'), paths = []; + for (var i = 0, len = parts.length; i < len; i++) { + var part = parts[i]; + if (part == '..') { + if (paths.length > 0) { + paths.pop(); + } + } else if (part !== '' && part != '.') { + paths.push(part); + } + } + return '/' + paths.join('/'); + } + if (/^\//.test(url)) { + url = host + getRealPath(url.substr(1)); + } else if (!/^\w+:\/\//.test(url)) { + url = host + getRealPath(pathname + '/' + url); + } + function getRelativePath(path, depth) { + if (url.substr(0, path.length) === path) { + var arr = []; + for (var i = 0; i < depth; i++) { + arr.push('..'); + } + var prefix = '.'; + if (arr.length > 0) { + prefix += '/' + arr.join('/'); + } + if (pathname == '/') { + prefix += '/'; + } + return prefix + url.substr(path.length); + } else { + if ((match = /^(.*)\//.exec(path))) { + return getRelativePath(match[1], ++depth); + } + } + } + if (mode === 'relative') { + url = getRelativePath(host + pathname, 0).substr(2); + } else if (mode === 'absolute') { + if (url.substr(0, host.length) === host) { + url = url.substr(host.length); + } + } + return url; +} +function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) { + if (html == null) { + html = ''; + } + urlType = urlType || ''; + wellFormatted = _undef(wellFormatted, false); + indentChar = _undef(indentChar, '\t'); + var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(','); + html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) { + return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3; + }); + html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '

    '); + html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1
    $2'); + html = html.replace(/\u200B/g, ''); + html = html.replace(/\u00A9/g, '©'); + html = html.replace(/\u00AE/g, '®'); + html = html.replace(/\u2003/g, ' '); + html = html.replace(/\u3000/g, ' '); + html = html.replace(/<[^>]+/g, function($0) { + return $0.replace(/\s+/g, ' '); + }); + var htmlTagMap = {}; + if (htmlTags) { + _each(htmlTags, function(key, val) { + var arr = key.split(','); + for (var i = 0, len = arr.length; i < len; i++) { + htmlTagMap[arr[i]] = _toMap(val); + } + }); + if (!htmlTagMap.script) { + html = html.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig, ''); + } + if (!htmlTagMap.style) { + html = html.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig, ''); + } + } + var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g; + var tagStack = []; + html = html.replace(re, function($0, $1, $2, $3, $4, $5, $6) { + var full = $0, + startNewline = $1 || '', + startSlash = $2 || '', + tagName = $3.toLowerCase(), + attr = $4 || '', + endSlash = $5 ? ' ' + $5 : '', + endNewline = $6 || ''; + if (htmlTags && !htmlTagMap[tagName]) { + return ''; + } + if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) { + endSlash = ' /'; + } + if (_INLINE_TAG_MAP[tagName]) { + if (startNewline) { + startNewline = ' '; + } + if (endNewline) { + endNewline = ' '; + } + } + if (_PRE_TAG_MAP[tagName]) { + if (startSlash) { + endNewline = '\n'; + } else { + startNewline = '\n'; + } + } + if (wellFormatted && tagName == 'br') { + endNewline = '\n'; + } + if (_BLOCK_TAG_MAP[tagName] && !_PRE_TAG_MAP[tagName]) { + if (wellFormatted) { + if (startSlash && tagStack.length > 0 && tagStack[tagStack.length - 1] === tagName) { + tagStack.pop(); + } else { + tagStack.push(tagName); + } + startNewline = '\n'; + endNewline = '\n'; + for (var i = 0, len = startSlash ? tagStack.length : tagStack.length - 1; i < len; i++) { + startNewline += indentChar; + if (!startSlash) { + endNewline += indentChar; + } + } + if (endSlash) { + tagStack.pop(); + } else if (!startSlash) { + endNewline += indentChar; + } + } else { + startNewline = endNewline = ''; + } + } + if (attr !== '') { + var attrMap = _getAttrList(full); + if (tagName === 'font') { + var fontStyleMap = {}, fontStyle = ''; + _each(attrMap, function(key, val) { + if (key === 'color') { + fontStyleMap.color = val; + delete attrMap[key]; + } + if (key === 'size') { + fontStyleMap['font-size'] = fontSizeList[parseInt(val, 10) - 1] || ''; + delete attrMap[key]; + } + if (key === 'face') { + fontStyleMap['font-family'] = val; + delete attrMap[key]; + } + if (key === 'style') { + fontStyle = val; + } + }); + if (fontStyle && !/;$/.test(fontStyle)) { + fontStyle += ';'; + } + _each(fontStyleMap, function(key, val) { + if (val === '') { + return; + } + if (/\s/.test(val)) { + val = "'" + val + "'"; + } + fontStyle += key + ':' + val + ';'; + }); + attrMap.style = fontStyle; + } + _each(attrMap, function(key, val) { + if (_FILL_ATTR_MAP[key]) { + attrMap[key] = key; + } + if (_inArray(key, ['src', 'href']) >= 0) { + attrMap[key] = _formatUrl(val, urlType); + } + if (htmlTags && key !== 'style' && !htmlTagMap[tagName]['*'] && !htmlTagMap[tagName][key] || + tagName === 'body' && key === 'contenteditable' || + /^kindeditor_\d+$/.test(key)) { + delete attrMap[key]; + } + if (key === 'style' && val !== '') { + var styleMap = _getCssList(val); + _each(styleMap, function(k, v) { + if (htmlTags && !htmlTagMap[tagName].style && !htmlTagMap[tagName]['.' + k]) { + delete styleMap[k]; + } + }); + var style = ''; + _each(styleMap, function(k, v) { + style += k + ':' + v + ';'; + }); + attrMap.style = style; + } + }); + attr = ''; + _each(attrMap, function(key, val) { + if (key === 'style' && val === '') { + return; + } + val = val.replace(/"/g, '"'); + attr += ' ' + key + '="' + val + '"'; + }); + } + if (tagName === 'font') { + tagName = 'span'; + } + return startNewline + '<' + startSlash + tagName + attr + endSlash + '>' + endNewline; + }); + html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) { + return $1 + $2.replace(/\n/g, '\n') + $3; + }); + html = html.replace(/\n\s*\n/g, '\n'); + html = html.replace(/\n/g, '\n'); + return _trim(html); +} +function _clearMsWord(html, htmlTags) { + html = html.replace(//ig, '') + .replace(//ig, '') + .replace(/]*>[\s\S]*?<\/style>/ig, '') + .replace(/]*>[\s\S]*?<\/script>/ig, '') + .replace(/]+>[\s\S]*?<\/w:[^>]+>/ig, '') + .replace(/]+>[\s\S]*?<\/o:[^>]+>/ig, '') + .replace(/[\s\S]*?<\/xml>/ig, '') + .replace(/<(?:table|td)[^>]*>/ig, function(full) { + return full.replace(/border-bottom:([#\w\s]+)/ig, 'border:$1'); + }); + return _formatHtml(html, htmlTags); +} +function _mediaType(src) { + if (/\.(rm|rmvb)(\?|$)/i.test(src)) { + return 'audio/x-pn-realaudio-plugin'; + } + if (/\.(swf|flv)(\?|$)/i.test(src)) { + return 'application/x-shockwave-flash'; + } + return 'video/x-ms-asf-plugin'; +} +function _mediaClass(type) { + if (/realaudio/i.test(type)) { + return 'ke-rm'; + } + if (/flash/i.test(type)) { + return 'ke-flash'; + } + return 'ke-media'; +} +function _mediaAttrs(srcTag) { + return _getAttrList(unescape(srcTag)); +} +function _mediaEmbed(attrs) { + var html = ' 0) { + style += 'width:' + width + 'px;'; + } + if (/\D/.test(height)) { + style += 'height:' + height + ';'; + } else if (height > 0) { + style += 'height:' + height + 'px;'; + } + var html = ''; + return html; +} + +function _tmpl(str, data) { + var fn = new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + "with(obj){p.push('" + + str.replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + "');}return p.join('');"); + return data ? fn(data) : fn; +} +K.formatUrl = _formatUrl; +K.formatHtml = _formatHtml; +K.getCssList = _getCssList; +K.getAttrList = _getAttrList; +K.mediaType = _mediaType; +K.mediaAttrs = _mediaAttrs; +K.mediaEmbed = _mediaEmbed; +K.mediaImg = _mediaImg; +K.clearMsWord = _clearMsWord; +K.tmpl = _tmpl; + + +function _contains(nodeA, nodeB) { + if (nodeA.nodeType == 9 && nodeB.nodeType != 9) { + return true; + } + while ((nodeB = nodeB.parentNode)) { + if (nodeB == nodeA) { + return true; + } + } + return false; +} +var _getSetAttrDiv = document.createElement('div'); +_getSetAttrDiv.setAttribute('className', 't'); +var _GET_SET_ATTRIBUTE = _getSetAttrDiv.className !== 't'; +function _getAttr(el, key) { + key = key.toLowerCase(); + var val = null; + if (!_GET_SET_ATTRIBUTE && el.nodeName.toLowerCase() != 'script') { + var div = el.ownerDocument.createElement('div'); + div.appendChild(el.cloneNode(false)); + var list = _getAttrList(_unescape(div.innerHTML)); + if (key in list) { + val = list[key]; + } + } else { + try { + val = el.getAttribute(key, 2); + } catch(e) { + val = el.getAttribute(key, 1); + } + } + if (key === 'style' && val !== null) { + val = _formatCss(val); + } + return val; +} +function _queryAll(expr, root) { + var exprList = expr.split(','); + if (exprList.length > 1) { + var mergedResults = []; + _each(exprList, function() { + _each(_queryAll(this, root), function() { + if (_inArray(this, mergedResults) < 0) { + mergedResults.push(this); + } + }); + }); + return mergedResults; + } + root = root || document; + function escape(str) { + if (typeof str != 'string') { + return str; + } + return str.replace(/([^\w\-])/g, '\\$1'); + } + function stripslashes(str) { + return str.replace(/\\/g, ''); + } + function cmpTag(tagA, tagB) { + return tagA === '*' || tagA.toLowerCase() === escape(tagB.toLowerCase()); + } + function byId(id, tag, root) { + var arr = [], + doc = root.ownerDocument || root, + el = doc.getElementById(stripslashes(id)); + if (el) { + if (cmpTag(tag, el.nodeName) && _contains(root, el)) { + arr.push(el); + } + } + return arr; + } + function byClass(className, tag, root) { + var doc = root.ownerDocument || root, arr = [], els, i, len, el; + if (root.getElementsByClassName) { + els = root.getElementsByClassName(stripslashes(className)); + for (i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (cmpTag(tag, el.nodeName)) { + arr.push(el); + } + } + } else if (doc.querySelectorAll) { + els = doc.querySelectorAll((root.nodeName !== '#document' ? root.nodeName + ' ' : '') + tag + '.' + className); + for (i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (_contains(root, el)) { + arr.push(el); + } + } + } else { + els = root.getElementsByTagName(tag); + className = ' ' + className + ' '; + for (i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (el.nodeType == 1) { + var cls = el.className; + if (cls && (' ' + cls + ' ').indexOf(className) > -1) { + arr.push(el); + } + } + } + } + return arr; + } + function byName(name, tag, root) { + var arr = [], doc = root.ownerDocument || root, + els = doc.getElementsByName(stripslashes(name)), el; + for (var i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (cmpTag(tag, el.nodeName) && _contains(root, el)) { + if (el.getAttribute('name') !== null) { + arr.push(el); + } + } + } + return arr; + } + function byAttr(key, val, tag, root) { + var arr = [], els = root.getElementsByTagName(tag), el; + for (var i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (el.nodeType == 1) { + if (val === null) { + if (_getAttr(el, key) !== null) { + arr.push(el); + } + } else { + if (val === escape(_getAttr(el, key))) { + arr.push(el); + } + } + } + } + return arr; + } + function select(expr, root) { + var arr = [], matches; + matches = /^((?:\\.|[^.#\s\[<>])+)/.exec(expr); + var tag = matches ? matches[1] : '*'; + if ((matches = /#((?:[\w\-]|\\.)+)$/.exec(expr))) { + arr = byId(matches[1], tag, root); + } else if ((matches = /\.((?:[\w\-]|\\.)+)$/.exec(expr))) { + arr = byClass(matches[1], tag, root); + } else if ((matches = /\[((?:[\w\-]|\\.)+)\]/.exec(expr))) { + arr = byAttr(matches[1].toLowerCase(), null, tag, root); + } else if ((matches = /\[((?:[\w\-]|\\.)+)\s*=\s*['"]?((?:\\.|[^'"]+)+)['"]?\]/.exec(expr))) { + var key = matches[1].toLowerCase(), val = matches[2]; + if (key === 'id') { + arr = byId(val, tag, root); + } else if (key === 'class') { + arr = byClass(val, tag, root); + } else if (key === 'name') { + arr = byName(val, tag, root); + } else { + arr = byAttr(key, val, tag, root); + } + } else { + var els = root.getElementsByTagName(tag), el; + for (var i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (el.nodeType == 1) { + arr.push(el); + } + } + } + return arr; + } + var parts = [], arr, re = /((?:\\.|[^\s>])+|[\s>])/g; + while ((arr = re.exec(expr))) { + if (arr[1] !== ' ') { + parts.push(arr[1]); + } + } + var results = []; + if (parts.length == 1) { + return select(parts[0], root); + } + var isChild = false, part, els, subResults, val, v, i, j, k, length, len, l; + for (i = 0, lenth = parts.length; i < lenth; i++) { + part = parts[i]; + if (part === '>') { + isChild = true; + continue; + } + if (i > 0) { + els = []; + for (j = 0, len = results.length; j < len; j++) { + val = results[j]; + subResults = select(part, val); + for (k = 0, l = subResults.length; k < l; k++) { + v = subResults[k]; + if (isChild) { + if (val === v.parentNode) { + els.push(v); + } + } else { + els.push(v); + } + } + } + results = els; + } else { + results = select(part, root); + } + if (results.length === 0) { + return []; + } + } + return results; +} +function _query(expr, root) { + var arr = _queryAll(expr, root); + return arr.length > 0 ? arr[0] : null; +} +K.query = _query; +K.queryAll = _queryAll; + + +function _get(val) { + return K(val)[0]; +} +function _getDoc(node) { + if (!node) { + return document; + } + return node.ownerDocument || node.document || node; +} +function _getWin(node) { + if (!node) { + return window; + } + var doc = _getDoc(node); + return doc.parentWindow || doc.defaultView; +} +function _setHtml(el, html) { + if (el.nodeType != 1) { + return; + } + var doc = _getDoc(el); + try { + el.innerHTML = '' + html; + var temp = doc.getElementById('__kindeditor_temp_tag__'); + temp.parentNode.removeChild(temp); + } catch(e) { + K(el).empty(); + K('@' + html, doc).each(function() { + el.appendChild(this); + }); + } +} +function _hasClass(el, cls) { + return _inString(cls, el.className, ' '); +} +function _setAttr(el, key, val) { + if (_IE && _V < 8 && key.toLowerCase() == 'class') { + key = 'className'; + } + el.setAttribute(key, '' + val); +} +function _removeAttr(el, key) { + if (_IE && _V < 8 && key.toLowerCase() == 'class') { + key = 'className'; + } + _setAttr(el, key, ''); + el.removeAttribute(key); +} +function _getNodeName(node) { + if (!node || !node.nodeName) { + return ''; + } + return node.nodeName.toLowerCase(); +} +function _computedCss(el, key) { + var self = this, win = _getWin(el), camelKey = _toCamel(key), val = ''; + if (win.getComputedStyle) { + var style = win.getComputedStyle(el, null); + val = style[camelKey] || style.getPropertyValue(key) || el.style[camelKey]; + } else if (el.currentStyle) { + val = el.currentStyle[camelKey] || el.style[camelKey]; + } + return val; +} +function _hasVal(node) { + return !!_VALUE_TAG_MAP[_getNodeName(node)]; +} +function _docElement(doc) { + doc = doc || document; + return _QUIRKS ? doc.body : doc.documentElement; +} +function _docHeight(doc) { + var el = _docElement(doc); + return Math.max(el.scrollHeight, el.clientHeight); +} +function _docWidth(doc) { + var el = _docElement(doc); + return Math.max(el.scrollWidth, el.clientWidth); +} +function _getScrollPos(doc) { + doc = doc || document; + var x, y; + if (_IE || _NEWIE || _OPERA) { + x = _docElement(doc).scrollLeft; + y = _docElement(doc).scrollTop; + } else { + x = _getWin(doc).scrollX; + y = _getWin(doc).scrollY; + } + return {x : x, y : y}; +} + +function KNode(node) { + this.init(node); +} +_extend(KNode, { + init : function(node) { + var self = this; + node = _isArray(node) ? node : [node]; + var length = 0; + for (var i = 0, len = node.length; i < len; i++) { + if (node[i]) { + self[i] = node[i].constructor === KNode ? node[i][0] : node[i]; + length++; + } + } + self.length = length; + self.doc = _getDoc(self[0]); + self.name = _getNodeName(self[0]); + self.type = self.length > 0 ? self[0].nodeType : null; + self.win = _getWin(self[0]); + }, + each : function(fn) { + var self = this; + for (var i = 0; i < self.length; i++) { + if (fn.call(self[i], i, self[i]) === false) { + return self; + } + } + return self; + }, + bind : function(type, fn) { + this.each(function() { + _bind(this, type, fn); + }); + return this; + }, + unbind : function(type, fn) { + this.each(function() { + _unbind(this, type, fn); + }); + return this; + }, + fire : function(type) { + if (this.length < 1) { + return this; + } + _fire(this[0], type); + return this; + }, + hasAttr : function(key) { + if (this.length < 1) { + return false; + } + return !!_getAttr(this[0], key); + }, + attr : function(key, val) { + var self = this; + if (key === undefined) { + return _getAttrList(self.outer()); + } + if (typeof key === 'object') { + _each(key, function(k, v) { + self.attr(k, v); + }); + return self; + } + if (val === undefined) { + val = self.length < 1 ? null : _getAttr(self[0], key); + return val === null ? '' : val; + } + self.each(function() { + _setAttr(this, key, val); + }); + return self; + }, + removeAttr : function(key) { + this.each(function() { + _removeAttr(this, key); + }); + return this; + }, + get : function(i) { + if (this.length < 1) { + return null; + } + return this[i || 0]; + }, + eq : function(i) { + if (this.length < 1) { + return null; + } + return this[i] ? new KNode(this[i]) : null; + }, + hasClass : function(cls) { + if (this.length < 1) { + return false; + } + return _hasClass(this[0], cls); + }, + addClass : function(cls) { + this.each(function() { + if (!_hasClass(this, cls)) { + this.className = _trim(this.className + ' ' + cls); + } + }); + return this; + }, + removeClass : function(cls) { + this.each(function() { + if (_hasClass(this, cls)) { + this.className = _trim(this.className.replace(new RegExp('(^|\\s)' + cls + '(\\s|$)'), ' ')); + } + }); + return this; + }, + html : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1 || self.type != 1) { + return ''; + } + return _formatHtml(self[0].innerHTML); + } + self.each(function() { + _setHtml(this, val); + }); + return self; + }, + text : function() { + var self = this; + if (self.length < 1) { + return ''; + } + return _IE ? self[0].innerText : self[0].textContent; + }, + hasVal : function() { + if (this.length < 1) { + return false; + } + return _hasVal(this[0]); + }, + val : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1) { + return ''; + } + return self.hasVal() ? self[0].value : self.attr('value'); + } else { + self.each(function() { + if (_hasVal(this)) { + this.value = val; + } else { + _setAttr(this, 'value' , val); + } + }); + return self; + } + }, + css : function(key, val) { + var self = this; + if (key === undefined) { + return _getCssList(self.attr('style')); + } + if (typeof key === 'object') { + _each(key, function(k, v) { + self.css(k, v); + }); + return self; + } + if (val === undefined) { + if (self.length < 1) { + return ''; + } + return self[0].style[_toCamel(key)] || _computedCss(self[0], key) || ''; + } + self.each(function() { + this.style[_toCamel(key)] = val; + }); + return self; + }, + width : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1) { + return 0; + } + return self[0].offsetWidth; + } + return self.css('width', _addUnit(val)); + }, + height : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1) { + return 0; + } + return self[0].offsetHeight; + } + return self.css('height', _addUnit(val)); + }, + opacity : function(val) { + this.each(function() { + if (this.style.opacity === undefined) { + this.style.filter = val == 1 ? '' : 'alpha(opacity=' + (val * 100) + ')'; + } else { + this.style.opacity = val == 1 ? '' : val; + } + }); + return this; + }, + data : function(key, val) { + var self = this; + key = 'kindeditor_data_' + key; + if (val === undefined) { + if (self.length < 1) { + return null; + } + return self[0][key]; + } + this.each(function() { + this[key] = val; + }); + return self; + }, + pos : function() { + var self = this, node = self[0], x = 0, y = 0; + if (node) { + if (node.getBoundingClientRect) { + var box = node.getBoundingClientRect(), + pos = _getScrollPos(self.doc); + x = box.left + pos.x; + y = box.top + pos.y; + } else { + while (node) { + x += node.offsetLeft; + y += node.offsetTop; + node = node.offsetParent; + } + } + } + return {x : _round(x), y : _round(y)}; + }, + clone : function(bool) { + if (this.length < 1) { + return new KNode([]); + } + return new KNode(this[0].cloneNode(bool)); + }, + append : function(expr) { + this.each(function() { + if (this.appendChild) { + this.appendChild(_get(expr)); + } + }); + return this; + }, + appendTo : function(expr) { + this.each(function() { + _get(expr).appendChild(this); + }); + return this; + }, + before : function(expr) { + this.each(function() { + this.parentNode.insertBefore(_get(expr), this); + }); + return this; + }, + after : function(expr) { + this.each(function() { + if (this.nextSibling) { + this.parentNode.insertBefore(_get(expr), this.nextSibling); + } else { + this.parentNode.appendChild(_get(expr)); + } + }); + return this; + }, + replaceWith : function(expr) { + var nodes = []; + this.each(function(i, node) { + _unbind(node); + var newNode = _get(expr); + node.parentNode.replaceChild(newNode, node); + nodes.push(newNode); + }); + return K(nodes); + }, + empty : function() { + var self = this; + self.each(function(i, node) { + var child = node.firstChild; + while (child) { + if (!node.parentNode) { + return; + } + var next = child.nextSibling; + child.parentNode.removeChild(child); + child = next; + } + }); + return self; + }, + remove : function(keepChilds) { + var self = this; + self.each(function(i, node) { + if (!node.parentNode) { + return; + } + _unbind(node); + if (keepChilds) { + var child = node.firstChild; + while (child) { + var next = child.nextSibling; + node.parentNode.insertBefore(child, node); + child = next; + } + } + node.parentNode.removeChild(node); + delete self[i]; + }); + self.length = 0; + return self; + }, + show : function(val) { + var self = this; + if (val === undefined) { + val = self._originDisplay || ''; + } + if (self.css('display') != 'none') { + return self; + } + return self.css('display', val); + }, + hide : function() { + var self = this; + if (self.length < 1) { + return self; + } + self._originDisplay = self[0].style.display; + return self.css('display', 'none'); + }, + outer : function() { + var self = this; + if (self.length < 1) { + return ''; + } + var div = self.doc.createElement('div'), html; + div.appendChild(self[0].cloneNode(true)); + html = _formatHtml(div.innerHTML); + div = null; + return html; + }, + isSingle : function() { + return !!_SINGLE_TAG_MAP[this.name]; + }, + isInline : function() { + return !!_INLINE_TAG_MAP[this.name]; + }, + isBlock : function() { + return !!_BLOCK_TAG_MAP[this.name]; + }, + isStyle : function() { + return !!_STYLE_TAG_MAP[this.name]; + }, + isControl : function() { + return !!_CONTROL_TAG_MAP[this.name]; + }, + contains : function(otherNode) { + if (this.length < 1) { + return false; + } + return _contains(this[0], _get(otherNode)); + }, + parent : function() { + if (this.length < 1) { + return null; + } + var node = this[0].parentNode; + return node ? new KNode(node) : null; + }, + children : function() { + if (this.length < 1) { + return new KNode([]); + } + var list = [], child = this[0].firstChild; + while (child) { + if (child.nodeType != 3 || _trim(child.nodeValue) !== '') { + list.push(child); + } + child = child.nextSibling; + } + return new KNode(list); + }, + first : function() { + var list = this.children(); + return list.length > 0 ? list.eq(0) : null; + }, + last : function() { + var list = this.children(); + return list.length > 0 ? list.eq(list.length - 1) : null; + }, + index : function() { + if (this.length < 1) { + return -1; + } + var i = -1, sibling = this[0]; + while (sibling) { + i++; + sibling = sibling.previousSibling; + } + return i; + }, + prev : function() { + if (this.length < 1) { + return null; + } + var node = this[0].previousSibling; + return node ? new KNode(node) : null; + }, + next : function() { + if (this.length < 1) { + return null; + } + var node = this[0].nextSibling; + return node ? new KNode(node) : null; + }, + scan : function(fn, order) { + if (this.length < 1) { + return; + } + order = (order === undefined) ? true : order; + function walk(node) { + var n = order ? node.firstChild : node.lastChild; + while (n) { + var next = order ? n.nextSibling : n.previousSibling; + if (fn(n) === false) { + return false; + } + if (walk(n) === false) { + return false; + } + n = next; + } + } + walk(this[0]); + return this; + } +}); +_each(('blur,focus,focusin,focusout,load,resize,scroll,unload,click,dblclick,' + + 'mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,' + + 'change,select,submit,keydown,keypress,keyup,error,contextmenu').split(','), function(i, type) { + KNode.prototype[type] = function(fn) { + return fn ? this.bind(type, fn) : this.fire(type); + }; +}); +var _K = K; +K = function(expr, root) { + if (expr === undefined || expr === null) { + return; + } + function newNode(node) { + if (!node[0]) { + node = []; + } + return new KNode(node); + } + if (typeof expr === 'string') { + if (root) { + root = _get(root); + } + var length = expr.length; + if (expr.charAt(0) === '@') { + expr = expr.substr(1); + } + if (expr.length !== length || /<.+>/.test(expr)) { + var doc = root ? root.ownerDocument || root : document, + div = doc.createElement('div'), list = []; + div.innerHTML = '' + expr; + for (var i = 0, len = div.childNodes.length; i < len; i++) { + var child = div.childNodes[i]; + if (child.id == '__kindeditor_temp_tag__') { + continue; + } + list.push(child); + } + return newNode(list); + } + return newNode(_queryAll(expr, root)); + } + if (expr && expr.constructor === KNode) { + return expr; + } + if (expr.toArray) { + expr = expr.toArray(); + } + if (_isArray(expr)) { + return newNode(expr); + } + return newNode(_toArray(arguments)); +}; +_each(_K, function(key, val) { + K[key] = val; +}); +K.NodeClass = KNode; +window.KindEditor = K; + + +var _START_TO_START = 0, + _START_TO_END = 1, + _END_TO_END = 2, + _END_TO_START = 3, + _BOOKMARK_ID = 0; +function _updateCollapsed(range) { + range.collapsed = (range.startContainer === range.endContainer && range.startOffset === range.endOffset); + return range; +} +function _copyAndDelete(range, isCopy, isDelete) { + var doc = range.doc, nodeList = []; + function splitTextNode(node, startOffset, endOffset) { + var length = node.nodeValue.length, centerNode; + if (isCopy) { + var cloneNode = node.cloneNode(true); + if (startOffset > 0) { + centerNode = cloneNode.splitText(startOffset); + } else { + centerNode = cloneNode; + } + if (endOffset < length) { + centerNode.splitText(endOffset - startOffset); + } + } + if (isDelete) { + var center = node; + if (startOffset > 0) { + center = node.splitText(startOffset); + range.setStart(node, startOffset); + } + if (endOffset < length) { + var right = center.splitText(endOffset - startOffset); + range.setEnd(right, 0); + } + nodeList.push(center); + } + return centerNode; + } + function removeNodes() { + if (isDelete) { + range.up().collapse(true); + } + for (var i = 0, len = nodeList.length; i < len; i++) { + var node = nodeList[i]; + if (node.parentNode) { + node.parentNode.removeChild(node); + } + } + } + var copyRange = range.cloneRange().down(); + var start = -1, incStart = -1, incEnd = -1, end = -1, + ancestor = range.commonAncestor(), frag = doc.createDocumentFragment(); + if (ancestor.nodeType == 3) { + var textNode = splitTextNode(ancestor, range.startOffset, range.endOffset); + if (isCopy) { + frag.appendChild(textNode); + } + removeNodes(); + return isCopy ? frag : range; + } + function extractNodes(parent, frag) { + var node = parent.firstChild, nextNode; + while (node) { + var testRange = new KRange(doc).selectNode(node); + start = testRange.compareBoundaryPoints(_START_TO_END, range); + if (start >= 0 && incStart <= 0) { + incStart = testRange.compareBoundaryPoints(_START_TO_START, range); + } + if (incStart >= 0 && incEnd <= 0) { + incEnd = testRange.compareBoundaryPoints(_END_TO_END, range); + } + if (incEnd >= 0 && end <= 0) { + end = testRange.compareBoundaryPoints(_END_TO_START, range); + } + if (end >= 0) { + return false; + } + nextNode = node.nextSibling; + if (start > 0) { + if (node.nodeType == 1) { + if (incStart >= 0 && incEnd <= 0) { + if (isCopy) { + frag.appendChild(node.cloneNode(true)); + } + if (isDelete) { + nodeList.push(node); + } + } else { + var childFlag; + if (isCopy) { + childFlag = node.cloneNode(false); + frag.appendChild(childFlag); + } + if (extractNodes(node, childFlag) === false) { + return false; + } + } + } else if (node.nodeType == 3) { + var textNode; + if (node == copyRange.startContainer) { + textNode = splitTextNode(node, copyRange.startOffset, node.nodeValue.length); + } else if (node == copyRange.endContainer) { + textNode = splitTextNode(node, 0, copyRange.endOffset); + } else { + textNode = splitTextNode(node, 0, node.nodeValue.length); + } + if (isCopy) { + try { + frag.appendChild(textNode); + } catch(e) {} + } + } + } + node = nextNode; + } + } + extractNodes(ancestor, frag); + if (isDelete) { + range.up().collapse(true); + } + for (var i = 0, len = nodeList.length; i < len; i++) { + var node = nodeList[i]; + if (node.parentNode) { + node.parentNode.removeChild(node); + } + } + return isCopy ? frag : range; +} +function _moveToElementText(range, el) { + var node = el; + while (node) { + var knode = K(node); + if (knode.name == 'marquee' || knode.name == 'select') { + return; + } + node = node.parentNode; + } + try { + range.moveToElementText(el); + } catch(e) {} +} +function _getStartEnd(rng, isStart) { + var doc = rng.parentElement().ownerDocument, + pointRange = rng.duplicate(); + pointRange.collapse(isStart); + var parent = pointRange.parentElement(), + nodes = parent.childNodes; + if (nodes.length === 0) { + return {node: parent.parentNode, offset: K(parent).index()}; + } + var startNode = doc, startPos = 0, cmp = -1; + var testRange = rng.duplicate(); + _moveToElementText(testRange, parent); + for (var i = 0, len = nodes.length; i < len; i++) { + var node = nodes[i]; + cmp = testRange.compareEndPoints('StartToStart', pointRange); + if (cmp === 0) { + return {node: node.parentNode, offset: i}; + } + if (node.nodeType == 1) { + var nodeRange = rng.duplicate(), dummy, knode = K(node), newNode = node; + if (knode.isControl()) { + dummy = doc.createElement('span'); + knode.after(dummy); + newNode = dummy; + startPos += knode.text().replace(/\r\n|\n|\r/g, '').length; + } + _moveToElementText(nodeRange, newNode); + testRange.setEndPoint('StartToEnd', nodeRange); + if (cmp > 0) { + startPos += nodeRange.text.replace(/\r\n|\n|\r/g, '').length; + } else { + startPos = 0; + } + if (dummy) { + K(dummy).remove(); + } + } else if (node.nodeType == 3) { + testRange.moveStart('character', node.nodeValue.length); + startPos += node.nodeValue.length; + } + if (cmp < 0) { + startNode = node; + } + } + if (cmp < 0 && startNode.nodeType == 1) { + return {node: parent, offset: K(parent.lastChild).index() + 1}; + } + if (cmp > 0) { + while (startNode.nextSibling && startNode.nodeType == 1) { + startNode = startNode.nextSibling; + } + } + testRange = rng.duplicate(); + _moveToElementText(testRange, parent); + testRange.setEndPoint('StartToEnd', pointRange); + startPos -= testRange.text.replace(/\r\n|\n|\r/g, '').length; + if (cmp > 0 && startNode.nodeType == 3) { + var prevNode = startNode.previousSibling; + while (prevNode && prevNode.nodeType == 3) { + startPos -= prevNode.nodeValue.length; + prevNode = prevNode.previousSibling; + } + } + return {node: startNode, offset: startPos}; +} +function _getEndRange(node, offset) { + var doc = node.ownerDocument || node, + range = doc.body.createTextRange(); + if (doc == node) { + range.collapse(true); + return range; + } + if (node.nodeType == 1 && node.childNodes.length > 0) { + var children = node.childNodes, isStart, child; + if (offset === 0) { + child = children[0]; + isStart = true; + } else { + child = children[offset - 1]; + isStart = false; + } + if (!child) { + return range; + } + if (K(child).name === 'head') { + if (offset === 1) { + isStart = true; + } + if (offset === 2) { + isStart = false; + } + range.collapse(isStart); + return range; + } + if (child.nodeType == 1) { + var kchild = K(child), span; + if (kchild.isControl()) { + span = doc.createElement('span'); + if (isStart) { + kchild.before(span); + } else { + kchild.after(span); + } + child = span; + } + _moveToElementText(range, child); + range.collapse(isStart); + if (span) { + K(span).remove(); + } + return range; + } + node = child; + offset = isStart ? 0 : child.nodeValue.length; + } + var dummy = doc.createElement('span'); + K(node).before(dummy); + _moveToElementText(range, dummy); + range.moveStart('character', offset); + K(dummy).remove(); + return range; +} +function _toRange(rng) { + var doc, range; + function tr2td(start) { + if (K(start.node).name == 'tr') { + start.node = start.node.cells[start.offset]; + start.offset = 0; + } + } + if (_IERANGE) { + if (rng.item) { + doc = _getDoc(rng.item(0)); + range = new KRange(doc); + range.selectNode(rng.item(0)); + return range; + } + doc = rng.parentElement().ownerDocument; + var start = _getStartEnd(rng, true), + end = _getStartEnd(rng, false); + tr2td(start); + tr2td(end); + range = new KRange(doc); + range.setStart(start.node, start.offset); + range.setEnd(end.node, end.offset); + return range; + } + var startContainer = rng.startContainer; + doc = startContainer.ownerDocument || startContainer; + range = new KRange(doc); + range.setStart(startContainer, rng.startOffset); + range.setEnd(rng.endContainer, rng.endOffset); + return range; +} + +function KRange(doc) { + this.init(doc); +} +_extend(KRange, { + init : function(doc) { + var self = this; + self.startContainer = doc; + self.startOffset = 0; + self.endContainer = doc; + self.endOffset = 0; + self.collapsed = true; + self.doc = doc; + }, + commonAncestor : function() { + function getParents(node) { + var parents = []; + while (node) { + parents.push(node); + node = node.parentNode; + } + return parents; + } + var parentsA = getParents(this.startContainer), + parentsB = getParents(this.endContainer), + i = 0, lenA = parentsA.length, lenB = parentsB.length, parentA, parentB; + while (++i) { + parentA = parentsA[lenA - i]; + parentB = parentsB[lenB - i]; + if (!parentA || !parentB || parentA !== parentB) { + break; + } + } + return parentsA[lenA - i + 1]; + }, + setStart : function(node, offset) { + var self = this, doc = self.doc; + self.startContainer = node; + self.startOffset = offset; + if (self.endContainer === doc) { + self.endContainer = node; + self.endOffset = offset; + } + return _updateCollapsed(this); + }, + setEnd : function(node, offset) { + var self = this, doc = self.doc; + self.endContainer = node; + self.endOffset = offset; + if (self.startContainer === doc) { + self.startContainer = node; + self.startOffset = offset; + } + return _updateCollapsed(this); + }, + setStartBefore : function(node) { + return this.setStart(node.parentNode || this.doc, K(node).index()); + }, + setStartAfter : function(node) { + return this.setStart(node.parentNode || this.doc, K(node).index() + 1); + }, + setEndBefore : function(node) { + return this.setEnd(node.parentNode || this.doc, K(node).index()); + }, + setEndAfter : function(node) { + return this.setEnd(node.parentNode || this.doc, K(node).index() + 1); + }, + selectNode : function(node) { + return this.setStartBefore(node).setEndAfter(node); + }, + selectNodeContents : function(node) { + var knode = K(node); + if (knode.type == 3 || knode.isSingle()) { + return this.selectNode(node); + } + var children = knode.children(); + if (children.length > 0) { + return this.setStartBefore(children[0]).setEndAfter(children[children.length - 1]); + } + return this.setStart(node, 0).setEnd(node, 0); + }, + collapse : function(toStart) { + if (toStart) { + return this.setEnd(this.startContainer, this.startOffset); + } + return this.setStart(this.endContainer, this.endOffset); + }, + compareBoundaryPoints : function(how, range) { + var rangeA = this.get(), rangeB = range.get(); + if (_IERANGE) { + var arr = {}; + arr[_START_TO_START] = 'StartToStart'; + arr[_START_TO_END] = 'EndToStart'; + arr[_END_TO_END] = 'EndToEnd'; + arr[_END_TO_START] = 'StartToEnd'; + var cmp = rangeA.compareEndPoints(arr[how], rangeB); + if (cmp !== 0) { + return cmp; + } + var nodeA, nodeB, nodeC, posA, posB; + if (how === _START_TO_START || how === _END_TO_START) { + nodeA = this.startContainer; + posA = this.startOffset; + } + if (how === _START_TO_END || how === _END_TO_END) { + nodeA = this.endContainer; + posA = this.endOffset; + } + if (how === _START_TO_START || how === _START_TO_END) { + nodeB = range.startContainer; + posB = range.startOffset; + } + if (how === _END_TO_END || how === _END_TO_START) { + nodeB = range.endContainer; + posB = range.endOffset; + } + if (nodeA === nodeB) { + var diff = posA - posB; + return diff > 0 ? 1 : (diff < 0 ? -1 : 0); + } + nodeC = nodeB; + while (nodeC && nodeC.parentNode !== nodeA) { + nodeC = nodeC.parentNode; + } + if (nodeC) { + return K(nodeC).index() >= posA ? -1 : 1; + } + nodeC = nodeA; + while (nodeC && nodeC.parentNode !== nodeB) { + nodeC = nodeC.parentNode; + } + if (nodeC) { + return K(nodeC).index() >= posB ? 1 : -1; + } + nodeC = K(nodeB).next(); + if (nodeC && nodeC.contains(nodeA)) { + return 1; + } + nodeC = K(nodeA).next(); + if (nodeC && nodeC.contains(nodeB)) { + return -1; + } + } else { + return rangeA.compareBoundaryPoints(how, rangeB); + } + }, + cloneRange : function() { + return new KRange(this.doc).setStart(this.startContainer, this.startOffset).setEnd(this.endContainer, this.endOffset); + }, + toString : function() { + var rng = this.get(), str = _IERANGE ? rng.text : rng.toString(); + return str.replace(/\r\n|\n|\r/g, ''); + }, + cloneContents : function() { + return _copyAndDelete(this, true, false); + }, + deleteContents : function() { + return _copyAndDelete(this, false, true); + }, + extractContents : function() { + return _copyAndDelete(this, true, true); + }, + insertNode : function(node) { + var self = this, + sc = self.startContainer, so = self.startOffset, + ec = self.endContainer, eo = self.endOffset, + firstChild, lastChild, c, nodeCount = 1; + if (node.nodeName.toLowerCase() === '#document-fragment') { + firstChild = node.firstChild; + lastChild = node.lastChild; + nodeCount = node.childNodes.length; + } + if (sc.nodeType == 1) { + c = sc.childNodes[so]; + if (c) { + sc.insertBefore(node, c); + if (sc === ec) { + eo += nodeCount; + } + } else { + sc.appendChild(node); + } + } else if (sc.nodeType == 3) { + if (so === 0) { + sc.parentNode.insertBefore(node, sc); + if (sc.parentNode === ec) { + eo += nodeCount; + } + } else if (so >= sc.nodeValue.length) { + if (sc.nextSibling) { + sc.parentNode.insertBefore(node, sc.nextSibling); + } else { + sc.parentNode.appendChild(node); + } + } else { + if (so > 0) { + c = sc.splitText(so); + } else { + c = sc; + } + sc.parentNode.insertBefore(node, c); + if (sc === ec) { + ec = c; + eo -= so; + } + } + } + if (firstChild) { + self.setStartBefore(firstChild).setEndAfter(lastChild); + } else { + self.selectNode(node); + } + if (self.compareBoundaryPoints(_END_TO_END, self.cloneRange().setEnd(ec, eo)) >= 1) { + return self; + } + return self.setEnd(ec, eo); + }, + surroundContents : function(node) { + node.appendChild(this.extractContents()); + return this.insertNode(node).selectNode(node); + }, + isControl : function() { + var self = this, + sc = self.startContainer, so = self.startOffset, + ec = self.endContainer, eo = self.endOffset, rng; + return sc.nodeType == 1 && sc === ec && so + 1 === eo && K(sc.childNodes[so]).isControl(); + }, + get : function(hasControlRange) { + var self = this, doc = self.doc, node, rng; + if (!_IERANGE) { + rng = doc.createRange(); + try { + rng.setStart(self.startContainer, self.startOffset); + rng.setEnd(self.endContainer, self.endOffset); + } catch (e) {} + return rng; + } + if (hasControlRange && self.isControl()) { + rng = doc.body.createControlRange(); + rng.addElement(self.startContainer.childNodes[self.startOffset]); + return rng; + } + var range = self.cloneRange().down(); + rng = doc.body.createTextRange(); + rng.setEndPoint('StartToStart', _getEndRange(range.startContainer, range.startOffset)); + rng.setEndPoint('EndToStart', _getEndRange(range.endContainer, range.endOffset)); + return rng; + }, + html : function() { + return K(this.cloneContents()).outer(); + }, + down : function() { + var self = this; + function downPos(node, pos, isStart) { + if (node.nodeType != 1) { + return; + } + var children = K(node).children(); + if (children.length === 0) { + return; + } + var left, right, child, offset; + if (pos > 0) { + left = children.eq(pos - 1); + } + if (pos < children.length) { + right = children.eq(pos); + } + if (left && left.type == 3) { + child = left[0]; + offset = child.nodeValue.length; + } + if (right && right.type == 3) { + child = right[0]; + offset = 0; + } + if (!child) { + return; + } + if (isStart) { + self.setStart(child, offset); + } else { + self.setEnd(child, offset); + } + } + downPos(self.startContainer, self.startOffset, true); + downPos(self.endContainer, self.endOffset, false); + return self; + }, + up : function() { + var self = this; + function upPos(node, pos, isStart) { + if (node.nodeType != 3) { + return; + } + if (pos === 0) { + if (isStart) { + self.setStartBefore(node); + } else { + self.setEndBefore(node); + } + } else if (pos == node.nodeValue.length) { + if (isStart) { + self.setStartAfter(node); + } else { + self.setEndAfter(node); + } + } + } + upPos(self.startContainer, self.startOffset, true); + upPos(self.endContainer, self.endOffset, false); + return self; + }, + enlarge : function(toBlock) { + var self = this; + self.up(); + function enlargePos(node, pos, isStart) { + var knode = K(node), parent; + if (knode.type == 3 || _NOSPLIT_TAG_MAP[knode.name] || !toBlock && knode.isBlock()) { + return; + } + if (pos === 0) { + while (!knode.prev()) { + parent = knode.parent(); + if (!parent || _NOSPLIT_TAG_MAP[parent.name] || !toBlock && parent.isBlock()) { + break; + } + knode = parent; + } + if (isStart) { + self.setStartBefore(knode[0]); + } else { + self.setEndBefore(knode[0]); + } + } else if (pos == knode.children().length) { + while (!knode.next()) { + parent = knode.parent(); + if (!parent || _NOSPLIT_TAG_MAP[parent.name] || !toBlock && parent.isBlock()) { + break; + } + knode = parent; + } + if (isStart) { + self.setStartAfter(knode[0]); + } else { + self.setEndAfter(knode[0]); + } + } + } + enlargePos(self.startContainer, self.startOffset, true); + enlargePos(self.endContainer, self.endOffset, false); + return self; + }, + shrink : function() { + var self = this, child, collapsed = self.collapsed; + while (self.startContainer.nodeType == 1 && (child = self.startContainer.childNodes[self.startOffset]) && child.nodeType == 1 && !K(child).isSingle()) { + self.setStart(child, 0); + } + if (collapsed) { + return self.collapse(collapsed); + } + while (self.endContainer.nodeType == 1 && self.endOffset > 0 && (child = self.endContainer.childNodes[self.endOffset - 1]) && child.nodeType == 1 && !K(child).isSingle()) { + self.setEnd(child, child.childNodes.length); + } + return self; + }, + createBookmark : function(serialize) { + var self = this, doc = self.doc, endNode, + startNode = K('', doc)[0]; + startNode.id = '__kindeditor_bookmark_start_' + (_BOOKMARK_ID++) + '__'; + if (!self.collapsed) { + endNode = startNode.cloneNode(true); + endNode.id = '__kindeditor_bookmark_end_' + (_BOOKMARK_ID++) + '__'; + } + if (endNode) { + self.cloneRange().collapse(false).insertNode(endNode).setEndBefore(endNode); + } + self.insertNode(startNode).setStartAfter(startNode); + return { + start : serialize ? '#' + startNode.id : startNode, + end : endNode ? (serialize ? '#' + endNode.id : endNode) : null + }; + }, + moveToBookmark : function(bookmark) { + var self = this, doc = self.doc, + start = K(bookmark.start, doc), end = bookmark.end ? K(bookmark.end, doc) : null; + if (!start || start.length < 1) { + return self; + } + self.setStartBefore(start[0]); + start.remove(); + if (end && end.length > 0) { + self.setEndBefore(end[0]); + end.remove(); + } else { + self.collapse(true); + } + return self; + }, + dump : function() { + console.log('--------------------'); + console.log(this.startContainer.nodeType == 3 ? this.startContainer.nodeValue : this.startContainer, this.startOffset); + console.log(this.endContainer.nodeType == 3 ? this.endContainer.nodeValue : this.endContainer, this.endOffset); + } +}); +function _range(mixed) { + if (!mixed.nodeName) { + return mixed.constructor === KRange ? mixed : _toRange(mixed); + } + return new KRange(mixed); +} +K.RangeClass = KRange; +K.range = _range; +K.START_TO_START = _START_TO_START; +K.START_TO_END = _START_TO_END; +K.END_TO_END = _END_TO_END; +K.END_TO_START = _END_TO_START; + + +function _nativeCommand(doc, key, val) { + try { + doc.execCommand(key, false, val); + } catch(e) {} +} +function _nativeCommandValue(doc, key) { + var val = ''; + try { + val = doc.queryCommandValue(key); + } catch (e) {} + if (typeof val !== 'string') { + val = ''; + } + return val; +} +function _getSel(doc) { + var win = _getWin(doc); + return _IERANGE ? doc.selection : win.getSelection(); +} +function _getRng(doc) { + var sel = _getSel(doc), rng; + try { + if (sel.rangeCount > 0) { + rng = sel.getRangeAt(0); + } else { + rng = sel.createRange(); + } + } catch(e) {} + if (_IERANGE && (!rng || (!rng.item && rng.parentElement().ownerDocument !== doc))) { + return null; + } + return rng; +} +function _singleKeyMap(map) { + var newMap = {}, arr, v; + _each(map, function(key, val) { + arr = key.split(','); + for (var i = 0, len = arr.length; i < len; i++) { + v = arr[i]; + newMap[v] = val; + } + }); + return newMap; +} +function _hasAttrOrCss(knode, map) { + return _hasAttrOrCssByKey(knode, map, '*') || _hasAttrOrCssByKey(knode, map); +} +function _hasAttrOrCssByKey(knode, map, mapKey) { + mapKey = mapKey || knode.name; + if (knode.type !== 1) { + return false; + } + var newMap = _singleKeyMap(map); + if (!newMap[mapKey]) { + return false; + } + var arr = newMap[mapKey].split(','); + for (var i = 0, len = arr.length; i < len; i++) { + var key = arr[i]; + if (key === '*') { + return true; + } + var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key); + var method = match[1] ? 'css' : 'attr'; + key = match[2]; + var val = match[3] || ''; + if (val === '' && knode[method](key) !== '') { + return true; + } + if (val !== '' && knode[method](key) === val) { + return true; + } + } + return false; +} +function _removeAttrOrCss(knode, map) { + if (knode.type != 1) { + return; + } + _removeAttrOrCssByKey(knode, map, '*'); + _removeAttrOrCssByKey(knode, map); +} +function _removeAttrOrCssByKey(knode, map, mapKey) { + mapKey = mapKey || knode.name; + if (knode.type !== 1) { + return; + } + var newMap = _singleKeyMap(map); + if (!newMap[mapKey]) { + return; + } + var arr = newMap[mapKey].split(','), allFlag = false; + for (var i = 0, len = arr.length; i < len; i++) { + var key = arr[i]; + if (key === '*') { + allFlag = true; + break; + } + var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key); + key = match[2]; + if (match[1]) { + key = _toCamel(key); + if (knode[0].style[key]) { + knode[0].style[key] = ''; + } + } else { + knode.removeAttr(key); + } + } + if (allFlag) { + knode.remove(true); + } +} +function _getInnerNode(knode) { + var inner = knode; + while (inner.first()) { + inner = inner.first(); + } + return inner; +} +function _isEmptyNode(knode) { + if (knode.type != 1 || knode.isSingle()) { + return false; + } + return knode.html().replace(/<[^>]+>/g, '') === ''; +} +function _mergeWrapper(a, b) { + a = a.clone(true); + var lastA = _getInnerNode(a), childA = a, merged = false; + while (b) { + while (childA) { + if (childA.name === b.name) { + _mergeAttrs(childA, b.attr(), b.css()); + merged = true; + } + childA = childA.first(); + } + if (!merged) { + lastA.append(b.clone(false)); + } + merged = false; + b = b.first(); + } + return a; +} +function _wrapNode(knode, wrapper) { + wrapper = wrapper.clone(true); + if (knode.type == 3) { + _getInnerNode(wrapper).append(knode.clone(false)); + knode.replaceWith(wrapper); + return wrapper; + } + var nodeWrapper = knode, child; + while ((child = knode.first()) && child.children().length == 1) { + knode = child; + } + child = knode.first(); + var frag = knode.doc.createDocumentFragment(); + while (child) { + frag.appendChild(child[0]); + child = child.next(); + } + wrapper = _mergeWrapper(nodeWrapper, wrapper); + if (frag.firstChild) { + _getInnerNode(wrapper).append(frag); + } + nodeWrapper.replaceWith(wrapper); + return wrapper; +} +function _mergeAttrs(knode, attrs, styles) { + _each(attrs, function(key, val) { + if (key !== 'style') { + knode.attr(key, val); + } + }); + _each(styles, function(key, val) { + knode.css(key, val); + }); +} +function _inPreElement(knode) { + while (knode && knode.name != 'body') { + if (_PRE_TAG_MAP[knode.name] || knode.name == 'div' && knode.hasClass('ke-script')) { + return true; + } + knode = knode.parent(); + } + return false; +} +function KCmd(range) { + this.init(range); +} +_extend(KCmd, { + init : function(range) { + var self = this, doc = range.doc; + self.doc = doc; + self.win = _getWin(doc); + self.sel = _getSel(doc); + self.range = range; + }, + selection : function(forceReset) { + var self = this, doc = self.doc, rng = _getRng(doc); + self.sel = _getSel(doc); + if (rng) { + self.range = _range(rng); + if (K(self.range.startContainer).name == 'html') { + self.range.selectNodeContents(doc.body).collapse(false); + } + return self; + } + if (forceReset) { + self.range.selectNodeContents(doc.body).collapse(false); + } + return self; + }, + select : function(hasDummy) { + hasDummy = _undef(hasDummy, true); + var self = this, sel = self.sel, range = self.range.cloneRange().shrink(), + sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset, + doc = _getDoc(sc), win = self.win, rng, hasU200b = false; + if (hasDummy && sc.nodeType == 1 && range.collapsed) { + if (_IERANGE) { + var dummy = K(' ', doc); + range.insertNode(dummy[0]); + rng = doc.body.createTextRange(); + try { + rng.moveToElementText(dummy[0]); + } catch(ex) {} + rng.collapse(false); + rng.select(); + dummy.remove(); + win.focus(); + return self; + } + if (_WEBKIT) { + var children = sc.childNodes; + if (K(sc).isInline() || so > 0 && K(children[so - 1]).isInline() || children[so] && K(children[so]).isInline()) { + range.insertNode(doc.createTextNode('\u200B')); + hasU200b = true; + } + } + } + if (_IERANGE) { + try { + rng = range.get(true); + rng.select(); + } catch(e) {} + } else { + if (hasU200b) { + range.collapse(false); + } + rng = range.get(true); + sel.removeAllRanges(); + sel.addRange(rng); + if (doc !== document) { + var pos = K(rng.endContainer).pos(); + win.scrollTo(pos.x, pos.y); + } + } + win.focus(); + return self; + }, + wrap : function(val) { + var self = this, doc = self.doc, range = self.range, wrapper; + wrapper = K(val, doc); + if (range.collapsed) { + range.shrink(); + range.insertNode(wrapper[0]).selectNodeContents(wrapper[0]); + return self; + } + if (wrapper.isBlock()) { + var copyWrapper = wrapper.clone(true), child = copyWrapper; + while (child.first()) { + child = child.first(); + } + child.append(range.extractContents()); + range.insertNode(copyWrapper[0]).selectNode(copyWrapper[0]); + return self; + } + range.enlarge(); + var bookmark = range.createBookmark(), ancestor = range.commonAncestor(), isStart = false; + K(ancestor).scan(function(node) { + if (!isStart && node == bookmark.start) { + isStart = true; + return; + } + if (isStart) { + if (node == bookmark.end) { + return false; + } + var knode = K(node); + if (_inPreElement(knode)) { + return; + } + if (knode.type == 3 && _trim(node.nodeValue).length > 0) { + var parent; + while ((parent = knode.parent()) && parent.isStyle() && parent.children().length == 1) { + knode = parent; + } + _wrapNode(knode, wrapper); + } + } + }); + range.moveToBookmark(bookmark); + return self; + }, + split : function(isStart, map) { + var range = this.range, doc = range.doc; + var tempRange = range.cloneRange().collapse(isStart); + var node = tempRange.startContainer, pos = tempRange.startOffset, + parent = node.nodeType == 3 ? node.parentNode : node, + needSplit = false, knode; + while (parent && parent.parentNode) { + knode = K(parent); + if (map) { + if (!knode.isStyle()) { + break; + } + if (!_hasAttrOrCss(knode, map)) { + break; + } + } else { + if (_NOSPLIT_TAG_MAP[knode.name]) { + break; + } + } + needSplit = true; + parent = parent.parentNode; + } + if (needSplit) { + var dummy = doc.createElement('span'); + range.cloneRange().collapse(!isStart).insertNode(dummy); + if (isStart) { + tempRange.setStartBefore(parent.firstChild).setEnd(node, pos); + } else { + tempRange.setStart(node, pos).setEndAfter(parent.lastChild); + } + var frag = tempRange.extractContents(), + first = frag.firstChild, last = frag.lastChild; + if (isStart) { + tempRange.insertNode(frag); + range.setStartAfter(last).setEndBefore(dummy); + } else { + parent.appendChild(frag); + range.setStartBefore(dummy).setEndBefore(first); + } + var dummyParent = dummy.parentNode; + if (dummyParent == range.endContainer) { + var prev = K(dummy).prev(), next = K(dummy).next(); + if (prev && next && prev.type == 3 && next.type == 3) { + range.setEnd(prev[0], prev[0].nodeValue.length); + } else if (!isStart) { + range.setEnd(range.endContainer, range.endOffset - 1); + } + } + dummyParent.removeChild(dummy); + } + return this; + }, + remove : function(map) { + var self = this, doc = self.doc, range = self.range; + range.enlarge(); + if (range.startOffset === 0) { + var ksc = K(range.startContainer), parent; + while ((parent = ksc.parent()) && parent.isStyle() && parent.children().length == 1) { + ksc = parent; + } + range.setStart(ksc[0], 0); + ksc = K(range.startContainer); + if (ksc.isBlock()) { + _removeAttrOrCss(ksc, map); + } + var kscp = ksc.parent(); + if (kscp && kscp.isBlock()) { + _removeAttrOrCss(kscp, map); + } + } + var sc, so; + if (range.collapsed) { + self.split(true, map); + sc = range.startContainer; + so = range.startOffset; + if (so > 0) { + var sb = K(sc.childNodes[so - 1]); + if (sb && _isEmptyNode(sb)) { + sb.remove(); + range.setStart(sc, so - 1); + } + } + var sa = K(sc.childNodes[so]); + if (sa && _isEmptyNode(sa)) { + sa.remove(); + } + if (_isEmptyNode(sc)) { + range.startBefore(sc); + sc.remove(); + } + range.collapse(true); + return self; + } + self.split(true, map); + self.split(false, map); + var startDummy = doc.createElement('span'), endDummy = doc.createElement('span'); + range.cloneRange().collapse(false).insertNode(endDummy); + range.cloneRange().collapse(true).insertNode(startDummy); + var nodeList = [], cmpStart = false; + K(range.commonAncestor()).scan(function(node) { + if (!cmpStart && node == startDummy) { + cmpStart = true; + return; + } + if (node == endDummy) { + return false; + } + if (cmpStart) { + nodeList.push(node); + } + }); + K(startDummy).remove(); + K(endDummy).remove(); + sc = range.startContainer; + so = range.startOffset; + var ec = range.endContainer, eo = range.endOffset; + if (so > 0) { + var startBefore = K(sc.childNodes[so - 1]); + if (startBefore && _isEmptyNode(startBefore)) { + startBefore.remove(); + range.setStart(sc, so - 1); + if (sc == ec) { + range.setEnd(ec, eo - 1); + } + } + var startAfter = K(sc.childNodes[so]); + if (startAfter && _isEmptyNode(startAfter)) { + startAfter.remove(); + if (sc == ec) { + range.setEnd(ec, eo - 1); + } + } + } + var endAfter = K(ec.childNodes[range.endOffset]); + if (endAfter && _isEmptyNode(endAfter)) { + endAfter.remove(); + } + var bookmark = range.createBookmark(true); + _each(nodeList, function(i, node) { + _removeAttrOrCss(K(node), map); + }); + range.moveToBookmark(bookmark); + return self; + }, + commonNode : function(map) { + var range = this.range; + var ec = range.endContainer, eo = range.endOffset, + node = (ec.nodeType == 3 || eo === 0) ? ec : ec.childNodes[eo - 1]; + function find(node) { + var child = node, parent = node; + while (parent) { + if (_hasAttrOrCss(K(parent), map)) { + return K(parent); + } + parent = parent.parentNode; + } + while (child && (child = child.lastChild)) { + if (_hasAttrOrCss(K(child), map)) { + return K(child); + } + } + return null; + } + var cNode = find(node); + if (cNode) { + return cNode; + } + if (node.nodeType == 1 || (ec.nodeType == 3 && eo === 0)) { + var prev = K(node).prev(); + if (prev) { + return find(prev); + } + } + return null; + }, + commonAncestor : function(tagName) { + var range = this.range, + sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset, + startNode = (sc.nodeType == 3 || so === 0) ? sc : sc.childNodes[so - 1], + endNode = (ec.nodeType == 3 || eo === 0) ? ec : ec.childNodes[eo - 1]; + function find(node) { + while (node) { + if (node.nodeType == 1) { + if (node.tagName.toLowerCase() === tagName) { + return node; + } + } + node = node.parentNode; + } + return null; + } + var start = find(startNode), end = find(endNode); + if (start && end && start === end) { + return K(start); + } + return null; + }, + state : function(key) { + var self = this, doc = self.doc, bool = false; + try { + bool = doc.queryCommandState(key); + } catch (e) {} + return bool; + }, + val : function(key) { + var self = this, doc = self.doc, range = self.range; + function lc(val) { + return val.toLowerCase(); + } + key = lc(key); + var val = '', knode; + if (key === 'fontfamily' || key === 'fontname') { + val = _nativeCommandValue(doc, 'fontname'); + val = val.replace(/['"]/g, ''); + return lc(val); + } + if (key === 'formatblock') { + val = _nativeCommandValue(doc, key); + if (val === '') { + knode = self.commonNode({'h1,h2,h3,h4,h5,h6,p,div,pre,address' : '*'}); + if (knode) { + val = knode.name; + } + } + if (val === 'Normal') { + val = 'p'; + } + return lc(val); + } + if (key === 'fontsize') { + knode = self.commonNode({'*' : '.font-size'}); + if (knode) { + val = knode.css('font-size'); + } + return lc(val); + } + if (key === 'forecolor') { + knode = self.commonNode({'*' : '.color'}); + if (knode) { + val = knode.css('color'); + } + val = _toHex(val); + if (val === '') { + val = 'default'; + } + return lc(val); + } + if (key === 'hilitecolor') { + knode = self.commonNode({'*' : '.background-color'}); + if (knode) { + val = knode.css('background-color'); + } + val = _toHex(val); + if (val === '') { + val = 'default'; + } + return lc(val); + } + return val; + }, + toggle : function(wrapper, map) { + var self = this; + if (self.commonNode(map)) { + self.remove(map); + } else { + self.wrap(wrapper); + } + return self.select(); + }, + bold : function() { + return this.toggle('', { + span : '.font-weight=bold', + strong : '*', + b : '*' + }); + }, + italic : function() { + return this.toggle('', { + span : '.font-style=italic', + em : '*', + i : '*' + }); + }, + underline : function() { + return this.toggle('', { + span : '.text-decoration=underline', + u : '*' + }); + }, + strikethrough : function() { + return this.toggle('', { + span : '.text-decoration=line-through', + s : '*' + }); + }, + forecolor : function(val) { + return this.wrap('').select(); + }, + hilitecolor : function(val) { + return this.wrap('').select(); + }, + fontsize : function(val) { + return this.wrap('').select(); + }, + fontname : function(val) { + return this.fontfamily(val); + }, + fontfamily : function(val) { + return this.wrap('').select(); + }, + removeformat : function() { + var map = { + '*' : '.font-weight,.font-style,.text-decoration,.color,.background-color,.font-size,.font-family,.text-indent' + }, + tags = _STYLE_TAG_MAP; + _each(tags, function(key, val) { + map[key] = '*'; + }); + this.remove(map); + return this.select(); + }, + inserthtml : function(val, quickMode) { + var self = this, range = self.range; + if (val === '') { + return self; + } + function pasteHtml(range, val) { + val = '' + val; + var rng = range.get(); + if (rng.item) { + rng.item(0).outerHTML = val; + } else { + rng.pasteHTML(val); + } + var temp = range.doc.getElementById('__kindeditor_temp_tag__'); + temp.parentNode.removeChild(temp); + var newRange = _toRange(rng); + range.setEnd(newRange.endContainer, newRange.endOffset); + range.collapse(false); + self.select(false); + } + function insertHtml(range, val) { + var doc = range.doc, + frag = doc.createDocumentFragment(); + K('@' + val, doc).each(function() { + frag.appendChild(this); + }); + range.deleteContents(); + range.insertNode(frag); + range.collapse(false); + self.select(false); + } + if (_IERANGE && quickMode) { + try { + pasteHtml(range, val); + } catch(e) { + insertHtml(range, val); + } + return self; + } + insertHtml(range, val); + return self; + }, + hr : function() { + return this.inserthtml('
    '); + }, + print : function() { + this.win.print(); + return this; + }, + insertimage : function(url, title, width, height, border, align) { + title = _undef(title, ''); + border = _undef(border, 0); + var html = ''; + return self.inserthtml(html); + } + if (range.isControl()) { + var node = K(range.startContainer.childNodes[range.startOffset]); + html += '>'; + node.after(K(html, doc)); + node.next().append(node); + range.selectNode(node[0]); + return self.select(); + } + function setAttr(node, url, type) { + K(node).attr('href', url).attr('data-ke-src', url); + if (type) { + K(node).attr('target', type); + } else { + K(node).removeAttr('target'); + } + } + var sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset; + if (sc.nodeType == 1 && sc === ec && so + 1 === eo) { + var child = sc.childNodes[so]; + if (child.nodeName.toLowerCase() == 'a') { + setAttr(child, url, type); + return self; + } + } + _nativeCommand(doc, 'createlink', '__kindeditor_temp_url__'); + K('a[href="__kindeditor_temp_url__"]', doc).each(function() { + setAttr(this, url, type); + }); + return self; + }, + unlink : function() { + var self = this, doc = self.doc, range = self.range; + self.select(); + if (range.collapsed) { + var a = self.commonNode({ a : '*' }); + if (a) { + range.selectNode(a.get()); + self.select(); + } + _nativeCommand(doc, 'unlink', null); + if (_WEBKIT && K(range.startContainer).name === 'img') { + var parent = K(range.startContainer).parent(); + if (parent.name === 'a') { + parent.remove(true); + } + } + } else { + _nativeCommand(doc, 'unlink', null); + } + return self; + } +}); +_each(('formatblock,selectall,justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,' + + 'insertunorderedlist,indent,outdent,subscript,superscript').split(','), function(i, name) { + KCmd.prototype[name] = function(val) { + var self = this; + self.select(); + _nativeCommand(self.doc, name, val); + if (_IERANGE && _inArray(name, 'justifyleft,justifycenter,justifyright,justifyfull'.split(',')) >= 0) { + self.selection(); + } + if (!_IERANGE || _inArray(name, 'formatblock,selectall,insertorderedlist,insertunorderedlist'.split(',')) >= 0) { + self.selection(); + } + return self; + }; +}); +_each('cut,copy,paste'.split(','), function(i, name) { + KCmd.prototype[name] = function() { + var self = this; + if (!self.doc.queryCommandSupported(name)) { + throw 'not supported'; + } + self.select(); + _nativeCommand(self.doc, name, null); + return self; + }; +}); +function _cmd(mixed) { + if (mixed.nodeName) { + var doc = _getDoc(mixed); + mixed = _range(doc).selectNodeContents(doc.body).collapse(false); + } + return new KCmd(mixed); +} +K.CmdClass = KCmd; +K.cmd = _cmd; + + +function _drag(options) { + var moveEl = options.moveEl, + moveFn = options.moveFn, + clickEl = options.clickEl || moveEl, + beforeDrag = options.beforeDrag, + iframeFix = options.iframeFix === undefined ? true : options.iframeFix; + var docs = [document]; + if (iframeFix) { + K('iframe').each(function() { + var src = _formatUrl(this.src || '', 'absolute'); + if (/^https?:\/\//.test(src)) { + return; + } + var doc; + try { + doc = _iframeDoc(this); + } catch(e) {} + if (doc) { + var pos = K(this).pos(); + K(doc).data('pos-x', pos.x); + K(doc).data('pos-y', pos.y); + docs.push(doc); + } + }); + } + clickEl.mousedown(function(e) { + if(e.button !== 0 && e.button !== 1) { + return; + } + e.stopPropagation(); + var self = clickEl.get(), + x = _removeUnit(moveEl.css('left')), + y = _removeUnit(moveEl.css('top')), + width = moveEl.width(), + height = moveEl.height(), + pageX = e.pageX, + pageY = e.pageY; + if (beforeDrag) { + beforeDrag(); + } + function moveListener(e) { + e.preventDefault(); + var kdoc = K(_getDoc(e.target)); + var diffX = _round((kdoc.data('pos-x') || 0) + e.pageX - pageX); + var diffY = _round((kdoc.data('pos-y') || 0) + e.pageY - pageY); + moveFn.call(clickEl, x, y, width, height, diffX, diffY); + } + function selectListener(e) { + e.preventDefault(); + } + function upListener(e) { + e.preventDefault(); + K(docs).unbind('mousemove', moveListener) + .unbind('mouseup', upListener) + .unbind('selectstart', selectListener); + if (self.releaseCapture) { + self.releaseCapture(); + } + } + K(docs).mousemove(moveListener) + .mouseup(upListener) + .bind('selectstart', selectListener); + if (self.setCapture) { + self.setCapture(); + } + }); +} + +function KWidget(options) { + this.init(options); +} +_extend(KWidget, { + init : function(options) { + var self = this; + self.name = options.name || ''; + self.doc = options.doc || document; + self.win = _getWin(self.doc); + self.x = _addUnit(options.x); + self.y = _addUnit(options.y); + self.z = options.z; + self.width = _addUnit(options.width); + self.height = _addUnit(options.height); + self.div = K('
    '); + self.options = options; + self._alignEl = options.alignEl; + if (self.width) { + self.div.css('width', self.width); + } + if (self.height) { + self.div.css('height', self.height); + } + if (self.z) { + self.div.css({ + position : 'absolute', + left : self.x, + top : self.y, + 'z-index' : self.z + }); + } + if (self.z && (self.x === undefined || self.y === undefined)) { + self.autoPos(self.width, self.height); + } + if (options.cls) { + self.div.addClass(options.cls); + } + if (options.shadowMode) { + self.div.addClass('ke-shadow'); + } + if (options.css) { + self.div.css(options.css); + } + if (options.src) { + K(options.src).replaceWith(self.div); + } else { + K(self.doc.body).append(self.div); + } + if (options.html) { + self.div.html(options.html); + } + if (options.autoScroll) { + if (_IE && _V < 7 || _QUIRKS) { + var scrollPos = _getScrollPos(); + K(self.win).bind('scroll', function(e) { + var pos = _getScrollPos(), + diffX = pos.x - scrollPos.x, + diffY = pos.y - scrollPos.y; + self.pos(_removeUnit(self.x) + diffX, _removeUnit(self.y) + diffY, false); + }); + } else { + self.div.css('position', 'fixed'); + } + } + }, + pos : function(x, y, updateProp) { + var self = this; + updateProp = _undef(updateProp, true); + if (x !== null) { + x = x < 0 ? 0 : _addUnit(x); + self.div.css('left', x); + if (updateProp) { + self.x = x; + } + } + if (y !== null) { + y = y < 0 ? 0 : _addUnit(y); + self.div.css('top', y); + if (updateProp) { + self.y = y; + } + } + return self; + }, + autoPos : function(width, height) { + var self = this, + w = _removeUnit(width) || 0, + h = _removeUnit(height) || 0, + scrollPos = _getScrollPos(); + if (self._alignEl) { + var knode = K(self._alignEl), + pos = knode.pos(), + diffX = _round(knode[0].clientWidth / 2 - w / 2), + diffY = _round(knode[0].clientHeight / 2 - h / 2); + x = diffX < 0 ? pos.x : pos.x + diffX; + y = diffY < 0 ? pos.y : pos.y + diffY; + } else { + var docEl = _docElement(self.doc); + x = _round(scrollPos.x + (docEl.clientWidth - w) / 2); + y = _round(scrollPos.y + (docEl.clientHeight - h) / 2); + } + if (!(_IE && _V < 7 || _QUIRKS)) { + x -= scrollPos.x; + y -= scrollPos.y; + } + return self.pos(x, y); + }, + remove : function() { + var self = this; + if (_IE && _V < 7 || _QUIRKS) { + K(self.win).unbind('scroll'); + } + self.div.remove(); + _each(self, function(i) { + self[i] = null; + }); + return this; + }, + show : function() { + this.div.show(); + return this; + }, + hide : function() { + this.div.hide(); + return this; + }, + draggable : function(options) { + var self = this; + options = options || {}; + options.moveEl = self.div; + options.moveFn = function(x, y, width, height, diffX, diffY) { + if ((x = x + diffX) < 0) { + x = 0; + } + if ((y = y + diffY) < 0) { + y = 0; + } + self.pos(x, y); + }; + _drag(options); + return self; + } +}); +function _widget(options) { + return new KWidget(options); +} +K.WidgetClass = KWidget; +K.widget = _widget; + + +function _iframeDoc(iframe) { + iframe = _get(iframe); + return iframe.contentDocument || iframe.contentWindow.document; +} +var html, _direction = ''; +if ((html = document.getElementsByTagName('html'))) { + _direction = html[0].dir; +} +function _getInitHtml(themesPath, bodyClass, cssPath, cssData) { + var arr = [ + (_direction === '' ? '' : ''), + '', + '' + ]; + if (!_isArray(cssPath)) { + cssPath = [cssPath]; + } + _each(cssPath, function(i, path) { + if (path) { + arr.push(''); + } + }); + if (cssData) { + arr.push(''); + } + arr.push(''); + return arr.join('\n'); +} +function _elementVal(knode, val) { + if (knode.hasVal()) { + if (val === undefined) { + var html = knode.val(); + html = html.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/ig, ''); + return html; + } + return knode.val(val); + } + return knode.html(val); +} + +function KEdit(options) { + this.init(options); +} +_extend(KEdit, KWidget, { + init : function(options) { + var self = this; + KEdit.parent.init.call(self, options); + self.srcElement = K(options.srcElement); + self.div.addClass('ke-edit'); + self.designMode = _undef(options.designMode, true); + self.beforeGetHtml = options.beforeGetHtml; + self.beforeSetHtml = options.beforeSetHtml; + self.afterSetHtml = options.afterSetHtml; + var themesPath = _undef(options.themesPath, ''), + bodyClass = options.bodyClass, + cssPath = options.cssPath, + cssData = options.cssData, + isDocumentDomain = location.protocol != 'res:' && location.host.replace(/:\d+/, '') !== document.domain, + srcScript = ('document.open();' + + (isDocumentDomain ? 'document.domain="' + document.domain + '";' : '') + + 'document.close();'), + iframeSrc = _IE ? ' src="javascript:void(function(){' + encodeURIComponent(srcScript) + '}())"' : ''; + self.iframe = K('').css('width', '100%'); + self.textarea = K('').css('width', '100%'); + self.tabIndex = isNaN(parseInt(options.tabIndex, 10)) ? self.srcElement.attr('tabindex') : parseInt(options.tabIndex, 10); + self.iframe.attr('tabindex', self.tabIndex); + self.textarea.attr('tabindex', self.tabIndex); + if (self.width) { + self.setWidth(self.width); + } + if (self.height) { + self.setHeight(self.height); + } + if (self.designMode) { + self.textarea.hide(); + } else { + self.iframe.hide(); + } + function ready() { + var doc = _iframeDoc(self.iframe); + doc.open(); + if (isDocumentDomain) { + doc.domain = document.domain; + } + doc.write(_getInitHtml(themesPath, bodyClass, cssPath, cssData)); + doc.close(); + self.win = self.iframe[0].contentWindow; + self.doc = doc; + var cmd = _cmd(doc); + self.afterChange(function(e) { + cmd.selection(); + }); + if (_WEBKIT) { + K(doc).click(function(e) { + if (K(e.target).name === 'img') { + cmd.selection(true); + cmd.range.selectNode(e.target); + cmd.select(); + } + }); + } + if (_IE) { + self._mousedownHandler = function() { + var newRange = cmd.range.cloneRange(); + newRange.shrink(); + if (newRange.isControl()) { + self.blur(); + } + }; + K(document).mousedown(self._mousedownHandler); + K(doc).keydown(function(e) { + if (e.which == 8) { + cmd.selection(); + var rng = cmd.range; + if (rng.isControl()) { + rng.collapse(true); + K(rng.startContainer.childNodes[rng.startOffset]).remove(); + e.preventDefault(); + } + } + }); + } + self.cmd = cmd; + self.html(_elementVal(self.srcElement)); + if (_IE) { + doc.body.disabled = true; + doc.body.contentEditable = true; + doc.body.removeAttribute('disabled'); + } else { + doc.designMode = 'on'; + } + if (options.afterCreate) { + options.afterCreate.call(self); + } + } + if (isDocumentDomain) { + self.iframe.bind('load', function(e) { + self.iframe.unbind('load'); + if (_IE) { + ready(); + } else { + setTimeout(ready, 0); + } + }); + } + self.div.append(self.iframe); + self.div.append(self.textarea); + self.srcElement.hide(); + !isDocumentDomain && ready(); + }, + setWidth : function(val) { + var self = this; + val = _addUnit(val); + self.width = val; + self.div.css('width', val); + return self; + }, + setHeight : function(val) { + var self = this; + val = _addUnit(val); + self.height = val; + self.div.css('height', val); + self.iframe.css('height', val); + if ((_IE && _V < 8) || _QUIRKS) { + val = _addUnit(_removeUnit(val) - 2); + } + self.textarea.css('height', val); + return self; + }, + remove : function() { + var self = this, doc = self.doc; + K(doc.body).unbind(); + K(doc).unbind(); + K(self.win).unbind(); + if (self._mousedownHandler) { + K(document).unbind('mousedown', self._mousedownHandler); + } + _elementVal(self.srcElement, self.html()); + self.srcElement.show(); + self.iframe.unbind(); + self.textarea.unbind(); + KEdit.parent.remove.call(self); + }, + html : function(val, isFull) { + var self = this, doc = self.doc; + if (self.designMode) { + var body = doc.body; + if (val === undefined) { + if (isFull) { + val = '' + body.parentNode.innerHTML + ''; + } else { + val = body.innerHTML; + } + if (self.beforeGetHtml) { + val = self.beforeGetHtml(val); + } + if (_GECKO && val == '
    ') { + val = ''; + } + return val; + } + if (self.beforeSetHtml) { + val = self.beforeSetHtml(val); + } + if (_IE && _V >= 9) { + val = val.replace(/(<.*?checked=")checked(".*>)/ig, '$1$2'); + } + K(body).html(val); + if (self.afterSetHtml) { + self.afterSetHtml(); + } + return self; + } + if (val === undefined) { + return self.textarea.val(); + } + self.textarea.val(val); + return self; + }, + design : function(bool) { + var self = this, val; + if (bool === undefined ? !self.designMode : bool) { + if (!self.designMode) { + val = self.html(); + self.designMode = true; + self.textarea.hide(); + self.html(val); + var iframe = self.iframe; + var height = _removeUnit(self.height); + iframe.height(height - 2); + iframe.show(); + setTimeout(function() { + iframe.height(height); + }, 0); + } + } else { + if (self.designMode) { + val = self.html(); + self.designMode = false; + self.html(val); + self.iframe.hide(); + self.textarea.show(); + } + } + return self.focus(); + }, + focus : function() { + var self = this; + self.designMode ? self.win.focus() : self.textarea[0].focus(); + return self; + }, + blur : function() { + var self = this; + if (_IE) { + var input = K('', self.div); + self.div.append(input); + input[0].focus(); + input.remove(); + } else { + self.designMode ? self.win.blur() : self.textarea[0].blur(); + } + return self; + }, + afterChange : function(fn) { + var self = this, doc = self.doc, body = doc.body; + K(doc).keyup(function(e) { + if (!e.ctrlKey && !e.altKey && _CHANGE_KEY_MAP[e.which]) { + fn(e); + } + }); + K(doc).mouseup(fn).contextmenu(fn); + K(self.win).blur(fn); + function timeoutHandler(e) { + setTimeout(function() { + fn(e); + }, 1); + } + K(body).bind('paste', timeoutHandler); + K(body).bind('cut', timeoutHandler); + return self; + } +}); +function _edit(options) { + return new KEdit(options); +} +K.EditClass = KEdit; +K.edit = _edit; +K.iframeDoc = _iframeDoc; + + +function _selectToolbar(name, fn) { + var self = this, + knode = self.get(name); + if (knode) { + if (knode.hasClass('ke-disabled')) { + return; + } + fn(knode); + } +} + +function KToolbar(options) { + this.init(options); +} +_extend(KToolbar, KWidget, { + init : function(options) { + var self = this; + KToolbar.parent.init.call(self, options); + self.disableMode = _undef(options.disableMode, false); + self.noDisableItemMap = _toMap(_undef(options.noDisableItems, [])); + self._itemMap = {}; + self.div.addClass('ke-toolbar').bind('contextmenu,mousedown,mousemove', function(e) { + e.preventDefault(); + }).attr('unselectable', 'on'); + function find(target) { + var knode = K(target); + if (knode.hasClass('ke-outline')) { + return knode; + } + if (knode.hasClass('ke-toolbar-icon')) { + return knode.parent(); + } + } + function hover(e, method) { + var knode = find(e.target); + if (knode) { + if (knode.hasClass('ke-disabled')) { + return; + } + if (knode.hasClass('ke-selected')) { + return; + } + knode[method]('ke-on'); + } + } + self.div.mouseover(function(e) { + hover(e, 'addClass'); + }) + .mouseout(function(e) { + hover(e, 'removeClass'); + }) + .click(function(e) { + var knode = find(e.target); + if (knode) { + if (knode.hasClass('ke-disabled')) { + return; + } + self.options.click.call(this, e, knode.attr('data-name')); + } + }); + }, + get : function(name) { + if (this._itemMap[name]) { + return this._itemMap[name]; + } + return (this._itemMap[name] = K('span.ke-icon-' + name, this.div).parent()); + }, + select : function(name) { + _selectToolbar.call(this, name, function(knode) { + knode.addClass('ke-selected'); + }); + return self; + }, + unselect : function(name) { + _selectToolbar.call(this, name, function(knode) { + knode.removeClass('ke-selected').removeClass('ke-on'); + }); + return self; + }, + enable : function(name) { + var self = this, + knode = name.get ? name : self.get(name); + if (knode) { + knode.removeClass('ke-disabled'); + knode.opacity(1); + } + return self; + }, + disable : function(name) { + var self = this, + knode = name.get ? name : self.get(name); + if (knode) { + knode.removeClass('ke-selected').addClass('ke-disabled'); + knode.opacity(0.5); + } + return self; + }, + disableAll : function(bool, noDisableItems) { + var self = this, map = self.noDisableItemMap, item; + if (noDisableItems) { + map = _toMap(noDisableItems); + } + if (bool === undefined ? !self.disableMode : bool) { + K('span.ke-outline', self.div).each(function() { + var knode = K(this), + name = knode[0].getAttribute('data-name', 2); + if (!map[name]) { + self.disable(knode); + } + }); + self.disableMode = true; + } else { + K('span.ke-outline', self.div).each(function() { + var knode = K(this), + name = knode[0].getAttribute('data-name', 2); + if (!map[name]) { + self.enable(knode); + } + }); + self.disableMode = false; + } + return self; + } +}); +function _toolbar(options) { + return new KToolbar(options); +} +K.ToolbarClass = KToolbar; +K.toolbar = _toolbar; + + +function KMenu(options) { + this.init(options); +} +_extend(KMenu, KWidget, { + init : function(options) { + var self = this; + options.z = options.z || 811213; + KMenu.parent.init.call(self, options); + self.centerLineMode = _undef(options.centerLineMode, true); + self.div.addClass('ke-menu').bind('click,mousedown', function(e){ + e.stopPropagation(); + }).attr('unselectable', 'on'); + }, + addItem : function(item) { + var self = this; + if (item.title === '-') { + self.div.append(K('
    ')); + return; + } + var itemDiv = K('
    '), + leftDiv = K('
    '), + rightDiv = K('
    '), + height = _addUnit(item.height), + iconClass = _undef(item.iconClass, ''); + self.div.append(itemDiv); + if (height) { + itemDiv.css('height', height); + rightDiv.css('line-height', height); + } + var centerDiv; + if (self.centerLineMode) { + centerDiv = K('
    '); + if (height) { + centerDiv.css('height', height); + } + } + itemDiv.mouseover(function(e) { + K(this).addClass('ke-menu-item-on'); + if (centerDiv) { + centerDiv.addClass('ke-menu-item-center-on'); + } + }) + .mouseout(function(e) { + K(this).removeClass('ke-menu-item-on'); + if (centerDiv) { + centerDiv.removeClass('ke-menu-item-center-on'); + } + }) + .click(function(e) { + item.click.call(K(this)); + e.stopPropagation(); + }) + .append(leftDiv); + if (centerDiv) { + itemDiv.append(centerDiv); + } + itemDiv.append(rightDiv); + if (item.checked) { + iconClass = 'ke-icon-checked'; + } + if (iconClass !== '') { + leftDiv.html(''); + } + rightDiv.html(item.title); + return self; + }, + remove : function() { + var self = this; + if (self.options.beforeRemove) { + self.options.beforeRemove.call(self); + } + K('.ke-menu-item', self.div[0]).unbind(); + KMenu.parent.remove.call(self); + return self; + } +}); +function _menu(options) { + return new KMenu(options); +} +K.MenuClass = KMenu; +K.menu = _menu; + + +function KColorPicker(options) { + this.init(options); +} +_extend(KColorPicker, KWidget, { + init : function(options) { + var self = this; + options.z = options.z || 811213; + KColorPicker.parent.init.call(self, options); + var colors = options.colors || [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ]; + self.selectedColor = (options.selectedColor || '').toLowerCase(); + self._cells = []; + self.div.addClass('ke-colorpicker').bind('click,mousedown', function(e){ + e.stopPropagation(); + }).attr('unselectable', 'on'); + var table = self.doc.createElement('table'); + self.div.append(table); + table.className = 'ke-colorpicker-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + var row = table.insertRow(0), cell = row.insertCell(0); + cell.colSpan = colors[0].length; + self._addAttr(cell, '', 'ke-colorpicker-cell-top'); + for (var i = 0; i < colors.length; i++) { + row = table.insertRow(i + 1); + for (var j = 0; j < colors[i].length; j++) { + cell = row.insertCell(j); + self._addAttr(cell, colors[i][j], 'ke-colorpicker-cell'); + } + } + }, + _addAttr : function(cell, color, cls) { + var self = this; + cell = K(cell).addClass(cls); + if (self.selectedColor === color.toLowerCase()) { + cell.addClass('ke-colorpicker-cell-selected'); + } + cell.attr('title', color || self.options.noColor); + cell.mouseover(function(e) { + K(this).addClass('ke-colorpicker-cell-on'); + }); + cell.mouseout(function(e) { + K(this).removeClass('ke-colorpicker-cell-on'); + }); + cell.click(function(e) { + e.stop(); + self.options.click.call(K(this), color); + }); + if (color) { + cell.append(K('
    ').css('background-color', color)); + } else { + cell.html(self.options.noColor); + } + K(cell).attr('unselectable', 'on'); + self._cells.push(cell); + }, + remove : function() { + var self = this; + _each(self._cells, function() { + this.unbind(); + }); + KColorPicker.parent.remove.call(self); + return self; + } +}); +function _colorpicker(options) { + return new KColorPicker(options); +} +K.ColorPickerClass = KColorPicker; +K.colorpicker = _colorpicker; + + +function KUploadButton(options) { + this.init(options); +} +_extend(KUploadButton, { + init : function(options) { + var self = this, + button = K(options.button), + fieldName = options.fieldName || 'file', + url = options.url || '', + title = button.val(), + extraParams = options.extraParams || {}, + cls = button[0].className || '', + target = options.target || 'kindeditor_upload_iframe_' + new Date().getTime(); + options.afterError = options.afterError || function(str) { + alert(str); + }; + var hiddenElements = []; + for(var k in extraParams){ + hiddenElements.push(''); + } + var html = [ + '
    ', + (options.target ? '' : ''), + (options.form ? '
    ' : '
    '), + '', + hiddenElements.join(''), + '', + '', + '', + (options.form ? '
    ' : ''), + '
    '].join(''); + var div = K(html, button.doc); + button.hide(); + button.before(div); + self.div = div; + self.button = button; + self.iframe = options.target ? K('iframe[name="' + target + '"]') : K('iframe', div); + self.form = options.form ? K(options.form) : K('form', div); + self.fileBox = K('.ke-upload-file', div); + var width = options.width || K('.ke-button-common', div).width(); + K('.ke-upload-area', div).width(width); + self.options = options; + }, + submit : function() { + var self = this, + iframe = self.iframe; + iframe.bind('load', function() { + iframe.unbind(); + var tempForm = document.createElement('form'); + self.fileBox.before(tempForm); + K(tempForm).append(self.fileBox); + tempForm.reset(); + K(tempForm).remove(true); + var doc = K.iframeDoc(iframe), + pre = doc.getElementsByTagName('pre')[0], + str = '', data; + if (pre) { + str = pre.innerHTML; + } else { + str = doc.body.innerHTML; + } + str = _unescape(str); + iframe[0].src = 'javascript:false'; + try { + data = K.json(str); + } catch (e) { + self.options.afterError.call(self, '' + doc.body.parentNode.innerHTML + ''); + } + if (data) { + self.options.afterUpload.call(self, data); + } + }); + self.form[0].submit(); + return self; + }, + remove : function() { + var self = this; + if (self.fileBox) { + self.fileBox.unbind(); + } + self.iframe.remove(); + self.div.remove(); + self.button.show(); + return self; + } +}); +function _uploadbutton(options) { + return new KUploadButton(options); +} +K.UploadButtonClass = KUploadButton; +K.uploadbutton = _uploadbutton; + + +function _createButton(arg) { + arg = arg || {}; + var name = arg.name || '', + span = K(''), + btn = K(''); + if (arg.click) { + btn.click(arg.click); + } + span.append(btn); + return span; +} + +function KDialog(options) { + this.init(options); +} +_extend(KDialog, KWidget, { + init : function(options) { + var self = this; + var shadowMode = _undef(options.shadowMode, true); + options.z = options.z || 811213; + options.shadowMode = false; + options.autoScroll = _undef(options.autoScroll, true); + KDialog.parent.init.call(self, options); + var title = options.title, + body = K(options.body, self.doc), + previewBtn = options.previewBtn, + yesBtn = options.yesBtn, + noBtn = options.noBtn, + closeBtn = options.closeBtn, + showMask = _undef(options.showMask, true); + self.div.addClass('ke-dialog').bind('click,mousedown', function(e){ + e.stopPropagation(); + }); + var contentDiv = K('
    ').appendTo(self.div); + if (_IE && _V < 7) { + self.iframeMask = K('').appendTo(self.div); + } else if (shadowMode) { + K('
    ').appendTo(self.div); + } + var headerDiv = K('
    '); + contentDiv.append(headerDiv); + headerDiv.html(title); + self.closeIcon = K('').click(closeBtn.click); + headerDiv.append(self.closeIcon); + self.draggable({ + clickEl : headerDiv, + beforeDrag : options.beforeDrag + }); + var bodyDiv = K('
    '); + contentDiv.append(bodyDiv); + bodyDiv.append(body); + var footerDiv = K(''); + if (previewBtn || yesBtn || noBtn) { + contentDiv.append(footerDiv); + } + _each([ + { btn : previewBtn, name : 'preview' }, + { btn : yesBtn, name : 'yes' }, + { btn : noBtn, name : 'no' } + ], function() { + if (this.btn) { + var button = _createButton(this.btn); + button.addClass('ke-dialog-' + this.name); + footerDiv.append(button); + } + }); + if (self.height) { + bodyDiv.height(_removeUnit(self.height) - headerDiv.height() - footerDiv.height()); + } + self.div.width(self.div.width()); + self.div.height(self.div.height()); + self.mask = null; + if (showMask) { + var docEl = _docElement(self.doc), + docWidth = Math.max(docEl.scrollWidth, docEl.clientWidth), + docHeight = Math.max(docEl.scrollHeight, docEl.clientHeight); + self.mask = _widget({ + x : 0, + y : 0, + z : self.z - 1, + cls : 'ke-dialog-mask', + width : docWidth, + height : docHeight + }); + } + self.autoPos(self.div.width(), self.div.height()); + self.footerDiv = footerDiv; + self.bodyDiv = bodyDiv; + self.headerDiv = headerDiv; + self.isLoading = false; + }, + setMaskIndex : function(z) { + var self = this; + self.mask.div.css('z-index', z); + }, + showLoading : function(msg) { + msg = _undef(msg, ''); + var self = this, body = self.bodyDiv; + self.loading = K('
    ' + msg + '
    ') + .width(body.width()).height(body.height()) + .css('top', self.headerDiv.height() + 'px'); + body.css('visibility', 'hidden').after(self.loading); + self.isLoading = true; + return self; + }, + hideLoading : function() { + this.loading && this.loading.remove(); + this.bodyDiv.css('visibility', 'visible'); + this.isLoading = false; + return this; + }, + remove : function() { + var self = this; + if (self.options.beforeRemove) { + self.options.beforeRemove.call(self); + } + self.mask && self.mask.remove(); + self.iframeMask && self.iframeMask.remove(); + self.closeIcon.unbind(); + K('input', self.div).unbind(); + K('button', self.div).unbind(); + self.footerDiv.unbind(); + self.bodyDiv.unbind(); + self.headerDiv.unbind(); + K('iframe', self.div).each(function() { + K(this).remove(); + }); + KDialog.parent.remove.call(self); + return self; + } +}); +function _dialog(options) { + return new KDialog(options); +} +K.DialogClass = KDialog; +K.dialog = _dialog; + + +function _tabs(options) { + var self = _widget(options), + remove = self.remove, + afterSelect = options.afterSelect, + div = self.div, + liList = []; + div.addClass('ke-tabs') + .bind('contextmenu,mousedown,mousemove', function(e) { + e.preventDefault(); + }); + var ul = K('
      '); + div.append(ul); + self.add = function(tab) { + var li = K('
    • ' + tab.title + '
    • '); + li.data('tab', tab); + liList.push(li); + ul.append(li); + }; + self.selectedIndex = 0; + self.select = function(index) { + self.selectedIndex = index; + _each(liList, function(i, li) { + li.unbind(); + if (i === index) { + li.addClass('ke-tabs-li-selected'); + K(li.data('tab').panel).show(''); + } else { + li.removeClass('ke-tabs-li-selected').removeClass('ke-tabs-li-on') + .mouseover(function() { + K(this).addClass('ke-tabs-li-on'); + }) + .mouseout(function() { + K(this).removeClass('ke-tabs-li-on'); + }) + .click(function() { + self.select(i); + }); + K(li.data('tab').panel).hide(); + } + }); + if (afterSelect) { + afterSelect.call(self, index); + } + }; + self.remove = function() { + _each(liList, function() { + this.remove(); + }); + ul.remove(); + remove.call(self); + }; + return self; +} +K.tabs = _tabs; + + +function _loadScript(url, fn) { + var head = document.getElementsByTagName('head')[0] || (_QUIRKS ? document.body : document.documentElement), + script = document.createElement('script'); + head.appendChild(script); + script.src = url; + script.charset = 'utf-8'; + script.onload = script.onreadystatechange = function() { + if (!this.readyState || this.readyState === 'loaded') { + if (fn) { + fn(); + } + script.onload = script.onreadystatechange = null; + head.removeChild(script); + } + }; +} + +function _chopQuery(url) { + var index = url.indexOf('?'); + return index > 0 ? url.substr(0, index) : url; +} +function _loadStyle(url) { + var head = document.getElementsByTagName('head')[0] || (_QUIRKS ? document.body : document.documentElement), + link = document.createElement('link'), + absoluteUrl = _chopQuery(_formatUrl(url, 'absolute')); + var links = K('link[rel="stylesheet"]', head); + for (var i = 0, len = links.length; i < len; i++) { + if (_chopQuery(_formatUrl(links[i].href, 'absolute')) === absoluteUrl) { + return; + } + } + head.appendChild(link); + link.href = url; + link.rel = 'stylesheet'; +} +function _ajax(url, fn, method, param, dataType) { + method = method || 'GET'; + dataType = dataType || 'json'; + var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); + xhr.open(method, url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4 && xhr.status == 200) { + if (fn) { + var data = _trim(xhr.responseText); + if (dataType == 'json') { + data = _json(data); + } + fn(data); + } + } + }; + if (method == 'POST') { + var params = []; + _each(param, function(key, val) { + params.push(encodeURIComponent(key) + '=' + encodeURIComponent(val)); + }); + try { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } catch (e) {} + xhr.send(params.join('&')); + } else { + xhr.send(null); + } +} +K.loadScript = _loadScript; +K.loadStyle = _loadStyle; +K.ajax = _ajax; + + +var _plugins = {}; +function _plugin(name, fn) { + if (name === undefined) { + return _plugins; + } + if (!fn) { + return _plugins[name]; + } + _plugins[name] = fn; +} +var _language = {}; +function _parseLangKey(key) { + var match, ns = 'core'; + if ((match = /^(\w+)\.(\w+)$/.exec(key))) { + ns = match[1]; + key = match[2]; + } + return { ns : ns, key : key }; +} +function _lang(mixed, langType) { + langType = langType === undefined ? K.options.langType : langType; + if (typeof mixed === 'string') { + if (!_language[langType]) { + return 'no language'; + } + var pos = mixed.length - 1; + if (mixed.substr(pos) === '.') { + return _language[langType][mixed.substr(0, pos)]; + } + var obj = _parseLangKey(mixed); + return _language[langType][obj.ns][obj.key]; + } + _each(mixed, function(key, val) { + var obj = _parseLangKey(key); + if (!_language[langType]) { + _language[langType] = {}; + } + if (!_language[langType][obj.ns]) { + _language[langType][obj.ns] = {}; + } + _language[langType][obj.ns][obj.key] = val; + }); +} + +function _getImageFromRange(range, fn) { + if (range.collapsed) { + return; + } + range = range.cloneRange().up(); + var sc = range.startContainer, so = range.startOffset; + if (!_WEBKIT && !range.isControl()) { + return; + } + var img = K(sc.childNodes[so]); + if (!img || img.name != 'img') { + return; + } + if (fn(img)) { + return img; + } +} +function _bindContextmenuEvent() { + var self = this, doc = self.edit.doc; + K(doc).contextmenu(function(e) { + if (self.menu) { + self.hideMenu(); + } + if (!self.useContextmenu) { + e.preventDefault(); + return; + } + if (self._contextmenus.length === 0) { + return; + } + var maxWidth = 0, items = []; + _each(self._contextmenus, function() { + if (this.title == '-') { + items.push(this); + return; + } + if (this.cond && this.cond()) { + items.push(this); + if (this.width && this.width > maxWidth) { + maxWidth = this.width; + } + } + }); + while (items.length > 0 && items[0].title == '-') { + items.shift(); + } + while (items.length > 0 && items[items.length - 1].title == '-') { + items.pop(); + } + var prevItem = null; + _each(items, function(i) { + if (this.title == '-' && prevItem.title == '-') { + delete items[i]; + } + prevItem = this; + }); + if (items.length > 0) { + e.preventDefault(); + var pos = K(self.edit.iframe).pos(), + menu = _menu({ + x : pos.x + e.clientX, + y : pos.y + e.clientY, + width : maxWidth, + css : { visibility: 'hidden' }, + shadowMode : self.shadowMode + }); + _each(items, function() { + if (this.title) { + menu.addItem(this); + } + }); + var docEl = _docElement(menu.doc), + menuHeight = menu.div.height(); + if (e.clientY + menuHeight >= docEl.clientHeight - 100) { + menu.pos(menu.x, _removeUnit(menu.y) - menuHeight); + } + menu.div.css('visibility', 'visible'); + self.menu = menu; + } + }); +} +function _bindNewlineEvent() { + var self = this, doc = self.edit.doc, newlineTag = self.newlineTag; + if (_IE && newlineTag !== 'br') { + return; + } + if (_GECKO && _V < 3 && newlineTag !== 'p') { + return; + } + if (_OPERA && _V < 9) { + return; + } + var brSkipTagMap = _toMap('h1,h2,h3,h4,h5,h6,pre,li'), + pSkipTagMap = _toMap('p,h1,h2,h3,h4,h5,h6,pre,li,blockquote'); + function getAncestorTagName(range) { + var ancestor = K(range.commonAncestor()); + while (ancestor) { + if (ancestor.type == 1 && !ancestor.isStyle()) { + break; + } + ancestor = ancestor.parent(); + } + return ancestor.name; + } + K(doc).keydown(function(e) { + if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) { + return; + } + self.cmd.selection(); + var tagName = getAncestorTagName(self.cmd.range); + if (tagName == 'marquee' || tagName == 'select') { + return; + } + if (newlineTag === 'br' && !brSkipTagMap[tagName]) { + e.preventDefault(); + self.insertHtml('
      ' + (_IE && _V < 9 ? '' : '\u200B')); + return; + } + if (!pSkipTagMap[tagName]) { + _nativeCommand(doc, 'formatblock', '

      '); + } + }); + K(doc).keyup(function(e) { + if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) { + return; + } + if (newlineTag == 'br') { + return; + } + if (_GECKO) { + var root = self.cmd.commonAncestor('p'); + var a = self.cmd.commonAncestor('a'); + if (a && a.text() == '') { + a.remove(true); + self.cmd.range.selectNodeContents(root[0]).collapse(true); + self.cmd.select(); + } + return; + } + self.cmd.selection(); + var tagName = getAncestorTagName(self.cmd.range); + if (tagName == 'marquee' || tagName == 'select') { + return; + } + if (!pSkipTagMap[tagName]) { + _nativeCommand(doc, 'formatblock', '

      '); + } + var div = self.cmd.commonAncestor('div'); + if (div) { + var p = K('

      '), + child = div[0].firstChild; + while (child) { + var next = child.nextSibling; + p.append(child); + child = next; + } + div.before(p); + div.remove(); + self.cmd.range.selectNodeContents(p[0]); + self.cmd.select(); + } + }); +} +function _bindTabEvent() { + var self = this, doc = self.edit.doc; + K(doc).keydown(function(e) { + if (e.which == 9) { + e.preventDefault(); + if (self.afterTab) { + self.afterTab.call(self, e); + return; + } + var cmd = self.cmd, range = cmd.range; + range.shrink(); + if (range.collapsed && range.startContainer.nodeType == 1) { + range.insertNode(K('@ ', doc)[0]); + cmd.select(); + } + self.insertHtml('    '); + } + }); +} +function _bindFocusEvent() { + var self = this; + K(self.edit.textarea[0], self.edit.win).focus(function(e) { + if (self.afterFocus) { + self.afterFocus.call(self, e); + } + }).blur(function(e) { + if (self.afterBlur) { + self.afterBlur.call(self, e); + } + }); +} +function _removeBookmarkTag(html) { + return _trim(html.replace(/]*id="?__kindeditor_bookmark_\w+_\d+__"?[^>]*><\/span>/ig, '')); +} +function _removeTempTag(html) { + return html.replace(/]+class="?__kindeditor_paste__"?[^>]*>[\s\S]*?<\/div>/ig, ''); +} +function _addBookmarkToStack(stack, bookmark) { + if (stack.length === 0) { + stack.push(bookmark); + return; + } + var prev = stack[stack.length - 1]; + if (_removeBookmarkTag(bookmark.html) !== _removeBookmarkTag(prev.html)) { + stack.push(bookmark); + } +} + +function _undoToRedo(fromStack, toStack) { + var self = this, edit = self.edit, + body = edit.doc.body, + range, bookmark; + if (fromStack.length === 0) { + return self; + } + if (edit.designMode) { + range = self.cmd.range; + bookmark = range.createBookmark(true); + bookmark.html = body.innerHTML; + } else { + bookmark = { + html : body.innerHTML + }; + } + _addBookmarkToStack(toStack, bookmark); + var prev = fromStack.pop(); + if (_removeBookmarkTag(bookmark.html) === _removeBookmarkTag(prev.html) && fromStack.length > 0) { + prev = fromStack.pop(); + } + if (edit.designMode) { + edit.html(prev.html); + if (prev.start) { + range.moveToBookmark(prev); + self.select(); + } + } else { + K(body).html(_removeBookmarkTag(prev.html)); + } + return self; +} +function KEditor(options) { + var self = this; + self.options = {}; + function setOption(key, val) { + if (KEditor.prototype[key] === undefined) { + self[key] = val; + } + self.options[key] = val; + } + _each(options, function(key, val) { + setOption(key, options[key]); + }); + _each(K.options, function(key, val) { + if (self[key] === undefined) { + setOption(key, val); + } + }); + var se = K(self.srcElement || '', + ''].join(''), + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var type = K('.ke-code-type', dialog.div).val(), + code = textarea.val(), + cls = type === '' ? '' : ' lang-' + type, + html = '
      \n' + K.escape(code) + '
      '; + if (K.trim(code) === '') { + alert(lang.pleaseInput); + textarea[0].focus(); + return; + } + self.insertHtml(html).hideDialog().focus(); + } + } + }), + textarea = K('textarea', dialog.div); + textarea[0].focus(); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('emoticons', function(K) { + var self = this, name = 'emoticons', + path = (self.emoticonsPath || self.pluginsPath + 'emoticons/images/'), + allowPreview = self.allowPreviewEmoticons === undefined ? true : self.allowPreviewEmoticons, + currentPageNum = 1; + self.clickToolbar(name, function() { + var rows = 5, cols = 9, total = 135, startNum = 0, + cells = rows * cols, pages = Math.ceil(total / cells), + colsHalf = Math.floor(cols / 2), + wrapperDiv = K('
      '), + elements = [], + menu = self.createMenu({ + name : name, + beforeRemove : function() { + removeEvent(); + } + }); + menu.div.append(wrapperDiv); + var previewDiv, previewImg; + if (allowPreview) { + previewDiv = K('
      ').css('right', 0); + previewImg = K(''); + wrapperDiv.append(previewDiv); + previewDiv.append(previewImg); + } + function bindCellEvent(cell, j, num) { + if (previewDiv) { + cell.mouseover(function() { + if (j > colsHalf) { + previewDiv.css('left', 0); + previewDiv.css('right', ''); + } else { + previewDiv.css('left', ''); + previewDiv.css('right', 0); + } + previewImg.attr('src', path + num + '.gif'); + K(this).addClass('ke-on'); + }); + } else { + cell.mouseover(function() { + K(this).addClass('ke-on'); + }); + } + cell.mouseout(function() { + K(this).removeClass('ke-on'); + }); + cell.click(function(e) { + self.insertHtml('').hideMenu().focus(); + e.stop(); + }); + } + function createEmoticonsTable(pageNum, parentDiv) { + var table = document.createElement('table'); + parentDiv.append(table); + if (previewDiv) { + K(table).mouseover(function() { + previewDiv.show('block'); + }); + K(table).mouseout(function() { + previewDiv.hide(); + }); + elements.push(K(table)); + } + table.className = 'ke-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + var num = (pageNum - 1) * cells + startNum; + for (var i = 0; i < rows; i++) { + var row = table.insertRow(i); + for (var j = 0; j < cols; j++) { + var cell = K(row.insertCell(j)); + cell.addClass('ke-cell'); + bindCellEvent(cell, j, num); + var span = K('') + .css('background-position', '-' + (24 * num) + 'px 0px') + .css('background-image', 'url(' + path + 'static.gif)'); + cell.append(span); + elements.push(cell); + num++; + } + } + return table; + } + var table = createEmoticonsTable(currentPageNum, wrapperDiv); + function removeEvent() { + K.each(elements, function() { + this.unbind(); + }); + } + var pageDiv; + function bindPageEvent(el, pageNum) { + el.click(function(e) { + removeEvent(); + table.parentNode.removeChild(table); + pageDiv.remove(); + table = createEmoticonsTable(pageNum, wrapperDiv); + createPageTable(pageNum); + currentPageNum = pageNum; + e.stop(); + }); + } + function createPageTable(currentPageNum) { + pageDiv = K('
      '); + wrapperDiv.append(pageDiv); + for (var pageNum = 1; pageNum <= pages; pageNum++) { + if (currentPageNum !== pageNum) { + var a = K('[' + pageNum + ']'); + bindPageEvent(a, pageNum); + pageDiv.append(a); + elements.push(a); + } else { + pageDiv.append(K('@[' + pageNum + ']')); + } + pageDiv.append(K('@ ')); + } + } + createPageTable(currentPageNum); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('filemanager', function(K) { + var self = this, name = 'filemanager', + fileManagerJson = K.undef(self.fileManagerJson, self.basePath + 'php/file_manager_json.php'), + imgPath = self.pluginsPath + name + '/images/', + lang = self.lang(name + '.'); + function makeFileTitle(filename, filesize, datetime) { + return filename + ' (' + Math.ceil(filesize / 1024) + 'KB, ' + datetime + ')'; + } + function bindTitle(el, data) { + if (data.is_dir) { + el.attr('title', data.filename); + } else { + el.attr('title', makeFileTitle(data.filename, data.filesize, data.datetime)); + } + } + self.plugin.filemanagerDialog = function(options) { + var width = K.undef(options.width, 650), + height = K.undef(options.height, 510), + dirName = K.undef(options.dirName, ''), + viewType = K.undef(options.viewType, 'VIEW').toUpperCase(), + clickFn = options.clickFn; + var html = [ + '
      ', + '
      ', + '
      ', + ' ', + '' + lang.moveup + '', + '
      ', + '
      ', + lang.viewType + ' ', + lang.orderType + ' ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : width, + height : height, + title : self.lang(name), + body : html + }), + div = dialog.div, + bodyDiv = K('.ke-plugin-filemanager-body', div), + moveupImg = K('[name="moveupImg"]', div), + moveupLink = K('[name="moveupLink"]', div), + viewServerBtn = K('[name="viewServer"]', div), + viewTypeBox = K('[name="viewType"]', div), + orderTypeBox = K('[name="orderType"]', div); + function reloadPage(path, order, func) { + var param = 'path=' + path + '&order=' + order + '&dir=' + dirName; + dialog.showLoading(self.lang('ajaxLoading')); + K.ajax(K.addParam(fileManagerJson, param + '&' + new Date().getTime()), function(data) { + dialog.hideLoading(); + func(data); + }); + } + var elList = []; + function bindEvent(el, result, data, createFunc) { + var fileUrl = K.formatUrl(result.current_url + data.filename, 'absolute'), + dirPath = encodeURIComponent(result.current_dir_path + data.filename + '/'); + if (data.is_dir) { + el.click(function(e) { + reloadPage(dirPath, orderTypeBox.val(), createFunc); + }); + } else if (data.is_photo) { + el.click(function(e) { + clickFn.call(this, fileUrl, data.filename); + }); + } else { + el.click(function(e) { + clickFn.call(this, fileUrl, data.filename); + }); + } + elList.push(el); + } + function createCommon(result, createFunc) { + K.each(elList, function() { + this.unbind(); + }); + moveupLink.unbind(); + viewTypeBox.unbind(); + orderTypeBox.unbind(); + if (result.current_dir_path) { + moveupLink.click(function(e) { + reloadPage(result.moveup_dir_path, orderTypeBox.val(), createFunc); + }); + } + function changeFunc() { + if (viewTypeBox.val() == 'VIEW') { + reloadPage(result.current_dir_path, orderTypeBox.val(), createView); + } else { + reloadPage(result.current_dir_path, orderTypeBox.val(), createList); + } + } + viewTypeBox.change(changeFunc); + orderTypeBox.change(changeFunc); + bodyDiv.html(''); + } + function createList(result) { + createCommon(result, createList); + var table = document.createElement('table'); + table.className = 'ke-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + bodyDiv.append(table); + var fileList = result.file_list; + for (var i = 0, len = fileList.length; i < len; i++) { + var data = fileList[i], row = K(table.insertRow(i)); + row.mouseover(function(e) { + K(this).addClass('ke-on'); + }) + .mouseout(function(e) { + K(this).removeClass('ke-on'); + }); + var iconUrl = imgPath + (data.is_dir ? 'folder-16.gif' : 'file-16.gif'), + img = K('' + data.filename + ''), + cell0 = K(row[0].insertCell(0)).addClass('ke-cell ke-name').append(img).append(document.createTextNode(' ' + data.filename)); + if (!data.is_dir || data.has_file) { + row.css('cursor', 'pointer'); + cell0.attr('title', data.filename); + bindEvent(cell0, result, data, createList); + } else { + cell0.attr('title', lang.emptyFolder); + } + K(row[0].insertCell(1)).addClass('ke-cell ke-size').html(data.is_dir ? '-' : Math.ceil(data.filesize / 1024) + 'KB'); + K(row[0].insertCell(2)).addClass('ke-cell ke-datetime').html(data.datetime); + } + } + function createView(result) { + createCommon(result, createView); + var fileList = result.file_list; + for (var i = 0, len = fileList.length; i < len; i++) { + var data = fileList[i], + div = K('
      '); + bodyDiv.append(div); + var photoDiv = K('
      ') + .mouseover(function(e) { + K(this).addClass('ke-on'); + }) + .mouseout(function(e) { + K(this).removeClass('ke-on'); + }); + div.append(photoDiv); + var fileUrl = result.current_url + data.filename, + iconUrl = data.is_dir ? imgPath + 'folder-64.gif' : (data.is_photo ? fileUrl : imgPath + 'file-64.gif'); + var img = K('' + data.filename + ''); + if (!data.is_dir || data.has_file) { + photoDiv.css('cursor', 'pointer'); + bindTitle(photoDiv, data); + bindEvent(photoDiv, result, data, createView); + } else { + photoDiv.attr('title', lang.emptyFolder); + } + photoDiv.append(img); + div.append('
      ' + data.filename + '
      '); + } + } + viewTypeBox.val(viewType); + reloadPage('', orderTypeBox.val(), viewType == 'VIEW' ? createView : createList); + return dialog; + } +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('flash', function(K) { + var self = this, name = 'flash', lang = self.lang(name + '.'), + allowFlashUpload = K.undef(self.allowFlashUpload, true), + allowFileManager = K.undef(self.allowFileManager, false), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'); + self.plugin.flash = { + edit : function() { + var html = [ + '
      ', + '
      ', + '', + '  ', + '  ', + '', + '', + '', + '
      ', + '
      ', + '', + ' ', + '
      ', + '
      ', + '', + ' ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()), + width = widthBox.val(), + height = heightBox.val(); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + var html = K.mediaImg(self.themesPath + 'common/blank.gif', { + src : url, + type : K.mediaType('.swf'), + width : width, + height : height, + quality : 'high' + }); + self.insertHtml(html).hideDialog().focus(); + } + } + }), + div = dialog.div, + urlBox = K('[name="url"]', div), + viewServerBtn = K('[name="viewServer"]', div), + widthBox = K('[name="width"]', div), + heightBox = K('[name="height"]', div); + urlBox.val('http://'); + if (allowFlashUpload) { + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + extraParams : extraParams, + url : K.addParam(uploadJson, 'dir=flash'), + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + urlBox.val(url); + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + alert(self.lang('uploadSuccess')); + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + }); + } else { + K('.ke-upload-button', div).hide(); + } + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'LIST', + dirName : 'flash', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + var img = self.plugin.getSelectedFlash(); + if (img) { + var attrs = K.mediaAttrs(img.attr('data-ke-tag')); + urlBox.val(attrs.src); + widthBox.val(K.removeUnit(img.css('width')) || attrs.width || 0); + heightBox.val(K.removeUnit(img.css('height')) || attrs.height || 0); + } + urlBox[0].focus(); + urlBox[0].select(); + }, + 'delete' : function() { + self.plugin.getSelectedFlash().remove(); + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.flash.edit); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('image', function(K) { + var self = this, name = 'image', + allowImageUpload = K.undef(self.allowImageUpload, true), + allowImageRemote = K.undef(self.allowImageRemote, true), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + allowFileManager = K.undef(self.allowFileManager, false), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'), + imageTabIndex = K.undef(self.imageTabIndex, 0), + imgPath = self.pluginsPath + 'image/images/', + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + fillDescAfterUploadImage = K.undef(self.fillDescAfterUploadImage, false), + lang = self.lang(name + '.'); + self.plugin.imageDialog = function(options) { + var imageUrl = options.imageUrl, + imageWidth = K.undef(options.imageWidth, ''), + imageHeight = K.undef(options.imageHeight, ''), + imageTitle = K.undef(options.imageTitle, ''), + imageAlign = K.undef(options.imageAlign, ''), + showRemote = K.undef(options.showRemote, true), + showLocal = K.undef(options.showLocal, true), + tabIndex = K.undef(options.tabIndex, 0), + clickFn = options.clickFn; + var target = 'kindeditor_upload_iframe_' + new Date().getTime(); + var hiddenElements = []; + for(var k in extraParams){ + hiddenElements.push(''); + } + var html = [ + '
      ', + '
      ', + '', + '', + '
      ' + ].join(''); + var dialogWidth = showLocal || allowFileManager ? 450 : 400, + dialogHeight = showLocal && showRemote ? 300 : 250; + var dialog = self.createDialog({ + name : name, + width : dialogWidth, + height : dialogHeight, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + if (dialog.isLoading) { + return; + } + if (showLocal && showRemote && tabs && tabs.selectedIndex === 1 || !showRemote) { + if (uploadbutton.fileBox.val() == '') { + alert(self.lang('pleaseSelectFile')); + return; + } + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + localUrlBox.val(''); + return; + } + var url = K.trim(urlBox.val()), + width = widthBox.val(), + height = heightBox.val(), + title = titleBox.val(), + align = ''; + alignBox.each(function() { + if (this.checked) { + align = this.value; + return false; + } + }); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + clickFn.call(self, url, title, width, height, 0, align); + } + }, + beforeRemove : function() { + viewServerBtn.unbind(); + widthBox.unbind(); + heightBox.unbind(); + refreshBtn.unbind(); + } + }), + div = dialog.div; + var urlBox = K('[name="url"]', div), + localUrlBox = K('[name="localUrl"]', div), + viewServerBtn = K('[name="viewServer"]', div), + widthBox = K('.tab1 [name="width"]', div), + heightBox = K('.tab1 [name="height"]', div), + refreshBtn = K('.ke-refresh-btn', div), + titleBox = K('.tab1 [name="title"]', div), + alignBox = K('.tab1 [name="align"]', div); + var tabs; + if (showRemote && showLocal) { + tabs = K.tabs({ + src : K('.tabs', div), + afterSelect : function(i) {} + }); + tabs.add({ + title : lang.remoteImage, + panel : K('.tab1', div) + }); + tabs.add({ + title : lang.localImage, + panel : K('.tab2', div) + }); + tabs.select(tabIndex); + } else if (showRemote) { + K('.tab1', div).show(); + } else if (showLocal) { + K('.tab2', div).show(); + } + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + form : K('.ke-form', div), + target : target, + width: 60, + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + if (!fillDescAfterUploadImage) { + clickFn.call(self, url, data.title, data.width, data.height, data.border, data.align); + } else { + K(".ke-dialog-row #remoteUrl", div).val(url); + K(".ke-tabs-li", div)[0].click(); + K(".ke-refresh-btn", div).click(); + } + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + localUrlBox.val(uploadbutton.fileBox.val()); + }); + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'VIEW', + dirName : 'image', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + var originalWidth = 0, originalHeight = 0; + function setSize(width, height) { + widthBox.val(width); + heightBox.val(height); + originalWidth = width; + originalHeight = height; + } + refreshBtn.click(function(e) { + var tempImg = K('', document).css({ + position : 'absolute', + visibility : 'hidden', + top : 0, + left : '-1000px' + }); + tempImg.bind('load', function() { + setSize(tempImg.width(), tempImg.height()); + tempImg.remove(); + }); + K(document.body).append(tempImg); + }); + widthBox.change(function(e) { + if (originalWidth > 0) { + heightBox.val(Math.round(originalHeight / originalWidth * parseInt(this.value, 10))); + } + }); + heightBox.change(function(e) { + if (originalHeight > 0) { + widthBox.val(Math.round(originalWidth / originalHeight * parseInt(this.value, 10))); + } + }); + urlBox.val(options.imageUrl); + setSize(options.imageWidth, options.imageHeight); + titleBox.val(options.imageTitle); + alignBox.each(function() { + if (this.value === options.imageAlign) { + this.checked = true; + return false; + } + }); + if (showRemote && tabIndex === 0) { + urlBox[0].focus(); + urlBox[0].select(); + } + return dialog; + }; + self.plugin.image = { + edit : function() { + var img = self.plugin.getSelectedImage(); + self.plugin.imageDialog({ + imageUrl : img ? img.attr('data-ke-src') : 'http://', + imageWidth : img ? img.width() : '', + imageHeight : img ? img.height() : '', + imageTitle : img ? img.attr('title') : '', + imageAlign : img ? img.attr('align') : '', + showRemote : allowImageRemote, + showLocal : allowImageUpload, + tabIndex: img ? 0 : imageTabIndex, + clickFn : function(url, title, width, height, border, align) { + if (img) { + img.attr('src', url); + img.attr('data-ke-src', url); + img.attr('width', width); + img.attr('height', height); + img.attr('title', title); + img.attr('align', align); + img.attr('alt', title); + } else { + self.exec('insertimage', url, title, width, height, border, align); + } + setTimeout(function() { + self.hideDialog().focus(); + }, 0); + } + }); + }, + 'delete' : function() { + var target = self.plugin.getSelectedImage(); + if (target.parent().name == 'a') { + target = target.parent(); + } + target.remove(); + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.image.edit); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('insertfile', function(K) { + var self = this, name = 'insertfile', + allowFileUpload = K.undef(self.allowFileUpload, true), + allowFileManager = K.undef(self.allowFileManager, false), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'), + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + lang = self.lang(name + '.'); + self.plugin.fileDialog = function(options) { + var fileUrl = K.undef(options.fileUrl, 'http://'), + fileTitle = K.undef(options.fileTitle, ''), + clickFn = options.clickFn; + var html = [ + '
      ', + '
      ', + '', + '  ', + '  ', + '', + '', + '', + '
      ', + '
      ', + '', + '
      ', + '
      ', + '', + '' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()), + title = titleBox.val(); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (K.trim(title) === '') { + title = url; + } + clickFn.call(self, url, title); + } + } + }), + div = dialog.div; + var urlBox = K('[name="url"]', div), + viewServerBtn = K('[name="viewServer"]', div), + titleBox = K('[name="title"]', div); + if (allowFileUpload) { + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + url : K.addParam(uploadJson, 'dir=file'), + extraParams : extraParams, + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + urlBox.val(url); + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + alert(self.lang('uploadSuccess')); + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + }); + } else { + K('.ke-upload-button', div).hide(); + } + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'LIST', + dirName : 'file', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + urlBox.val(fileUrl); + titleBox.val(fileTitle); + urlBox[0].focus(); + urlBox[0].select(); + }; + self.clickToolbar(name, function() { + self.plugin.fileDialog({ + clickFn : function(url, title) { + var html = '' + title + ''; + self.insertHtml(html).hideDialog().focus(); + } + }); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('lineheight', function(K) { + var self = this, name = 'lineheight', lang = self.lang(name + '.'); + self.clickToolbar(name, function() { + var curVal = '', commonNode = self.cmd.commonNode({'*' : '.line-height'}); + if (commonNode) { + curVal = commonNode.css('line-height'); + } + var menu = self.createMenu({ + name : name, + width : 150 + }); + K.each(lang.lineHeight, function(i, row) { + K.each(row, function(key, val) { + menu.addItem({ + title : val, + checked : curVal === key, + click : function() { + self.cmd.toggle('', { + span : '.line-height=' + key + }); + self.updateState(); + self.addBookmark(); + self.hideMenu(); + } + }); + }); + }); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('link', function(K) { + var self = this, name = 'link'; + self.plugin.link = { + edit : function() { + var lang = self.lang(name + '.'), + html = '
      ' + + '
      ' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + self.exec('createlink', url, typeBox.val()).hideDialog().focus(); + } + } + }), + div = dialog.div, + urlBox = K('input[name="url"]', div), + typeBox = K('select[name="type"]', div); + urlBox.val('http://'); + typeBox[0].options[0] = new Option(lang.newWindow, '_blank'); + typeBox[0].options[1] = new Option(lang.selfWindow, ''); + self.cmd.selection(); + var a = self.plugin.getSelectedLink(); + if (a) { + self.cmd.range.selectNode(a[0]); + self.cmd.select(); + urlBox.val(a.attr('data-ke-src')); + typeBox.val(a.attr('target')); + } + urlBox[0].focus(); + urlBox[0].select(); + }, + 'delete' : function() { + self.exec('unlink', null); + } + }; + self.clickToolbar(name, self.plugin.link.edit); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('media', function(K) { + var self = this, name = 'media', lang = self.lang(name + '.'), + allowMediaUpload = K.undef(self.allowMediaUpload, true), + allowFileManager = K.undef(self.allowFileManager, false), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'); + self.plugin.media = { + edit : function() { + var html = [ + '
      ', + '
      ', + '', + '  ', + '  ', + '', + '', + '', + '
      ', + '
      ', + '', + '', + '
      ', + '
      ', + '', + '', + '
      ', + '
      ', + '', + ' ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 450, + height : 230, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()), + width = widthBox.val(), + height = heightBox.val(); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + var html = K.mediaImg(self.themesPath + 'common/blank.gif', { + src : url, + type : K.mediaType(url), + width : width, + height : height, + autostart : autostartBox[0].checked ? 'true' : 'false', + loop : 'true' + }); + self.insertHtml(html).hideDialog().focus(); + } + } + }), + div = dialog.div, + urlBox = K('[name="url"]', div), + viewServerBtn = K('[name="viewServer"]', div), + widthBox = K('[name="width"]', div), + heightBox = K('[name="height"]', div), + autostartBox = K('[name="autostart"]', div); + urlBox.val('http://'); + if (allowMediaUpload) { + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + extraParams : extraParams, + url : K.addParam(uploadJson, 'dir=media'), + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + urlBox.val(url); + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + alert(self.lang('uploadSuccess')); + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + }); + } else { + K('.ke-upload-button', div).hide(); + } + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'LIST', + dirName : 'media', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + var img = self.plugin.getSelectedMedia(); + if (img) { + var attrs = K.mediaAttrs(img.attr('data-ke-tag')); + urlBox.val(attrs.src); + widthBox.val(K.removeUnit(img.css('width')) || attrs.width || 0); + heightBox.val(K.removeUnit(img.css('height')) || attrs.height || 0); + autostartBox[0].checked = (attrs.autostart === 'true'); + } + urlBox[0].focus(); + urlBox[0].select(); + }, + 'delete' : function() { + self.plugin.getSelectedMedia().remove(); + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.media.edit); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +(function(K) { +function KSWFUpload(options) { + this.init(options); +} +K.extend(KSWFUpload, { + init : function(options) { + var self = this; + options.afterError = options.afterError || function(str) { + alert(str); + }; + self.options = options; + self.progressbars = {}; + self.div = K(options.container).html([ + '
      ', + '
      ', + '
      ', + '', + '
      ', + '
      ' + options.uploadDesc + '
      ', + '', + '', + '', + '
      ', + '
      ', + '
      ' + ].join('')); + self.bodyDiv = K('.ke-swfupload-body', self.div); + function showError(itemDiv, msg) { + K('.ke-status > div', itemDiv).hide(); + K('.ke-message', itemDiv).addClass('ke-error').show().html(K.escape(msg)); + } + var settings = { + debug : false, + upload_url : options.uploadUrl, + flash_url : options.flashUrl, + file_post_name : options.filePostName, + button_placeholder : K('.ke-swfupload-button > input', self.div)[0], + button_image_url: options.buttonImageUrl, + button_width: options.buttonWidth, + button_height: options.buttonHeight, + button_cursor : SWFUpload.CURSOR.HAND, + file_types : options.fileTypes, + file_types_description : options.fileTypesDesc, + file_upload_limit : options.fileUploadLimit, + file_size_limit : options.fileSizeLimit, + post_params : options.postParams, + file_queued_handler : function(file) { + file.url = self.options.fileIconUrl; + self.appendFile(file); + }, + file_queue_error_handler : function(file, errorCode, message) { + var errorName = ''; + switch (errorCode) { + case SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED: + errorName = options.queueLimitExceeded; + break; + case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT: + errorName = options.fileExceedsSizeLimit; + break; + case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE: + errorName = options.zeroByteFile; + break; + case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE: + errorName = options.invalidFiletype; + break; + default: + errorName = options.unknownError; + break; + } + K.DEBUG && alert(errorName); + }, + upload_start_handler : function(file) { + var self = this; + var itemDiv = K('div[data-id="' + file.id + '"]', self.bodyDiv); + K('.ke-status > div', itemDiv).hide(); + K('.ke-progressbar', itemDiv).show(); + }, + upload_progress_handler : function(file, bytesLoaded, bytesTotal) { + var percent = Math.round(bytesLoaded * 100 / bytesTotal); + var progressbar = self.progressbars[file.id]; + progressbar.bar.css('width', Math.round(percent * 80 / 100) + 'px'); + progressbar.percent.html(percent + '%'); + }, + upload_error_handler : function(file, errorCode, message) { + if (file && file.filestatus == SWFUpload.FILE_STATUS.ERROR) { + var itemDiv = K('div[data-id="' + file.id + '"]', self.bodyDiv).eq(0); + showError(itemDiv, self.options.errorMessage); + } + }, + upload_success_handler : function(file, serverData) { + var itemDiv = K('div[data-id="' + file.id + '"]', self.bodyDiv).eq(0); + var data = {}; + try { + data = K.json(serverData); + } catch (e) { + self.options.afterError.call(this, '' + serverData + ''); + } + if (data.error !== 0) { + showError(itemDiv, K.DEBUG ? data.message : self.options.errorMessage); + return; + } + file.url = data.url; + K('.ke-img', itemDiv).attr('src', file.url).attr('data-status', file.filestatus).data('data', data); + K('.ke-status > div', itemDiv).hide(); + } + }; + self.swfu = new SWFUpload(settings); + K('.ke-swfupload-startupload input', self.div).click(function() { + self.swfu.startUpload(); + }); + }, + getUrlList : function() { + var list = []; + K('.ke-img', self.bodyDiv).each(function() { + var img = K(this); + var status = img.attr('data-status'); + if (status == SWFUpload.FILE_STATUS.COMPLETE) { + list.push(img.data('data')); + } + }); + return list; + }, + removeFile : function(fileId) { + var self = this; + self.swfu.cancelUpload(fileId); + var itemDiv = K('div[data-id="' + fileId + '"]', self.bodyDiv); + K('.ke-photo', itemDiv).unbind(); + K('.ke-delete', itemDiv).unbind(); + itemDiv.remove(); + }, + removeFiles : function() { + var self = this; + K('.ke-item', self.bodyDiv).each(function() { + self.removeFile(K(this).attr('data-id')); + }); + }, + appendFile : function(file) { + var self = this; + var itemDiv = K('
      '); + self.bodyDiv.append(itemDiv); + var photoDiv = K('
      ') + .mouseover(function(e) { + K(this).addClass('ke-on'); + }) + .mouseout(function(e) { + K(this).removeClass('ke-on'); + }); + itemDiv.append(photoDiv); + var img = K('' + file.name + ''); + photoDiv.append(img); + K('').appendTo(photoDiv).click(function() { + self.removeFile(file.id); + }); + var statusDiv = K('
      ').appendTo(photoDiv); + K(['
      ', + '
      ', + '
      0%
      '].join('')).hide().appendTo(statusDiv); + K('
      ' + self.options.pendingMessage + '
      ').appendTo(statusDiv); + itemDiv.append('
      ' + file.name + '
      '); + self.progressbars[file.id] = { + bar : K('.ke-progressbar-bar-inner', photoDiv), + percent : K('.ke-progressbar-percent', photoDiv) + }; + }, + remove : function() { + this.removeFiles(); + this.swfu.destroy(); + this.div.html(''); + } +}); +K.swfupload = function(element, options) { + return new KSWFUpload(element, options); +}; +})(KindEditor); +KindEditor.plugin('multiimage', function(K) { + var self = this, name = 'multiimage', + formatUploadUrl = K.undef(self.formatUploadUrl, true), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'), + imgPath = self.pluginsPath + 'multiimage/images/', + imageSizeLimit = K.undef(self.imageSizeLimit, '1MB'), + imageFileTypes = K.undef(self.imageFileTypes, '*.jpg;*.gif;*.png'), + imageUploadLimit = K.undef(self.imageUploadLimit, 20), + filePostName = K.undef(self.filePostName, 'imgFile'), + lang = self.lang(name + '.'); + self.plugin.multiImageDialog = function(options) { + var clickFn = options.clickFn, + uploadDesc = K.tmpl(lang.uploadDesc, {uploadLimit : imageUploadLimit, sizeLimit : imageSizeLimit}); + var html = [ + '
      ', + '
      ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 650, + height : 510, + title : self.lang(name), + body : html, + previewBtn : { + name : lang.insertAll, + click : function(e) { + clickFn.call(self, swfupload.getUrlList()); + } + }, + yesBtn : { + name : lang.clearAll, + click : function(e) { + swfupload.removeFiles(); + } + }, + beforeRemove : function() { + if (!K.IE || K.V <= 8) { + swfupload.remove(); + } + } + }), + div = dialog.div; + var swfupload = K.swfupload({ + container : K('.swfupload', div), + buttonImageUrl : imgPath + (self.langType == 'zh-CN' ? 'select-files-zh-CN.png' : 'select-files-en.png'), + buttonWidth : self.langType == 'zh-CN' ? 72 : 88, + buttonHeight : 23, + fileIconUrl : imgPath + 'image.png', + uploadDesc : uploadDesc, + startButtonValue : lang.startUpload, + uploadUrl : K.addParam(uploadJson, 'dir=image'), + flashUrl : imgPath + 'swfupload.swf', + filePostName : filePostName, + fileTypes : '*.jpg;*.jpeg;*.gif;*.png;*.bmp', + fileTypesDesc : 'Image Files', + fileUploadLimit : imageUploadLimit, + fileSizeLimit : imageSizeLimit, + postParams : K.undef(self.extraFileUploadParams, {}), + queueLimitExceeded : lang.queueLimitExceeded, + fileExceedsSizeLimit : lang.fileExceedsSizeLimit, + zeroByteFile : lang.zeroByteFile, + invalidFiletype : lang.invalidFiletype, + unknownError : lang.unknownError, + pendingMessage : lang.pending, + errorMessage : lang.uploadError, + afterError : function(html) { + self.errorDialog(html); + } + }); + return dialog; + }; + self.clickToolbar(name, function() { + self.plugin.multiImageDialog({ + clickFn : function (urlList) { + if (urlList.length === 0) { + return; + } + K.each(urlList, function(i, data) { + if (self.afterUpload) { + self.afterUpload.call(self, data.url, data, 'multiimage'); + } + self.exec('insertimage', data.url, data.title, data.width, data.height, data.border, data.align); + }); + setTimeout(function() { + self.hideDialog().focus(); + }, 0); + } + }); + }); +}); +/* ******************* */ +/* Constructor & Init */ +/* ******************* */ +(function() { +window.SWFUpload = function (settings) { + this.initSWFUpload(settings); +}; +SWFUpload.prototype.initSWFUpload = function (settings) { + try { + this.customSettings = {}; + this.settings = settings; + this.eventQueue = []; + this.movieName = "KindEditor_SWFUpload_" + SWFUpload.movieCount++; + this.movieElement = null; + SWFUpload.instances[this.movieName] = this; + this.initSettings(); + this.loadFlash(); + this.displayDebugInfo(); + } catch (ex) { + delete SWFUpload.instances[this.movieName]; + throw ex; + } +}; +/* *************** */ +/* Static Members */ +/* *************** */ +SWFUpload.instances = {}; +SWFUpload.movieCount = 0; +SWFUpload.version = "2.2.0 2009-03-25"; +SWFUpload.QUEUE_ERROR = { + QUEUE_LIMIT_EXCEEDED : -100, + FILE_EXCEEDS_SIZE_LIMIT : -110, + ZERO_BYTE_FILE : -120, + INVALID_FILETYPE : -130 +}; +SWFUpload.UPLOAD_ERROR = { + HTTP_ERROR : -200, + MISSING_UPLOAD_URL : -210, + IO_ERROR : -220, + SECURITY_ERROR : -230, + UPLOAD_LIMIT_EXCEEDED : -240, + UPLOAD_FAILED : -250, + SPECIFIED_FILE_ID_NOT_FOUND : -260, + FILE_VALIDATION_FAILED : -270, + FILE_CANCELLED : -280, + UPLOAD_STOPPED : -290 +}; +SWFUpload.FILE_STATUS = { + QUEUED : -1, + IN_PROGRESS : -2, + ERROR : -3, + COMPLETE : -4, + CANCELLED : -5 +}; +SWFUpload.BUTTON_ACTION = { + SELECT_FILE : -100, + SELECT_FILES : -110, + START_UPLOAD : -120 +}; +SWFUpload.CURSOR = { + ARROW : -1, + HAND : -2 +}; +SWFUpload.WINDOW_MODE = { + WINDOW : "window", + TRANSPARENT : "transparent", + OPAQUE : "opaque" +}; +SWFUpload.completeURL = function(url) { + if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) { + return url; + } + var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : ""); + var indexSlash = window.location.pathname.lastIndexOf("/"); + if (indexSlash <= 0) { + path = "/"; + } else { + path = window.location.pathname.substr(0, indexSlash) + "/"; + } + return /*currentURL +*/ path + url; +}; +/* ******************** */ +/* Instance Members */ +/* ******************** */ +SWFUpload.prototype.initSettings = function () { + this.ensureDefault = function (settingName, defaultValue) { + this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName]; + }; + this.ensureDefault("upload_url", ""); + this.ensureDefault("preserve_relative_urls", false); + this.ensureDefault("file_post_name", "Filedata"); + this.ensureDefault("post_params", {}); + this.ensureDefault("use_query_string", false); + this.ensureDefault("requeue_on_error", false); + this.ensureDefault("http_success", []); + this.ensureDefault("assume_success_timeout", 0); + this.ensureDefault("file_types", "*.*"); + this.ensureDefault("file_types_description", "All Files"); + this.ensureDefault("file_size_limit", 0); + this.ensureDefault("file_upload_limit", 0); + this.ensureDefault("file_queue_limit", 0); + this.ensureDefault("flash_url", "swfupload.swf"); + this.ensureDefault("prevent_swf_caching", true); + this.ensureDefault("button_image_url", ""); + this.ensureDefault("button_width", 1); + this.ensureDefault("button_height", 1); + this.ensureDefault("button_text", ""); + this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;"); + this.ensureDefault("button_text_top_padding", 0); + this.ensureDefault("button_text_left_padding", 0); + this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES); + this.ensureDefault("button_disabled", false); + this.ensureDefault("button_placeholder_id", ""); + this.ensureDefault("button_placeholder", null); + this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW); + this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW); + this.ensureDefault("debug", false); + this.settings.debug_enabled = this.settings.debug; + this.settings.return_upload_start_handler = this.returnUploadStart; + this.ensureDefault("swfupload_loaded_handler", null); + this.ensureDefault("file_dialog_start_handler", null); + this.ensureDefault("file_queued_handler", null); + this.ensureDefault("file_queue_error_handler", null); + this.ensureDefault("file_dialog_complete_handler", null); + this.ensureDefault("upload_start_handler", null); + this.ensureDefault("upload_progress_handler", null); + this.ensureDefault("upload_error_handler", null); + this.ensureDefault("upload_success_handler", null); + this.ensureDefault("upload_complete_handler", null); + this.ensureDefault("debug_handler", this.debugMessage); + this.ensureDefault("custom_settings", {}); + this.customSettings = this.settings.custom_settings; + if (!!this.settings.prevent_swf_caching) { + this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime(); + } + if (!this.settings.preserve_relative_urls) { + this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url); + this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url); + } + delete this.ensureDefault; +}; +SWFUpload.prototype.loadFlash = function () { + var targetElement, tempParent; + if (document.getElementById(this.movieName) !== null) { + throw "ID " + this.movieName + " is already in use. The Flash Object could not be added"; + } + targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder; + if (targetElement == undefined) { + throw "Could not find the placeholder element: " + this.settings.button_placeholder_id; + } + tempParent = document.createElement("div"); + tempParent.innerHTML = this.getFlashHTML(); + targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement); + if (window[this.movieName] == undefined) { + window[this.movieName] = this.getMovieElement(); + } +}; +SWFUpload.prototype.getFlashHTML = function () { + var classid = ''; + if (KindEditor.IE && KindEditor.V > 8) { + classid = ' classid = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"'; + } + return ['', + '', + '', + '', + '', + '', + '', + ''].join(""); +}; +SWFUpload.prototype.getFlashVars = function () { + var paramString = this.buildParamString(); + var httpSuccessString = this.settings.http_success.join(","); + return ["movieName=", encodeURIComponent(this.movieName), + "&uploadURL=", encodeURIComponent(this.settings.upload_url), + "&useQueryString=", encodeURIComponent(this.settings.use_query_string), + "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error), + "&httpSuccess=", encodeURIComponent(httpSuccessString), + "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout), + "&params=", encodeURIComponent(paramString), + "&filePostName=", encodeURIComponent(this.settings.file_post_name), + "&fileTypes=", encodeURIComponent(this.settings.file_types), + "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description), + "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit), + "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit), + "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit), + "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled), + "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url), + "&buttonWidth=", encodeURIComponent(this.settings.button_width), + "&buttonHeight=", encodeURIComponent(this.settings.button_height), + "&buttonText=", encodeURIComponent(this.settings.button_text), + "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding), + "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding), + "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style), + "&buttonAction=", encodeURIComponent(this.settings.button_action), + "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled), + "&buttonCursor=", encodeURIComponent(this.settings.button_cursor) + ].join(""); +}; +SWFUpload.prototype.getMovieElement = function () { + if (this.movieElement == undefined) { + this.movieElement = document.getElementById(this.movieName); + } + if (this.movieElement === null) { + throw "Could not find Flash element"; + } + return this.movieElement; +}; +SWFUpload.prototype.buildParamString = function () { + var postParams = this.settings.post_params; + var paramStringPairs = []; + if (typeof(postParams) === "object") { + for (var name in postParams) { + if (postParams.hasOwnProperty(name)) { + paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString())); + } + } + } + return paramStringPairs.join("&"); +}; +SWFUpload.prototype.destroy = function () { + try { + this.cancelUpload(null, false); + var movieElement = null; + movieElement = this.getMovieElement(); + if (movieElement && typeof(movieElement.CallFunction) === "unknown") { + for (var i in movieElement) { + try { + if (typeof(movieElement[i]) === "function") { + movieElement[i] = null; + } + } catch (ex1) {} + } + try { + movieElement.parentNode.removeChild(movieElement); + } catch (ex) {} + } + window[this.movieName] = null; + SWFUpload.instances[this.movieName] = null; + delete SWFUpload.instances[this.movieName]; + this.movieElement = null; + this.settings = null; + this.customSettings = null; + this.eventQueue = null; + this.movieName = null; + return true; + } catch (ex2) { + return false; + } +}; +SWFUpload.prototype.displayDebugInfo = function () { + this.debug( + [ + "---SWFUpload Instance Info---\n", + "Version: ", SWFUpload.version, "\n", + "Movie Name: ", this.movieName, "\n", + "Settings:\n", + "\t", "upload_url: ", this.settings.upload_url, "\n", + "\t", "flash_url: ", this.settings.flash_url, "\n", + "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n", + "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n", + "\t", "http_success: ", this.settings.http_success.join(", "), "\n", + "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n", + "\t", "file_post_name: ", this.settings.file_post_name, "\n", + "\t", "post_params: ", this.settings.post_params.toString(), "\n", + "\t", "file_types: ", this.settings.file_types, "\n", + "\t", "file_types_description: ", this.settings.file_types_description, "\n", + "\t", "file_size_limit: ", this.settings.file_size_limit, "\n", + "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n", + "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n", + "\t", "debug: ", this.settings.debug.toString(), "\n", + "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n", + "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n", + "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n", + "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n", + "\t", "button_width: ", this.settings.button_width.toString(), "\n", + "\t", "button_height: ", this.settings.button_height.toString(), "\n", + "\t", "button_text: ", this.settings.button_text.toString(), "\n", + "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n", + "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n", + "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n", + "\t", "button_action: ", this.settings.button_action.toString(), "\n", + "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n", + "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n", + "Event Handlers:\n", + "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n", + "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n", + "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n", + "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n", + "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n", + "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n", + "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n", + "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n", + "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n", + "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n" + ].join("") + ); +}; +/* Note: addSetting and getSetting are no longer used by SWFUpload but are included + the maintain v2 API compatibility +*/ +SWFUpload.prototype.addSetting = function (name, value, default_value) { + if (value == undefined) { + return (this.settings[name] = default_value); + } else { + return (this.settings[name] = value); + } +}; +SWFUpload.prototype.getSetting = function (name) { + if (this.settings[name] != undefined) { + return this.settings[name]; + } + return ""; +}; +SWFUpload.prototype.callFlash = function (functionName, argumentArray) { + argumentArray = argumentArray || []; + var movieElement = this.getMovieElement(); + var returnValue, returnString; + try { + returnString = movieElement.CallFunction('' + __flash__argumentsToXML(argumentArray, 0) + ''); + returnValue = eval(returnString); + } catch (ex) { + throw "Call to " + functionName + " failed"; + } + if (returnValue != undefined && typeof returnValue.post === "object") { + returnValue = this.unescapeFilePostParams(returnValue); + } + return returnValue; +}; +/* ***************************** + -- Flash control methods -- + Your UI should use these + to operate SWFUpload + ***************************** */ +SWFUpload.prototype.selectFile = function () { + this.callFlash("SelectFile"); +}; +SWFUpload.prototype.selectFiles = function () { + this.callFlash("SelectFiles"); +}; +SWFUpload.prototype.startUpload = function (fileID) { + this.callFlash("StartUpload", [fileID]); +}; +SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) { + if (triggerErrorEvent !== false) { + triggerErrorEvent = true; + } + this.callFlash("CancelUpload", [fileID, triggerErrorEvent]); +}; +SWFUpload.prototype.stopUpload = function () { + this.callFlash("StopUpload"); +}; +/* ************************ + * Settings methods + * These methods change the SWFUpload settings. + * SWFUpload settings should not be changed directly on the settings object + * since many of the settings need to be passed to Flash in order to take + * effect. + * *********************** */ +SWFUpload.prototype.getStats = function () { + return this.callFlash("GetStats"); +}; +SWFUpload.prototype.setStats = function (statsObject) { + this.callFlash("SetStats", [statsObject]); +}; +SWFUpload.prototype.getFile = function (fileID) { + if (typeof(fileID) === "number") { + return this.callFlash("GetFileByIndex", [fileID]); + } else { + return this.callFlash("GetFile", [fileID]); + } +}; +SWFUpload.prototype.addFileParam = function (fileID, name, value) { + return this.callFlash("AddFileParam", [fileID, name, value]); +}; +SWFUpload.prototype.removeFileParam = function (fileID, name) { + this.callFlash("RemoveFileParam", [fileID, name]); +}; +SWFUpload.prototype.setUploadURL = function (url) { + this.settings.upload_url = url.toString(); + this.callFlash("SetUploadURL", [url]); +}; +SWFUpload.prototype.setPostParams = function (paramsObject) { + this.settings.post_params = paramsObject; + this.callFlash("SetPostParams", [paramsObject]); +}; +SWFUpload.prototype.addPostParam = function (name, value) { + this.settings.post_params[name] = value; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; +SWFUpload.prototype.removePostParam = function (name) { + delete this.settings.post_params[name]; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; +SWFUpload.prototype.setFileTypes = function (types, description) { + this.settings.file_types = types; + this.settings.file_types_description = description; + this.callFlash("SetFileTypes", [types, description]); +}; +SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) { + this.settings.file_size_limit = fileSizeLimit; + this.callFlash("SetFileSizeLimit", [fileSizeLimit]); +}; +SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) { + this.settings.file_upload_limit = fileUploadLimit; + this.callFlash("SetFileUploadLimit", [fileUploadLimit]); +}; +SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) { + this.settings.file_queue_limit = fileQueueLimit; + this.callFlash("SetFileQueueLimit", [fileQueueLimit]); +}; +SWFUpload.prototype.setFilePostName = function (filePostName) { + this.settings.file_post_name = filePostName; + this.callFlash("SetFilePostName", [filePostName]); +}; +SWFUpload.prototype.setUseQueryString = function (useQueryString) { + this.settings.use_query_string = useQueryString; + this.callFlash("SetUseQueryString", [useQueryString]); +}; +SWFUpload.prototype.setRequeueOnError = function (requeueOnError) { + this.settings.requeue_on_error = requeueOnError; + this.callFlash("SetRequeueOnError", [requeueOnError]); +}; +SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) { + if (typeof http_status_codes === "string") { + http_status_codes = http_status_codes.replace(" ", "").split(","); + } + this.settings.http_success = http_status_codes; + this.callFlash("SetHTTPSuccess", [http_status_codes]); +}; +SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) { + this.settings.assume_success_timeout = timeout_seconds; + this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]); +}; +SWFUpload.prototype.setDebugEnabled = function (debugEnabled) { + this.settings.debug_enabled = debugEnabled; + this.callFlash("SetDebugEnabled", [debugEnabled]); +}; +SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) { + if (buttonImageURL == undefined) { + buttonImageURL = ""; + } + this.settings.button_image_url = buttonImageURL; + this.callFlash("SetButtonImageURL", [buttonImageURL]); +}; +SWFUpload.prototype.setButtonDimensions = function (width, height) { + this.settings.button_width = width; + this.settings.button_height = height; + var movie = this.getMovieElement(); + if (movie != undefined) { + movie.style.width = width + "px"; + movie.style.height = height + "px"; + } + this.callFlash("SetButtonDimensions", [width, height]); +}; +SWFUpload.prototype.setButtonText = function (html) { + this.settings.button_text = html; + this.callFlash("SetButtonText", [html]); +}; +SWFUpload.prototype.setButtonTextPadding = function (left, top) { + this.settings.button_text_top_padding = top; + this.settings.button_text_left_padding = left; + this.callFlash("SetButtonTextPadding", [left, top]); +}; +SWFUpload.prototype.setButtonTextStyle = function (css) { + this.settings.button_text_style = css; + this.callFlash("SetButtonTextStyle", [css]); +}; +SWFUpload.prototype.setButtonDisabled = function (isDisabled) { + this.settings.button_disabled = isDisabled; + this.callFlash("SetButtonDisabled", [isDisabled]); +}; +SWFUpload.prototype.setButtonAction = function (buttonAction) { + this.settings.button_action = buttonAction; + this.callFlash("SetButtonAction", [buttonAction]); +}; +SWFUpload.prototype.setButtonCursor = function (cursor) { + this.settings.button_cursor = cursor; + this.callFlash("SetButtonCursor", [cursor]); +}; +/* ******************************* + Flash Event Interfaces + These functions are used by Flash to trigger the various + events. + All these functions a Private. + Because the ExternalInterface library is buggy the event calls + are added to a queue and the queue then executed by a setTimeout. + This ensures that events are executed in a determinate order and that + the ExternalInterface bugs are avoided. +******************************* */ +SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) { + if (argumentArray == undefined) { + argumentArray = []; + } else if (!(argumentArray instanceof Array)) { + argumentArray = [argumentArray]; + } + var self = this; + if (typeof this.settings[handlerName] === "function") { + this.eventQueue.push(function () { + this.settings[handlerName].apply(this, argumentArray); + }); + setTimeout(function () { + self.executeNextEvent(); + }, 0); + } else if (this.settings[handlerName] !== null) { + throw "Event handler " + handlerName + " is unknown or is not a function"; + } +}; +SWFUpload.prototype.executeNextEvent = function () { + var f = this.eventQueue ? this.eventQueue.shift() : null; + if (typeof(f) === "function") { + f.apply(this); + } +}; +SWFUpload.prototype.unescapeFilePostParams = function (file) { + var reg = /[$]([0-9a-f]{4})/i; + var unescapedPost = {}; + var uk; + if (file != undefined) { + for (var k in file.post) { + if (file.post.hasOwnProperty(k)) { + uk = k; + var match; + while ((match = reg.exec(uk)) !== null) { + uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16))); + } + unescapedPost[uk] = file.post[k]; + } + } + file.post = unescapedPost; + } + return file; +}; +SWFUpload.prototype.testExternalInterface = function () { + try { + return this.callFlash("TestExternalInterface"); + } catch (ex) { + return false; + } +}; +SWFUpload.prototype.flashReady = function () { + var movieElement = this.getMovieElement(); + if (!movieElement) { + this.debug("Flash called back ready but the flash movie can't be found."); + return; + } + this.cleanUp(movieElement); + this.queueEvent("swfupload_loaded_handler"); +}; +SWFUpload.prototype.cleanUp = function (movieElement) { + try { + if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { + this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)"); + for (var key in movieElement) { + try { + if (typeof(movieElement[key]) === "function") { + movieElement[key] = null; + } + } catch (ex) { + } + } + } + } catch (ex1) { + } + window["__flash__removeCallback"] = function (instance, name) { + try { + if (instance) { + instance[name] = null; + } + } catch (flashEx) { + } + }; +}; +/* This is a chance to do something before the browse window opens */ +SWFUpload.prototype.fileDialogStart = function () { + this.queueEvent("file_dialog_start_handler"); +}; +/* Called when a file is successfully added to the queue. */ +SWFUpload.prototype.fileQueued = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queued_handler", file); +}; +/* Handle errors that occur when an attempt to queue a file fails. */ +SWFUpload.prototype.fileQueueError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queue_error_handler", [file, errorCode, message]); +}; +/* Called after the file dialog has closed and the selected files have been queued. + You could call startUpload here if you want the queued files to begin uploading immediately. */ +SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) { + this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]); +}; +SWFUpload.prototype.uploadStart = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("return_upload_start_handler", file); +}; +SWFUpload.prototype.returnUploadStart = function (file) { + var returnValue; + if (typeof this.settings.upload_start_handler === "function") { + file = this.unescapeFilePostParams(file); + returnValue = this.settings.upload_start_handler.call(this, file); + } else if (this.settings.upload_start_handler != undefined) { + throw "upload_start_handler must be a function"; + } + if (returnValue === undefined) { + returnValue = true; + } + returnValue = !!returnValue; + this.callFlash("ReturnUploadStart", [returnValue]); +}; +SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]); +}; +SWFUpload.prototype.uploadError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_error_handler", [file, errorCode, message]); +}; +SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_success_handler", [file, serverData, responseReceived]); +}; +SWFUpload.prototype.uploadComplete = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_complete_handler", file); +}; +/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the + internal debug console. You can override this event and have messages written where you want. */ +SWFUpload.prototype.debug = function (message) { + this.queueEvent("debug_handler", message); +}; +/* ********************************** + Debug Console + The debug console is a self contained, in page location + for debug message to be sent. The Debug Console adds + itself to the body if necessary. + The console is automatically scrolled as messages appear. + If you are using your own debug handler or when you deploy to production and + have debug disabled you can remove these functions to reduce the file size + and complexity. +********************************** */ +SWFUpload.prototype.debugMessage = function (message) { + if (this.settings.debug) { + var exceptionMessage, exceptionValues = []; + if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") { + for (var key in message) { + if (message.hasOwnProperty(key)) { + exceptionValues.push(key + ": " + message[key]); + } + } + exceptionMessage = exceptionValues.join("\n") || ""; + exceptionValues = exceptionMessage.split("\n"); + exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: "); + SWFUpload.Console.writeLine(exceptionMessage); + } else { + SWFUpload.Console.writeLine(message); + } + } +}; +SWFUpload.Console = {}; +SWFUpload.Console.writeLine = function (message) { + var console, documentForm; + try { + console = document.getElementById("SWFUpload_Console"); + if (!console) { + documentForm = document.createElement("form"); + document.getElementsByTagName("body")[0].appendChild(documentForm); + console = document.createElement("textarea"); + console.id = "SWFUpload_Console"; + console.style.fontFamily = "monospace"; + console.setAttribute("wrap", "off"); + console.wrap = "off"; + console.style.overflow = "auto"; + console.style.width = "700px"; + console.style.height = "350px"; + console.style.margin = "5px"; + documentForm.appendChild(console); + } + console.value += message + "\n"; + console.scrollTop = console.scrollHeight - console.clientHeight; + } catch (ex) { + alert("Exception: " + ex.name + " Message: " + ex.message); + } +}; +})(); +(function() { +/* + Queue Plug-in + Features: + *Adds a cancelQueue() method for cancelling the entire queue. + *All queued files are uploaded when startUpload() is called. + *If false is returned from uploadComplete then the queue upload is stopped. + If false is not returned (strict comparison) then the queue upload is continued. + *Adds a QueueComplete event that is fired when all the queued files have finished uploading. + Set the event handler with the queue_complete_handler setting. + */ +if (typeof(SWFUpload) === "function") { + SWFUpload.queue = {}; + SWFUpload.prototype.initSettings = (function (oldInitSettings) { + return function () { + if (typeof(oldInitSettings) === "function") { + oldInitSettings.call(this); + } + this.queueSettings = {}; + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler; + this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler; + this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler; + this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler; + this.settings.queue_complete_handler = this.settings.queue_complete_handler || null; + }; + })(SWFUpload.prototype.initSettings); + SWFUpload.prototype.startUpload = function (fileID) { + this.queueSettings.queue_cancelled_flag = false; + this.callFlash("StartUpload", [fileID]); + }; + SWFUpload.prototype.cancelQueue = function () { + this.queueSettings.queue_cancelled_flag = true; + this.stopUpload(); + var stats = this.getStats(); + while (stats.files_queued > 0) { + this.cancelUpload(); + stats = this.getStats(); + } + }; + SWFUpload.queue.uploadStartHandler = function (file) { + var returnValue; + if (typeof(this.queueSettings.user_upload_start_handler) === "function") { + returnValue = this.queueSettings.user_upload_start_handler.call(this, file); + } + returnValue = (returnValue === false) ? false : true; + this.queueSettings.queue_cancelled_flag = !returnValue; + return returnValue; + }; + SWFUpload.queue.uploadCompleteHandler = function (file) { + var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler; + var continueUpload; + if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) { + this.queueSettings.queue_upload_count++; + } + if (typeof(user_upload_complete_handler) === "function") { + continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true; + } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) { + continueUpload = false; + } else { + continueUpload = true; + } + if (continueUpload) { + var stats = this.getStats(); + if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) { + this.startUpload(); + } else if (this.queueSettings.queue_cancelled_flag === false) { + this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]); + this.queueSettings.queue_upload_count = 0; + } else { + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + } + } + }; +} +})(); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('pagebreak', function(K) { + var self = this; + var name = 'pagebreak'; + var pagebreakHtml = K.undef(self.pagebreakHtml, '
      '); + self.clickToolbar(name, function() { + var cmd = self.cmd, range = cmd.range; + self.focus(); + var tail = self.newlineTag == 'br' || K.WEBKIT ? '' : ''; + self.insertHtml(pagebreakHtml + tail); + if (tail !== '') { + var p = K('#__kindeditor_tail_tag__', self.edit.doc); + range.selectNodeContents(p[0]); + p.removeAttr('id'); + cmd.select(); + } + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('plainpaste', function(K) { + var self = this, name = 'plainpaste'; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = '
      ' + + '
      ' + lang.comment + '
      ' + + '' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var html = textarea.val(); + html = K.escape(html); + html = html.replace(/ {2}/g, '  '); + if (self.newlineTag == 'p') { + html = html.replace(/^/, '

      ').replace(/$/, '

      ').replace(/\n/g, '

      '); + } else { + html = html.replace(/\n/g, '
      $&'); + } + self.insertHtml(html).hideDialog().focus(); + } + } + }), + textarea = K('textarea', dialog.div); + textarea[0].focus(); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('preview', function(K) { + var self = this, name = 'preview', undefined; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = '

      ' + + '' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 750, + title : self.lang(name), + body : html + }), + iframe = K('iframe', dialog.div), + doc = K.iframeDoc(iframe); + doc.open(); + doc.write(self.fullHtml()); + doc.close(); + K(doc.body).css('background-color', '#FFF'); + iframe[0].contentWindow.focus(); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('quickformat', function(K) { + var self = this, name = 'quickformat', + blockMap = K.toMap('blockquote,center,div,h1,h2,h3,h4,h5,h6,p'); + function getFirstChild(knode) { + var child = knode.first(); + while (child && child.first()) { + child = child.first(); + } + return child; + } + self.clickToolbar(name, function() { + self.focus(); + var doc = self.edit.doc, + range = self.cmd.range, + child = K(doc.body).first(), next, + nodeList = [], subList = [], + bookmark = range.createBookmark(true); + while(child) { + next = child.next(); + var firstChild = getFirstChild(child); + if (!firstChild || firstChild.name != 'img') { + if (blockMap[child.name]) { + child.html(child.html().replace(/^(\s| | )+/ig, '')); + child.css('text-indent', '2em'); + } else { + subList.push(child); + } + if (!next || (blockMap[next.name] || blockMap[child.name] && !blockMap[next.name])) { + if (subList.length > 0) { + nodeList.push(subList); + } + subList = []; + } + } + child = next; + } + K.each(nodeList, function(i, subList) { + var wrapper = K('

      ', doc); + subList[0].before(wrapper); + K.each(subList, function(i, knode) { + wrapper.append(knode); + }); + }); + range.moveToBookmark(bookmark); + self.addBookmark(); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('table', function(K) { + var self = this, name = 'table', lang = self.lang(name + '.'), zeroborder = 'ke-zeroborder'; + function _setColor(box, color) { + color = color.toUpperCase(); + box.css('background-color', color); + box.css('color', color === '#000000' ? '#FFFFFF' : '#000000'); + box.html(color); + } + var pickerList = []; + function _initColorPicker(dialogDiv, colorBox) { + colorBox.bind('click,mousedown', function(e){ + e.stopPropagation(); + }); + function removePicker() { + K.each(pickerList, function() { + this.remove(); + }); + pickerList = []; + K(document).unbind('click,mousedown', removePicker); + dialogDiv.unbind('click,mousedown', removePicker); + } + colorBox.click(function(e) { + removePicker(); + var box = K(this), + pos = box.pos(); + var picker = K.colorpicker({ + x : pos.x, + y : pos.y + box.height(), + z : 811214, + selectedColor : K(this).html(), + colors : self.colorTable, + noColor : self.lang('noColor'), + shadowMode : self.shadowMode, + click : function(color) { + _setColor(box, color); + removePicker(); + } + }); + pickerList.push(picker); + K(document).bind('click,mousedown', removePicker); + dialogDiv.bind('click,mousedown', removePicker); + }); + } + function _getCellIndex(table, row, cell) { + var rowSpanCount = 0; + for (var i = 0, len = row.cells.length; i < len; i++) { + if (row.cells[i] == cell) { + break; + } + rowSpanCount += row.cells[i].rowSpan - 1; + } + return cell.cellIndex - rowSpanCount; + } + self.plugin.table = { + prop : function(isInsert) { + var html = [ + '
      ', + '
      ', + '', + lang.rows + '   ', + lang.cols + ' ', + '
      ', + '
      ', + '', + lang.width + '   ', + '   ', + lang.height + '   ', + '', + '
      ', + '
      ', + '', + lang.padding + '   ', + lang.spacing + ' ', + '
      ', + '
      ', + '', + '', + '
      ', + '
      ', + '', + lang.borderWidth + '   ', + lang.borderColor + ' ', + '
      ', + '
      ', + '', + '', + '
      ', + '
      ' + ].join(''); + var bookmark = self.cmd.range.createBookmark(); + var dialog = self.createDialog({ + name : name, + width : 500, + title : self.lang(name), + body : html, + beforeRemove : function() { + colorBox.unbind(); + }, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var rows = rowsBox.val(), + cols = colsBox.val(), + width = widthBox.val(), + height = heightBox.val(), + widthType = widthTypeBox.val(), + heightType = heightTypeBox.val(), + padding = paddingBox.val(), + spacing = spacingBox.val(), + align = alignBox.val(), + border = borderBox.val(), + borderColor = K(colorBox[0]).html() || '', + bgColor = K(colorBox[1]).html() || ''; + if (rows == 0 || !/^\d+$/.test(rows)) { + alert(self.lang('invalidRows')); + rowsBox[0].focus(); + return; + } + if (cols == 0 || !/^\d+$/.test(cols)) { + alert(self.lang('invalidRows')); + colsBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + if (!/^\d*$/.test(padding)) { + alert(self.lang('invalidPadding')); + paddingBox[0].focus(); + return; + } + if (!/^\d*$/.test(spacing)) { + alert(self.lang('invalidSpacing')); + spacingBox[0].focus(); + return; + } + if (!/^\d*$/.test(border)) { + alert(self.lang('invalidBorder')); + borderBox[0].focus(); + return; + } + if (table) { + if (width !== '') { + table.width(width + widthType); + } else { + table.css('width', ''); + } + if (table[0].width !== undefined) { + table.removeAttr('width'); + } + if (height !== '') { + table.height(height + heightType); + } else { + table.css('height', ''); + } + if (table[0].height !== undefined) { + table.removeAttr('height'); + } + table.css('background-color', bgColor); + if (table[0].bgColor !== undefined) { + table.removeAttr('bgColor'); + } + if (padding !== '') { + table[0].cellPadding = padding; + } else { + table.removeAttr('cellPadding'); + } + if (spacing !== '') { + table[0].cellSpacing = spacing; + } else { + table.removeAttr('cellSpacing'); + } + if (align !== '') { + table[0].align = align; + } else { + table.removeAttr('align'); + } + if (border !== '') { + table.attr('border', border); + } else { + table.removeAttr('border'); + } + if (border === '' || border === '0') { + table.addClass(zeroborder); + } else { + table.removeClass(zeroborder); + } + if (borderColor !== '') { + table.attr('borderColor', borderColor); + } else { + table.removeAttr('borderColor'); + } + self.hideDialog().focus(); + self.cmd.range.moveToBookmark(bookmark); + self.cmd.select(); + self.addBookmark(); + return; + } + var style = ''; + if (width !== '') { + style += 'width:' + width + widthType + ';'; + } + if (height !== '') { + style += 'height:' + height + heightType + ';'; + } + if (bgColor !== '') { + style += 'background-color:' + bgColor + ';'; + } + var html = '') + ''; + } + html += ''; + } + html += ''; + if (!K.IE) { + html += '
      '; + } + self.insertHtml(html); + self.select().hideDialog().focus(); + self.addBookmark(); + } + } + }), + div = dialog.div, + rowsBox = K('[name="rows"]', div).val(3), + colsBox = K('[name="cols"]', div).val(2), + widthBox = K('[name="width"]', div).val(100), + heightBox = K('[name="height"]', div), + widthTypeBox = K('[name="widthType"]', div), + heightTypeBox = K('[name="heightType"]', div), + paddingBox = K('[name="padding"]', div).val(2), + spacingBox = K('[name="spacing"]', div).val(0), + alignBox = K('[name="align"]', div), + borderBox = K('[name="border"]', div).val(1), + colorBox = K('.ke-input-color', div); + _initColorPicker(div, colorBox.eq(0)); + _initColorPicker(div, colorBox.eq(1)); + _setColor(colorBox.eq(0), '#000000'); + _setColor(colorBox.eq(1), ''); + rowsBox[0].focus(); + rowsBox[0].select(); + var table; + if (isInsert) { + return; + } + table = self.plugin.getSelectedTable(); + if (table) { + rowsBox.val(table[0].rows.length); + colsBox.val(table[0].rows.length > 0 ? table[0].rows[0].cells.length : 0); + rowsBox.attr('disabled', true); + colsBox.attr('disabled', true); + var match, + tableWidth = table[0].style.width || table[0].width, + tableHeight = table[0].style.height || table[0].height; + if (tableWidth !== undefined && (match = /^(\d+)((?:px|%)*)$/.exec(tableWidth))) { + widthBox.val(match[1]); + widthTypeBox.val(match[2]); + } else { + widthBox.val(''); + } + if (tableHeight !== undefined && (match = /^(\d+)((?:px|%)*)$/.exec(tableHeight))) { + heightBox.val(match[1]); + heightTypeBox.val(match[2]); + } + paddingBox.val(table[0].cellPadding || ''); + spacingBox.val(table[0].cellSpacing || ''); + alignBox.val(table[0].align || ''); + borderBox.val(table[0].border === undefined ? '' : table[0].border); + _setColor(colorBox.eq(0), K.toHex(table.attr('borderColor') || '')); + _setColor(colorBox.eq(1), K.toHex(table[0].style.backgroundColor || table[0].bgColor || '')); + widthBox[0].focus(); + widthBox[0].select(); + } + }, + cellprop : function() { + var html = [ + '
      ', + '
      ', + '', + lang.width + '   ', + '   ', + lang.height + '   ', + '', + '
      ', + '
      ', + '', + lang.textAlign + ' ', + lang.verticalAlign + ' ', + '
      ', + '
      ', + '', + lang.borderWidth + '   ', + lang.borderColor + ' ', + '
      ', + '
      ', + '', + '', + '
      ', + '
      ' + ].join(''); + var bookmark = self.cmd.range.createBookmark(); + var dialog = self.createDialog({ + name : name, + width : 500, + title : self.lang('tablecell'), + body : html, + beforeRemove : function() { + colorBox.unbind(); + }, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var width = widthBox.val(), + height = heightBox.val(), + widthType = widthTypeBox.val(), + heightType = heightTypeBox.val(), + padding = paddingBox.val(), + spacing = spacingBox.val(), + textAlign = textAlignBox.val(), + verticalAlign = verticalAlignBox.val(), + border = borderBox.val(), + borderColor = K(colorBox[0]).html() || '', + bgColor = K(colorBox[1]).html() || ''; + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + if (!/^\d*$/.test(border)) { + alert(self.lang('invalidBorder')); + borderBox[0].focus(); + return; + } + cell.css({ + width : width !== '' ? (width + widthType) : '', + height : height !== '' ? (height + heightType) : '', + 'background-color' : bgColor, + 'text-align' : textAlign, + 'vertical-align' : verticalAlign, + 'border-width' : border, + 'border-style' : border !== '' ? 'solid' : '', + 'border-color' : borderColor + }); + self.hideDialog().focus(); + self.cmd.range.moveToBookmark(bookmark); + self.cmd.select(); + self.addBookmark(); + } + } + }), + div = dialog.div, + widthBox = K('[name="width"]', div).val(100), + heightBox = K('[name="height"]', div), + widthTypeBox = K('[name="widthType"]', div), + heightTypeBox = K('[name="heightType"]', div), + paddingBox = K('[name="padding"]', div).val(2), + spacingBox = K('[name="spacing"]', div).val(0), + textAlignBox = K('[name="textAlign"]', div), + verticalAlignBox = K('[name="verticalAlign"]', div), + borderBox = K('[name="border"]', div).val(1), + colorBox = K('.ke-input-color', div); + _initColorPicker(div, colorBox.eq(0)); + _initColorPicker(div, colorBox.eq(1)); + _setColor(colorBox.eq(0), '#000000'); + _setColor(colorBox.eq(1), ''); + widthBox[0].focus(); + widthBox[0].select(); + var cell = self.plugin.getSelectedCell(); + var match, + cellWidth = cell[0].style.width || cell[0].width || '', + cellHeight = cell[0].style.height || cell[0].height || ''; + if ((match = /^(\d+)((?:px|%)*)$/.exec(cellWidth))) { + widthBox.val(match[1]); + widthTypeBox.val(match[2]); + } else { + widthBox.val(''); + } + if ((match = /^(\d+)((?:px|%)*)$/.exec(cellHeight))) { + heightBox.val(match[1]); + heightTypeBox.val(match[2]); + } + textAlignBox.val(cell[0].style.textAlign || ''); + verticalAlignBox.val(cell[0].style.verticalAlign || ''); + var border = cell[0].style.borderWidth || ''; + if (border) { + border = parseInt(border); + } + borderBox.val(border); + _setColor(colorBox.eq(0), K.toHex(cell[0].style.borderColor || '')); + _setColor(colorBox.eq(1), K.toHex(cell[0].style.backgroundColor || '')); + widthBox[0].focus(); + widthBox[0].select(); + }, + insert : function() { + this.prop(true); + }, + 'delete' : function() { + var table = self.plugin.getSelectedTable(); + self.cmd.range.setStartBefore(table[0]).collapse(true); + self.cmd.select(); + table.remove(); + self.addBookmark(); + }, + colinsert : function(offset) { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + index = cell.cellIndex + offset; + index += table.rows[0].cells.length - row.cells.length; + for (var i = 0, len = table.rows.length; i < len; i++) { + var newRow = table.rows[i], + newCell = newRow.insertCell(index); + newCell.innerHTML = K.IE ? '' : '
      '; + index = _getCellIndex(table, newRow, newCell); + } + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + colinsertleft : function() { + this.colinsert(0); + }, + colinsertright : function() { + this.colinsert(1); + }, + rowinsert : function(offset) { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0]; + var rowIndex = row.rowIndex; + if (offset === 1) { + rowIndex = row.rowIndex + (cell.rowSpan - 1) + offset; + } + var newRow = table.insertRow(rowIndex); + for (var i = 0, len = row.cells.length; i < len; i++) { + if (row.cells[i].rowSpan > 1) { + len -= row.cells[i].rowSpan - 1; + } + var newCell = newRow.insertCell(i); + if (offset === 1 && row.cells[i].colSpan > 1) { + newCell.colSpan = row.cells[i].colSpan; + } + newCell.innerHTML = K.IE ? '' : '
      '; + } + for (var j = rowIndex; j >= 0; j--) { + var cells = table.rows[j].cells; + if (cells.length > i) { + for (var k = cell.cellIndex; k >= 0; k--) { + if (cells[k].rowSpan > 1) { + cells[k].rowSpan += 1; + } + } + break; + } + } + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + rowinsertabove : function() { + this.rowinsert(0); + }, + rowinsertbelow : function() { + this.rowinsert(1); + }, + rowmerge : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex, + nextRowIndex = rowIndex + cell.rowSpan, + nextRow = table.rows[nextRowIndex]; + if (table.rows.length <= nextRowIndex) { + return; + } + var cellIndex = cell.cellIndex; + if (nextRow.cells.length <= cellIndex) { + return; + } + var nextCell = nextRow.cells[cellIndex]; + if (cell.colSpan !== nextCell.colSpan) { + return; + } + cell.rowSpan += nextCell.rowSpan; + nextRow.deleteCell(cellIndex); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + colmerge : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex, + cellIndex = cell.cellIndex, + nextCellIndex = cellIndex + 1; + if (row.cells.length <= nextCellIndex) { + return; + } + var nextCell = row.cells[nextCellIndex]; + if (cell.rowSpan !== nextCell.rowSpan) { + return; + } + cell.colSpan += nextCell.colSpan; + row.deleteCell(nextCellIndex); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + rowsplit : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex; + if (cell.rowSpan === 1) { + return; + } + var cellIndex = _getCellIndex(table, row, cell); + for (var i = 1, len = cell.rowSpan; i < len; i++) { + var newRow = table.rows[rowIndex + i], + newCell = newRow.insertCell(cellIndex); + if (cell.colSpan > 1) { + newCell.colSpan = cell.colSpan; + } + newCell.innerHTML = K.IE ? '' : '
      '; + cellIndex = _getCellIndex(table, newRow, newCell); + } + K(cell).removeAttr('rowSpan'); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + colsplit : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + cellIndex = cell.cellIndex; + if (cell.colSpan === 1) { + return; + } + for (var i = 1, len = cell.colSpan; i < len; i++) { + var newCell = row.insertCell(cellIndex + i); + if (cell.rowSpan > 1) { + newCell.rowSpan = cell.rowSpan; + } + newCell.innerHTML = K.IE ? '' : '
      '; + } + K(cell).removeAttr('colSpan'); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + coldelete : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + index = cell.cellIndex; + for (var i = 0, len = table.rows.length; i < len; i++) { + var newRow = table.rows[i], + newCell = newRow.cells[index]; + if (newCell.colSpan > 1) { + newCell.colSpan -= 1; + if (newCell.colSpan === 1) { + K(newCell).removeAttr('colSpan'); + } + } else { + newRow.deleteCell(index); + } + if (newCell.rowSpan > 1) { + i += newCell.rowSpan - 1; + } + } + if (row.cells.length === 0) { + self.cmd.range.setStartBefore(table).collapse(true); + self.cmd.select(); + K(table).remove(); + } else { + self.cmd.selection(true); + } + self.addBookmark(); + }, + rowdelete : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex; + for (var i = cell.rowSpan - 1; i >= 0; i--) { + table.deleteRow(rowIndex + i); + } + if (table.rows.length === 0) { + self.cmd.range.setStartBefore(table).collapse(true); + self.cmd.select(); + K(table).remove(); + } else { + self.cmd.selection(true); + } + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.table.prop); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('template', function(K) { + var self = this, name = 'template', lang = self.lang(name + '.'), + htmlPath = self.pluginsPath + name + '/html/'; + function getFilePath(fileName) { + return htmlPath + fileName + '?ver=' + encodeURIComponent(K.DEBUG ? K.TIME : K.VERSION); + } + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + arr = ['
      ', + '
      ', + '
      ', + lang. selectTemplate + '
      ', + '
      ', + ' ', + '
      ', + '
      ', + '
      ', + '', + '
      '].join(''); + var dialog = self.createDialog({ + name : name, + width : 500, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var doc = K.iframeDoc(iframe); + self[checkbox[0].checked ? 'html' : 'insertHtml'](doc.body.innerHTML).hideDialog().focus(); + } + } + }); + var selectBox = K('select', dialog.div), + checkbox = K('[name="replaceFlag"]', dialog.div), + iframe = K('iframe', dialog.div); + checkbox[0].checked = true; + iframe.attr('src', getFilePath(selectBox.val())); + selectBox.change(function() { + iframe.attr('src', getFilePath(this.value)); + }); + }); +}); + +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ +KindEditor.plugin('wordpaste', function(K) { + var self = this, name = 'wordpaste'; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = '
      ' + + '
      ' + lang.comment + '
      ' + + '' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var str = doc.body.innerHTML; + str = K.clearMsWord(str, self.filterMode ? self.htmlTags : K.options.htmlTags); + self.insertHtml(str).hideDialog().focus(); + } + } + }), + div = dialog.div, + iframe = K('iframe', div), + doc = K.iframeDoc(iframe); + if (!K.IE) { + doc.designMode = 'on'; + } + doc.open(); + doc.write('WordPaste'); + doc.write(''); + if (!K.IE) { + doc.write('
      '); + } + doc.write(''); + doc.close(); + if (K.IE) { + doc.body.contentEditable = 'true'; + } + iframe[0].contentWindow.focus(); + }); +}); + + +KindEditor.plugin('fixtoolbar', function (K) { + var self = this; + if (!self.fixToolBar) { + return; + } + function init() { + var toolbar = K('.ke-toolbar'); + var originY = toolbar.pos().y; + K(window).bind('scroll', function () { + if (toolbar.css('position') == 'fixed') { + if(document.body.scrollTop - originY < 0){ + toolbar.css('position', 'static'); + toolbar.css('top', 'auto'); + } + } else { + if (toolbar.pos().y - document.body.scrollTop < 0) { + toolbar.css('position', 'fixed'); + toolbar.css('top', 0); + } + } + }); + } + if (self.isCreated) { + init(); + } else { + self.afterCreate(init); + } +}); diff --git a/php/kindeditor_demo/kindeditor/lang/ar.js b/php/kindeditor_demo/kindeditor/lang/ar.js new file mode 100755 index 0000000..99dcfd6 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lang/ar.js @@ -0,0 +1,242 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +* Arabic Translation By daif alotaibi (http://daif.net/) +*******************************************************************************/ + +KindEditor.lang({ + source : 'عرض المصدر', + preview : 'معاينة الصفحة', + undo : 'تراجع(Ctrl+Z)', + redo : 'إعادة التراجع(Ctrl+Y)', + cut : 'قص(Ctrl+X)', + copy : 'نسخ(Ctrl+C)', + paste : 'لصق(Ctrl+V)', + plainpaste : 'لصق كنص عادي', + wordpaste : 'لصق من مايكروسفت ورد', + selectall : 'تحديد الكل', + justifyleft : 'محاذاه لليسار', + justifycenter : 'محاذاه للوسط', + justifyright : 'محاذاه لليمين', + justifyfull : 'محاذاه تلقائية', + insertorderedlist : 'قائمة مرقمه', + insertunorderedlist : 'قائمة نقطية', + indent : 'إزاحه النص', + outdent : 'إلغاء الازاحة', + subscript : 'أسفل النص', + superscript : 'أعلى النص', + formatblock : 'Paragraph format', + fontname : 'نوع الخط', + fontsize : 'حجم الخط', + forecolor : 'لون النص', + hilitecolor : 'لون خلفية النص', + bold : 'عريض(Ctrl+B)', + italic : 'مائل(Ctrl+I)', + underline : 'خط تحت النص(Ctrl+U)', + strikethrough : 'خط على النص', + removeformat : 'إزالة التنسيق', + image : 'إدراج صورة', + multiimage : 'Multi image', + flash : 'إدراج فلاش', + media : 'إدراج وسائط متعددة', + table : 'إدراج جدول', + tablecell : 'خلية', + hr : 'إدراج خط أفقي', + emoticons : 'إدراج وجه ضاحك', + link : 'رابط', + unlink : 'إزالة الرابط', + fullscreen : 'محرر ملئ الشاشة', + about : 'حول', + print : 'طباعة', + filemanager : 'مدير الملفات', + code : 'إدراج نص برمجي', + map : 'خرائط قووقل', + baidumap : 'خرائط قووقل', + lineheight : 'إرتفاع السطر', + clearhtml : 'مسح كود HTML', + pagebreak : 'إدراج فاصل صفحات', + quickformat : 'تنسيق سريع', + insertfile : 'إدراج ملف', + template : 'إدراج قالب', + anchor : 'رابط', + yes : 'موافق', + no : 'إلغاء', + close : 'إغلاق', + editImage : 'خصائص الصورة', + deleteImage : 'حذفالصورة', + editFlash : 'خصائص الفلاش', + deleteFlash : 'حذف الفلاش', + editMedia : 'خصائص الوسائط', + deleteMedia : 'حذف الوسائط', + editLink : 'خصائص الرابط', + deleteLink : 'إزالة الرابط', + editAnchor : 'Anchor properties', + deleteAnchor : 'Delete Anchor', + tableprop : 'خصائص الجدول', + tablecellprop : 'خصائص الخلية', + tableinsert : 'إدراج جدول', + tabledelete : 'حذف جدول', + tablecolinsertleft : 'إدراج عمود لليسار', + tablecolinsertright : 'إدراج عمود لليسار', + tablerowinsertabove : 'إدراج صف للأعلى', + tablerowinsertbelow : 'إدراج صف للأسفل', + tablerowmerge : 'دمج للأسفل', + tablecolmerge : 'دمج لليمين', + tablerowsplit : 'تقسم الصف', + tablecolsplit : 'تقسيم العمود', + tablecoldelete : 'حذف العمود', + tablerowdelete : 'حذف الصف', + noColor : 'إفتراضي', + pleaseSelectFile : 'Please select file.', + invalidImg : "الرجاء إدخال رابط صحيح.\nالملفات المسموح بها: jpg,gif,bmp,png", + invalidMedia : "الرجاء إدخال رابط صحيح.\nالملفات المسموح بها: swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb", + invalidWidth : "العرض يجب أن يكون رقم.", + invalidHeight : "الإرتفاع يجب أن يكون رقم.", + invalidBorder : "عرض الحد يجب أن يكون رقم.", + invalidUrl : "الرجاء إدخال رابط حيح.", + invalidRows : 'صفوف غير صحيح.', + invalidCols : 'أعمدة غير صحيحة.', + invalidPadding : 'The padding must be number.', + invalidSpacing : 'The spacing must be number.', + invalidJson : 'Invalid JSON string.', + uploadSuccess : 'تم رفع الملف بنجاح.', + cutError : 'حاليا غير مدعومة من المتصفح, إستخدم إختصار لوحة المفاتيح (Ctrl+X).', + copyError : 'حاليا غير مدعومة من المتصفح, إستخدم إختصار لوحة المفاتيح (Ctrl+C).', + pasteError : 'حاليا غير مدعومة من المتصفح, إستخدم إختصار لوحة المفاتيح (Ctrl+V).', + ajaxLoading : 'Loading ...', + uploadLoading : 'Uploading ...', + uploadError : 'Upload Error', + 'plainpaste.comment' : 'إستخدم إختصار لوحة المفاتيح (Ctrl+V) للصق داخل النافذة.', + 'wordpaste.comment' : 'إستخدم إختصار لوحة المفاتيح (Ctrl+V) للصق داخل النافذة.', + 'code.pleaseInput' : 'Please input code.', + 'link.url' : 'الرابط', + 'link.linkType' : 'الهدف', + 'link.newWindow' : 'نافذة جديدة', + 'link.selfWindow' : 'نفس النافذة', + 'flash.url' : 'الرابط', + 'flash.width' : 'العرض', + 'flash.height' : 'الإرتفاع', + 'flash.upload' : 'رفع', + 'flash.viewServer' : 'أستعراض', + 'media.url' : 'الرابط', + 'media.width' : 'العرض', + 'media.height' : 'الإرتفاع', + 'media.autostart' : 'تشغيل تلقائي', + 'media.upload' : 'رفع', + 'media.viewServer' : 'أستعراض', + 'image.remoteImage' : 'إدراج الرابط', + 'image.localImage' : 'رفع', + 'image.remoteUrl' : 'الرابط', + 'image.localUrl' : 'الملف', + 'image.size' : 'الحجم', + 'image.width' : 'العرض', + 'image.height' : 'الإرتفاع', + 'image.resetSize' : 'إستعادة الأبعاد', + 'image.align' : 'محاذاة', + 'image.defaultAlign' : 'الإفتراضي', + 'image.leftAlign' : 'اليسار', + 'image.rightAlign' : 'اليمين', + 'image.imgTitle' : 'العنوان', + 'image.upload' : 'أستعراض', + 'image.viewServer' : 'أستعراض', + 'multiimage.uploadDesc' : 'Allows users to upload <%=uploadLimit%> images, single image size not exceeding <%=sizeLimit%>', + 'multiimage.startUpload' : 'Start upload', + 'multiimage.clearAll' : 'Clear all', + 'multiimage.insertAll' : 'Insert all', + 'multiimage.queueLimitExceeded' : 'Queue limit exceeded.', + 'multiimage.fileExceedsSizeLimit' : 'File exceeds size limit.', + 'multiimage.zeroByteFile' : 'Zero byte file.', + 'multiimage.invalidFiletype' : 'Invalid file type.', + 'multiimage.unknownError' : 'Unknown upload error.', + 'multiimage.pending' : 'Pending ...', + 'multiimage.uploadError' : 'Upload error', + 'filemanager.emptyFolder' : 'فارغ', + 'filemanager.moveup' : 'المجلد الأب', + 'filemanager.viewType' : 'العرض: ', + 'filemanager.viewImage' : 'مصغرات', + 'filemanager.listImage' : 'قائمة', + 'filemanager.orderType' : 'الترتيب: ', + 'filemanager.fileName' : 'بالإسم', + 'filemanager.fileSize' : 'بالحجم', + 'filemanager.fileType' : 'بالنوع', + 'insertfile.url' : 'الرابط', + 'insertfile.title' : 'العنوان', + 'insertfile.upload' : 'رفع', + 'insertfile.viewServer' : 'أستعراض', + 'table.cells' : 'خلايا', + 'table.rows' : 'صفوف', + 'table.cols' : 'أعمدة', + 'table.size' : 'الأبعاد', + 'table.width' : 'العرض', + 'table.height' : 'الإرتفاع', + 'table.percent' : '%', + 'table.px' : 'px', + 'table.space' : 'الخارج', + 'table.padding' : 'الداخل', + 'table.spacing' : 'الفراغات', + 'table.align' : 'محاذاه', + 'table.textAlign' : 'افقى', + 'table.verticalAlign' : 'رأسي', + 'table.alignDefault' : 'إفتراضي', + 'table.alignLeft' : 'يسار', + 'table.alignCenter' : 'وسط', + 'table.alignRight' : 'يمين', + 'table.alignTop' : 'أعلى', + 'table.alignMiddle' : 'منتصف', + 'table.alignBottom' : 'أسفل', + 'table.alignBaseline' : 'Baseline', + 'table.border' : 'الحدود', + 'table.borderWidth' : 'العرض', + 'table.borderColor' : 'اللون', + 'table.backgroundColor' : 'الخلفية', + 'map.address' : 'العنوان: ', + 'map.search' : 'بحث', + 'baidumap.address' : 'العنوان: ', + 'baidumap.search' : 'بحث', + 'baidumap.insertDynamicMap' : 'Dynamic Map', + 'anchor.name' : 'إسم الرابط', + 'formatblock.formatBlock' : { + h1 : 'عنوان 1', + h2 : 'عنوان 2', + h3 : 'عنوان 3', + h4 : 'عنوان 4', + p : 'عادي' + }, + 'fontname.fontName' : { + 'Arial' : 'Arial', + 'Arial Black' : 'Arial Black', + 'Comic Sans MS' : 'Comic Sans MS', + 'Courier New' : 'Courier New', + 'Garamond' : 'Garamond', + 'Georgia' : 'Georgia', + 'Tahoma' : 'Tahoma', + 'Times New Roman' : 'Times New Roman', + 'Trebuchet MS' : 'Trebuchet MS', + 'Verdana' : 'Verdana' + }, + 'lineheight.lineHeight' : [ + {'1' : 'إرتفاع السطر 1'}, + {'1.5' : 'إرتفاع السطر 1.5'}, + {'2' : 'إرتفاع السطر 2'}, + {'2.5' : 'إرتفاع السطر 2.5'}, + {'3' : 'إرتفاع السطر 3'} + ], + 'template.selectTemplate' : 'قالب', + 'template.replaceContent' : 'إستبدال المحتوى الحالي', + 'template.fileList' : { + '1.html' : 'صورة ونص', + '2.html' : 'جدول', + '3.html' : 'قائمة' + } +}, 'ar'); + +KindEditor.each(KindEditor.options.items, function(i, name) { + if (name == 'baidumap') { + KindEditor.options.items[i] = 'map'; + } +}); +KindEditor.options.langType = 'ar'; \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lang/en.js b/php/kindeditor_demo/kindeditor/lang/en.js new file mode 100755 index 0000000..909bf49 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lang/en.js @@ -0,0 +1,241 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.lang({ + source : 'Source', + preview : 'Preview', + undo : 'Undo(Ctrl+Z)', + redo : 'Redo(Ctrl+Y)', + cut : 'Cut(Ctrl+X)', + copy : 'Copy(Ctrl+C)', + paste : 'Paste(Ctrl+V)', + plainpaste : 'Paste as plain text', + wordpaste : 'Paste from Word', + selectall : 'Select all', + justifyleft : 'Align left', + justifycenter : 'Align center', + justifyright : 'Align right', + justifyfull : 'Align full', + insertorderedlist : 'Ordered list', + insertunorderedlist : 'Unordered list', + indent : 'Increase indent', + outdent : 'Decrease indent', + subscript : 'Subscript', + superscript : 'Superscript', + formatblock : 'Paragraph format', + fontname : 'Font family', + fontsize : 'Font size', + forecolor : 'Text color', + hilitecolor : 'Highlight color', + bold : 'Bold(Ctrl+B)', + italic : 'Italic(Ctrl+I)', + underline : 'Underline(Ctrl+U)', + strikethrough : 'Strikethrough', + removeformat : 'Remove format', + image : 'Image', + multiimage : 'Multi image', + flash : 'Flash', + media : 'Embeded media', + table : 'Table', + tablecell : 'Cell', + hr : 'Insert horizontal line', + emoticons : 'Insert emoticon', + link : 'Link', + unlink : 'Unlink', + fullscreen : 'Toggle fullscreen mode', + about : 'About', + print : 'Print', + filemanager : 'File Manager', + code : 'Insert code', + map : 'Google Maps', + baidumap : 'Baidu Maps', + lineheight : 'Line height', + clearhtml : 'Clear HTML code', + pagebreak : 'Insert Page Break', + quickformat : 'Quick Format', + insertfile : 'Insert file', + template : 'Insert Template', + anchor : 'Anchor', + yes : 'OK', + no : 'Cancel', + close : 'Close', + editImage : 'Image properties', + deleteImage : 'Delete image', + editFlash : 'Flash properties', + deleteFlash : 'Delete flash', + editMedia : 'Media properties', + deleteMedia : 'Delete media', + editLink : 'Link properties', + deleteLink : 'Unlink', + editAnchor : 'Anchor properties', + deleteAnchor : 'Delete Anchor', + tableprop : 'Table properties', + tablecellprop : 'Cell properties', + tableinsert : 'Insert table', + tabledelete : 'Delete table', + tablecolinsertleft : 'Insert column left', + tablecolinsertright : 'Insert column right', + tablerowinsertabove : 'Insert row above', + tablerowinsertbelow : 'Insert row below', + tablerowmerge : 'Merge down', + tablecolmerge : 'Merge right', + tablerowsplit : 'Split row', + tablecolsplit : 'Split column', + tablecoldelete : 'Delete column', + tablerowdelete : 'Delete row', + noColor : 'Default', + pleaseSelectFile : 'Please select file.', + invalidImg : "Please type valid URL.\nAllowed file extension: jpg,gif,bmp,png", + invalidMedia : "Please type valid URL.\nAllowed file extension: swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb", + invalidWidth : "The width must be number.", + invalidHeight : "The height must be number.", + invalidBorder : "The border must be number.", + invalidUrl : "Please type valid URL.", + invalidRows : 'Invalid rows.', + invalidCols : 'Invalid columns.', + invalidPadding : 'The padding must be number.', + invalidSpacing : 'The spacing must be number.', + invalidJson : 'Invalid JSON string.', + uploadSuccess : 'Upload success.', + cutError : 'Currently not supported by your browser, use keyboard shortcut(Ctrl+X) instead.', + copyError : 'Currently not supported by your browser, use keyboard shortcut(Ctrl+C) instead.', + pasteError : 'Currently not supported by your browser, use keyboard shortcut(Ctrl+V) instead.', + ajaxLoading : 'Loading ...', + uploadLoading : 'Uploading ...', + uploadError : 'Upload Error', + 'plainpaste.comment' : 'Use keyboard shortcut(Ctrl+V) to paste the text into the window.', + 'wordpaste.comment' : 'Use keyboard shortcut(Ctrl+V) to paste the text into the window.', + 'code.pleaseInput' : 'Please input code.', + 'link.url' : 'URL', + 'link.linkType' : 'Target', + 'link.newWindow' : 'New window', + 'link.selfWindow' : 'Same window', + 'flash.url' : 'URL', + 'flash.width' : 'Width', + 'flash.height' : 'Height', + 'flash.upload' : 'Upload', + 'flash.viewServer' : 'Browse', + 'media.url' : 'URL', + 'media.width' : 'Width', + 'media.height' : 'Height', + 'media.autostart' : 'Auto start', + 'media.upload' : 'Upload', + 'media.viewServer' : 'Browse', + 'image.remoteImage' : 'Insert URL', + 'image.localImage' : 'Upload', + 'image.remoteUrl' : 'URL', + 'image.localUrl' : 'File', + 'image.size' : 'Size', + 'image.width' : 'Width', + 'image.height' : 'Height', + 'image.resetSize' : 'Reset dimensions', + 'image.align' : 'Align', + 'image.defaultAlign' : 'Default', + 'image.leftAlign' : 'Left', + 'image.rightAlign' : 'Right', + 'image.imgTitle' : 'Title', + 'image.upload' : 'Browse', + 'image.viewServer' : 'Browse', + 'multiimage.uploadDesc' : 'Allows users to upload <%=uploadLimit%> images, single image size not exceeding <%=sizeLimit%>', + 'multiimage.startUpload' : 'Start upload', + 'multiimage.clearAll' : 'Clear all', + 'multiimage.insertAll' : 'Insert all', + 'multiimage.queueLimitExceeded' : 'Queue limit exceeded.', + 'multiimage.fileExceedsSizeLimit' : 'File exceeds size limit.', + 'multiimage.zeroByteFile' : 'Zero byte file.', + 'multiimage.invalidFiletype' : 'Invalid file type.', + 'multiimage.unknownError' : 'Unknown upload error.', + 'multiimage.pending' : 'Pending ...', + 'multiimage.uploadError' : 'Upload error', + 'filemanager.emptyFolder' : 'Blank', + 'filemanager.moveup' : 'Parent folder', + 'filemanager.viewType' : 'Display: ', + 'filemanager.viewImage' : 'Thumbnails', + 'filemanager.listImage' : 'List', + 'filemanager.orderType' : 'Sorting: ', + 'filemanager.fileName' : 'By name', + 'filemanager.fileSize' : 'By size', + 'filemanager.fileType' : 'By type', + 'insertfile.url' : 'URL', + 'insertfile.title' : 'Title', + 'insertfile.upload' : 'Upload', + 'insertfile.viewServer' : 'Browse', + 'table.cells' : 'Cells', + 'table.rows' : 'Rows', + 'table.cols' : 'Columns', + 'table.size' : 'Dimensions', + 'table.width' : 'Width', + 'table.height' : 'Height', + 'table.percent' : '%', + 'table.px' : 'px', + 'table.space' : 'Space', + 'table.padding' : 'Padding', + 'table.spacing' : 'Spacing', + 'table.align' : 'Align', + 'table.textAlign' : 'Horizontal', + 'table.verticalAlign' : 'Vertical', + 'table.alignDefault' : 'Default', + 'table.alignLeft' : 'Left', + 'table.alignCenter' : 'Center', + 'table.alignRight' : 'Right', + 'table.alignTop' : 'Top', + 'table.alignMiddle' : 'Middle', + 'table.alignBottom' : 'Bottom', + 'table.alignBaseline' : 'Baseline', + 'table.border' : 'Border', + 'table.borderWidth' : 'Width', + 'table.borderColor' : 'Color', + 'table.backgroundColor' : 'Background', + 'map.address' : 'Address: ', + 'map.search' : 'Search', + 'baidumap.address' : 'Address: ', + 'baidumap.search' : 'Search', + 'baidumap.insertDynamicMap' : 'Dynamic Map', + 'anchor.name' : 'Anchor name', + 'formatblock.formatBlock' : { + h1 : 'Heading 1', + h2 : 'Heading 2', + h3 : 'Heading 3', + h4 : 'Heading 4', + p : 'Normal' + }, + 'fontname.fontName' : { + 'Arial' : 'Arial', + 'Arial Black' : 'Arial Black', + 'Comic Sans MS' : 'Comic Sans MS', + 'Courier New' : 'Courier New', + 'Garamond' : 'Garamond', + 'Georgia' : 'Georgia', + 'Tahoma' : 'Tahoma', + 'Times New Roman' : 'Times New Roman', + 'Trebuchet MS' : 'Trebuchet MS', + 'Verdana' : 'Verdana' + }, + 'lineheight.lineHeight' : [ + {'1' : 'Line height 1'}, + {'1.5' : 'Line height 1.5'}, + {'2' : 'Line height 2'}, + {'2.5' : 'Line height 2.5'}, + {'3' : 'Line height 3'} + ], + 'template.selectTemplate' : 'Template', + 'template.replaceContent' : 'Replace current content', + 'template.fileList' : { + '1.html' : 'Image and Text', + '2.html' : 'Table', + '3.html' : 'List' + } +}, 'en'); + +KindEditor.each(KindEditor.options.items, function(i, name) { + if (name == 'baidumap') { + KindEditor.options.items[i] = 'map'; + } +}); +KindEditor.options.langType = 'en'; diff --git a/php/kindeditor_demo/kindeditor/lang/ko.js b/php/kindeditor_demo/kindeditor/lang/ko.js new file mode 100755 index 0000000..bf5eb22 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lang/ko.js @@ -0,0 +1,246 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Composite +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.lang({ + source : '소스', + preview : '미리보기', + undo : '작업취소(Ctrl+Z)', + redo : '작업재개(Ctrl+Y)', + cut : '잘라내기(Ctrl+X)', + copy : '복사(Ctrl+C)', + paste : '붙여넣기(Ctrl+V)', + plainpaste : '일반 텍스트로 붙여넣기', + wordpaste : '워드 문서로 붙여넣기', + selectall : '전체 선택', + justifyleft : '왼쪽 정렬', + justifycenter : '가운데 정렬', + justifyright : '오른쪽 정렬', + justifyfull : '양쪽 정렬', + insertorderedlist : '순서 목록', + insertunorderedlist : '비순서 목록', + indent : '들여쓰기', + outdent : '내어쓰기', + subscript : '아랫첨자', + superscript : '윗첨자', + formatblock : '문단 형식', + fontname : '글꼴', + fontsize : '글자 크기', + forecolor : '글자색', + hilitecolor : '강조색', + bold : '굵게(Ctrl+B)', + italic : '이텔릭(Ctrl+I)', + underline : '빝줄(Ctrl+U)', + strikethrough : '취소선', + removeformat : '형식 제거', + image : '이미지 추가', + multiimage : '여러 이미지 추가', + flash : '플래시 추가', + media : '미디어 추가', + table : '표', + tablecell : '열', + hr : '구분선 추가', + emoticons : '이모티콘 추가', + link : '링크', + unlink : '링크 제거', + fullscreen : '전체 화면 모드', + about : '이 에디터는...', + print : '인쇄', + filemanager : '파일 관리자', + code : '코드 추가', + map : '구글 맵 추가', + baidumap : '바이두 맵 추가', + lineheight : '행 간격', + clearhtml : 'HTML 코드 정리', + pagebreak : '페이지 구분 추가', + quickformat : '빠른 형식', + insertfile : '파일 추가', + template : '템플릿 추가', + anchor : '책갈피', + yes : '확인', + no : '취소', + close : '닫기', + editImage : '이미지 속성', + deleteImage : '이미지 삭제', + editFlash : '플래시 속성', + deleteFlash : '플래시 삭제', + editMedia : '미디어 속성', + deleteMedia : '미디어 삭제', + editLink : '링크 속성', + deleteLink : '링크 삭제', + editAnchor : 'Anchor properties', + deleteAnchor : 'Delete Anchor', + tableprop : '표 속성', + tablecellprop : '열 속성', + tableinsert : '표 추가', + tabledelete : '표 삭제', + tablecolinsertleft : '왼쪽으로 열 추가', + tablecolinsertright : '오른쪽으로 열 추가', + tablerowinsertabove : '위쪽으로 열 추가', + tablerowinsertbelow : '아래쪽으로 열 추가', + tablerowmerge : '아래로 병합', + tablecolmerge : '오른쪽으로 병합', + tablerowsplit : '행 나누기', + tablecolsplit : '열 나누기', + tablecoldelete : '열 삭제', + tablerowdelete : '행 삭제', + noColor : '기본색', + pleaseSelectFile : '파일 선택', + invalidImg : "올바른 주소를 입력하세요.\njpg,gif,bmp,png 형식이 가능합니다.", + invalidMedia : "올바른 주소를 입력하세요.\nswf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb 형식이 가능합니다.", + invalidWidth : "넓이 값은 숫자여야 합니다.", + invalidHeight : "높이 값은 숫자여야 합니다.", + invalidBorder : "굵기 값은 숫자여야 합니다.", + invalidUrl : "올바른 주소를 입력하세요.", + invalidRows : '올바른 행이 아닙니다.', + invalidCols : '올바른 열이 아닙니다.', + invalidPadding : '안쪽 여백 값은 숫자여야 합니다.', + invalidSpacing : '간격 길이 값은 숫자여야 합니다.', + invalidJson : '올바른 JSON 형식이 아닙니다.', + uploadSuccess : '업로드가 완료되었습니다.', + cutError : '브라우저가 잘라내기 기능을 지원하지 않습니다, 단축키로 대신 사용하세요. (Ctrl+X)', + copyError : '브라우저가 복사 기능을 지원하지 않습니다, 단축키로 대신 사용하세요. (Ctrl+X)', + pasteError : '브라우저가 붙여넣기 기능을 지원하지 않습니다, 단축키로 대신 사용하세요. (Ctrl+X)', + ajaxLoading : '불러오는 중 ...', + uploadLoading : '업로드 중 ...', + uploadError : '업로드 오류', + 'plainpaste.comment' : '단축키(Ctrl+V)를 통하여 여기에 텍스트를 붙여넣으세요.', + 'wordpaste.comment' : '단축키(Ctrl+V)를 통하여 여기에 워드 텍스트를 붙여넣으세요.', + 'code.pleaseInput' : 'Please input code.', + 'link.url' : '주소', + 'link.linkType' : '창', + 'link.newWindow' : '새 창', + 'link.selfWindow' : '현재 창', + 'flash.url' : '주소', + 'flash.width' : '넓이', + 'flash.height' : '높이', + 'flash.upload' : '업로드', + 'flash.viewServer' : '찾아보기', + 'media.url' : '주소', + 'media.width' : '넓이', + 'media.height' : '높이', + 'media.autostart' : '자동 시작', + 'media.upload' : '업로드', + 'media.viewServer' : '찾아보기', + 'image.remoteImage' : '외부 이미지', + 'image.localImage' : '내부 이미지', + 'image.remoteUrl' : '주소', + 'image.localUrl' : '파일', + 'image.size' : '크기', + 'image.width' : '넓이', + 'image.height' : '높이', + 'image.resetSize' : '기본 크기로', + 'image.align' : '정렬', + 'image.defaultAlign' : '기본', + 'image.leftAlign' : '왼쪽', + 'image.rightAlign' : '오른쪽', + 'image.imgTitle' : '제목', + 'image.upload' : '찾아보기', + 'image.viewServer' : '찾아보기', + 'multiimage.uploadDesc' : '최대 이미지 개수: <%=uploadLimit%>개, 개당 이미지 크기: <%=sizeLimit%>', + 'multiimage.startUpload' : '업로드 시작', + 'multiimage.clearAll' : '모두 삭제', + 'multiimage.insertAll' : '모두 삽입', + 'multiimage.queueLimitExceeded' : '업로드 개수가 초과되었습니다.', + 'multiimage.fileExceedsSizeLimit' : '업로드 크기가 초과되었습니다.', + 'multiimage.zeroByteFile' : '파일 크기가 없습니다.', + 'multiimage.invalidFiletype' : '올바른 이미지가 아닙니다.', + 'multiimage.unknownError' : '알 수 없는 업로드 오류가 발생하였습니다.', + 'multiimage.pending' : '처리 중 ...', + 'multiimage.uploadError' : '업로드 오류', + 'filemanager.emptyFolder' : '빈 폴더', + 'filemanager.moveup' : '위로', + 'filemanager.viewType' : '보기 방식: ', + 'filemanager.viewImage' : '미리 보기', + 'filemanager.listImage' : '목록', + 'filemanager.orderType' : '정렬 방식: ', + 'filemanager.fileName' : '이름별', + 'filemanager.fileSize' : '크기별', + 'filemanager.fileType' : '종류별', + 'insertfile.url' : '주소', + 'insertfile.title' : '제목', + 'insertfile.upload' : '업로드', + 'insertfile.viewServer' : '찾아보기', + 'table.cells' : '열', + 'table.rows' : '행', + 'table.cols' : '열', + 'table.size' : '표 크기', + 'table.width' : '넓이', + 'table.height' : '높이', + 'table.percent' : '%', + 'table.px' : 'px', + 'table.space' : '간격', + 'table.padding' : '안쪽여백', + 'table.spacing' : '간격', + 'table.align' : '정렬', + 'table.textAlign' : '수직', + 'table.verticalAlign' : '수평', + 'table.alignDefault' : '기본', + 'table.alignLeft' : '왼쪽', + 'table.alignCenter' : '가운데', + 'table.alignRight' : '오른쪽', + 'table.alignTop' : '위쪽', + 'table.alignMiddle' : '중간', + 'table.alignBottom' : '아래쪽', + 'table.alignBaseline' : '글자기준', + 'table.border' : '테두리', + 'table.borderWidth' : '크기', + 'table.borderColor' : '색상', + 'table.backgroundColor' : '배경', + 'map.address' : '주소: ', + 'map.search' : '검색', + 'baidumap.address' : '주소: ', + 'baidumap.search' : '검색', + 'baidumap.insertDynamicMap' : '동적 지도', + 'anchor.name' : '책갈피명', + 'formatblock.formatBlock' : { + h1 : '제목 1', + h2 : '제목 2', + h3 : '제목 3', + h4 : '제목 4', + p : '본문' + }, + 'fontname.fontName' : { + 'Gulim' : '굴림', + 'Dotum' : '돋움', + 'Batang' : '바탕', + 'Gungsuh' : '궁서', + 'Malgun Gothic' : '맑은 고딕', + 'Arial' : 'Arial', + 'Arial Black' : 'Arial Black', + 'Comic Sans MS' : 'Comic Sans MS', + 'Courier New' : 'Courier New', + 'Garamond' : 'Garamond', + 'Georgia' : 'Georgia', + 'Tahoma' : 'Tahoma', + 'Times New Roman' : 'Times New Roman', + 'Trebuchet MS' : 'Trebuchet MS', + 'Verdana' : 'Verdana' + }, + 'lineheight.lineHeight' : [ + {'1' : '행간 1'}, + {'1.5' : '행간 1.5'}, + {'2' : '행간 2'}, + {'2.5' : '행간 2.5'}, + {'3' : '행간 3'} + ], + 'template.selectTemplate' : '템플릿', + 'template.replaceContent' : '내용 바꾸기', + 'template.fileList' : { + '1.html' : '이미지와 텍스트', + '2.html' : '표', + '3.html' : '목록' + } +}, 'ko'); + +KindEditor.each(KindEditor.options.items, function(i, name) { + if (name == 'baidumap') { + KindEditor.options.items[i] = 'map'; + } +}); +KindEditor.options.langType = 'ko'; diff --git a/php/kindeditor_demo/kindeditor/lang/ru.js b/php/kindeditor_demo/kindeditor/lang/ru.js new file mode 100755 index 0000000..dda10bf --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lang/ru.js @@ -0,0 +1,242 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +* Translated to Russian by Valery Votintsev (http://codersclub.org/) +*******************************************************************************/ + +KindEditor.lang({ + source : 'Source', + preview : 'Preview', + undo : 'Отмена(Ctrl+Z)', + redo : 'Повтор(Ctrl+Y)', + cut : 'Вырезать(Ctrl+X)', + copy : 'Копировать(Ctrl+C)', + paste : 'Вставить(Ctrl+V)', + plainpaste : 'Вставить как простой текст', + wordpaste : 'Вставить из Word', + selectall : 'Выбрать все', + justifyleft : 'Выравнивание влево', + justifycenter : 'Выравнивание по центру', + justifyright : 'Выравнивание вправо', + justifyfull : 'Выравнивание по обеим сторонам', + insertorderedlist : 'Нумерованый список', + insertunorderedlist : 'Ненумерованый список', + indent : 'Добавить отступ', + outdent : 'Убрать отступ', + subscript : 'Надстрочный', + superscript : 'Подстрочный', + formatblock : 'Формат параграфа', + fontname : 'Шрифт', + fontsize : 'Размер', + forecolor : 'Цвет текста', + hilitecolor : 'Цвет фона', + bold : 'Жирный(Ctrl+B)', + italic : 'Наклонный(Ctrl+I)', + underline : 'Подчёркнутый(Ctrl+U)', + strikethrough : 'Перечёркнутый', + removeformat : 'Удалить формат', + image : 'Изображение', + multiimage : 'Мульти-загрузка', + flash : 'Flash', + media : 'Встроенные данные', + table : 'Таблица', + tablecell : 'Ячейка', + hr : 'Горизонтальный разделитель', + emoticons : 'Смайл', + link : 'Ссылка', + unlink : 'Убрать ссылку', + fullscreen : 'На весь экран', + about : 'О программе', + print : 'Печать', + filemanager : 'Файлы', + code : 'Код', + map : 'Карта Google', + baidumap : 'Карта Baidu', + lineheight : 'Межстрочный интервал', + clearhtml : 'Очистить HTML код', + pagebreak : 'Разрыв страницы', + quickformat : 'Быстрый формат', + insertfile : 'Вставить файл', + template : 'Вставить шаблон', + anchor : 'Якорь', + yes : 'OK', + no : 'Отмена', + close : 'Закрыть', + editImage : 'Свойства изображения', + deleteImage : 'Удалить изображение', + editFlash : 'Свойства Flash', + deleteFlash : 'Удалить Flash', + editMedia : 'Свойства Media', + deleteMedia : 'Удалить Media', + editLink : 'Свойства ссылки', + deleteLink : 'Удалить ссылку', + editAnchor : 'Anchor properties', + deleteAnchor : 'Delete Anchor', + tableprop : 'Свойства таблицы', + tablecellprop : 'Свойства ячейки', + tableinsert : 'Вставить таблицу', + tabledelete : 'Удалить таблицу', + tablecolinsertleft : 'Добавить столбец слева', + tablecolinsertright : 'Добавить столбец справа', + tablerowinsertabove : 'Добавить строку выше', + tablerowinsertbelow : 'Добавить строку ниже', + tablerowmerge : 'Объединить вниз', + tablecolmerge : 'Объединить вправо', + tablerowsplit : 'Разделить строку', + tablecolsplit : 'Разделить столбец', + tablecoldelete : 'Удалить столбец', + tablerowdelete : 'Удалить строку', + noColor : 'По умолчанию', + pleaseSelectFile : 'Выберите файл.', + invalidImg : "Укажите корректный URL изображения.\nРазрешённые форматы: jpg,gif,bmp,png", + invalidMedia : "Укажите корректный тип медиа-объекта.\nРазрешённые типы: swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb", + invalidWidth : "Ширина должна быть числом.", + invalidHeight : "Высота должна быть числом.", + invalidBorder : "Ширина рамки должна быть числом.", + invalidUrl : "Укажите корректный URL.", + invalidRows : 'Неверные строки.', + invalidCols : 'Неверные столбцы.', + invalidPadding : 'padding должен быть числом.', + invalidSpacing : 'spacing должен быть числом.', + invalidJson : 'Неверная JSON строка.', + uploadSuccess : 'Загрузка завершена.', + cutError : 'Данная опция не поддерживается вашим браузером, воспользуйтесь комбинацией клавиш (Ctrl+X).', + copyError : 'Данная опция не поддерживается вашим браузером, воспользуйтесь комбинацией клавиш (Ctrl+C).', + pasteError : 'Данная опция не поддерживается вашим браузером, воспользуйтесь комбинацией клавиш (Ctrl+V).', + ajaxLoading : 'Загрузка ...', + uploadLoading : 'Загрузка ...', + uploadError : 'Сбой загрузки', + 'plainpaste.comment' : 'Для вставки скопированного текста воспользуйтесь комбинацией клавиш (Ctrl+V).', + 'wordpaste.comment' : 'Для вставки скопированного текста воспользуйтесь комбинацией клавиш (Ctrl+V).', + 'code.pleaseInput' : 'Введите код.', + 'link.url' : 'URL', + 'link.linkType' : 'Открывать ссылку', + 'link.newWindow' : 'в новом окне', + 'link.selfWindow' : 'в том же окне', + 'flash.url' : 'URL', + 'flash.width' : 'Ширина', + 'flash.height' : 'Высота', + 'flash.upload' : 'Загрузить', + 'flash.viewServer' : 'Выбрать', + 'media.url' : 'URL', + 'media.width' : 'Ширина', + 'media.height' : 'Высота', + 'media.autostart' : 'Автостарт', + 'media.upload' : 'Загрузить', + 'media.viewServer' : 'Выбрать', + 'image.remoteImage' : 'Вставить URL изображения', + 'image.localImage' : 'Загрузить', + 'image.remoteUrl' : 'URL', + 'image.localUrl' : 'Файл', + 'image.size' : 'Размер', + 'image.width' : 'Ширина', + 'image.height' : 'Высота', + 'image.resetSize' : 'Сбросить размеры', + 'image.align' : 'Выравнивание', + 'image.defaultAlign' : 'По умолчанию', + 'image.leftAlign' : 'Влево', + 'image.rightAlign' : 'Вправо', + 'image.imgTitle' : 'Название', + 'image.upload' : 'Загрузить', + 'image.viewServer' : 'Выбрать', + 'multiimage.uploadDesc' : 'Максимальное кол-во изображений: <%=uploadLimit%>, Максимальный размер одного изображения: <%=sizeLimit%>', + 'multiimage.startUpload' : 'Начать загрузку', + 'multiimage.clearAll' : 'Очистить все', + 'multiimage.insertAll' : 'Вставить все', + 'multiimage.queueLimitExceeded' : 'Превышен лимит очереди.', + 'multiimage.fileExceedsSizeLimit' : 'Превышен максимальный размер файла.', + 'multiimage.zeroByteFile' : 'Файл нулевой длины.', + 'multiimage.invalidFiletype' : 'Недопустимый тип файла.', + 'multiimage.unknownError' : 'Непредвиденная ошибка загрузки.', + 'multiimage.pending' : 'Ожидает ...', + 'multiimage.uploadError' : 'Ошибка загрузки', + 'filemanager.emptyFolder' : 'Папка пуста', + 'filemanager.moveup' : 'Наверх', + 'filemanager.viewType' : 'Тип показа: ', + 'filemanager.viewImage' : 'Превьюшки', + 'filemanager.listImage' : 'Список', + 'filemanager.orderType' : 'Сортировка: ', + 'filemanager.fileName' : 'По имени', + 'filemanager.fileSize' : 'По размеру', + 'filemanager.fileType' : 'По типу', + 'insertfile.url' : 'URL', + 'insertfile.title' : 'Название', + 'insertfile.upload' : 'Загрузить', + 'insertfile.viewServer' : 'Выбрать', + 'table.cells' : 'Ячейки', + 'table.rows' : 'Строки', + 'table.cols' : 'Столбцы', + 'table.size' : 'Размеры', + 'table.width' : 'Ширина', + 'table.height' : 'Высота', + 'table.percent' : '%', + 'table.px' : 'px', + 'table.space' : 'Space', + 'table.padding' : 'Padding', + 'table.spacing' : 'Spacing', + 'table.align' : 'Выравнивание', + 'table.textAlign' : 'По горизонтали', + 'table.verticalAlign' : 'По вертикали', + 'table.alignDefault' : 'По умолчанию', + 'table.alignLeft' : 'Влево', + 'table.alignCenter' : 'По центру', + 'table.alignRight' : 'Вправо', + 'table.alignTop' : 'Вверх', + 'table.alignMiddle' : 'Посередине', + 'table.alignBottom' : 'Вниз', + 'table.alignBaseline' : 'По базовой линии', + 'table.border' : 'Рамка', + 'table.borderWidth' : 'Ширина', + 'table.borderColor' : 'Цвет', + 'table.backgroundColor' : 'Цвет фона', + 'map.address' : 'Адрес: ', + 'map.search' : 'Поиск', + 'baidumap.address' : 'Адрес: ', + 'baidumap.search' : 'Поиск', + 'baidumap.insertDynamicMap' : 'Динамическая карта', + 'anchor.name' : 'Имя якоря', + 'formatblock.formatBlock' : { + h1 : 'Заголовок 1', + h2 : 'Заголовок 2', + h3 : 'Заголовок 3', + h4 : 'Заголовок 4', + p : 'Обычный текст' + }, + 'fontname.fontName' : { + 'Arial' : 'Arial', + 'Arial Black' : 'Arial Black', + 'Comic Sans MS' : 'Comic Sans MS', + 'Courier New' : 'Courier New', + 'Garamond' : 'Garamond', + 'Georgia' : 'Georgia', + 'Tahoma' : 'Tahoma', + 'Times New Roman' : 'Times New Roman', + 'Trebuchet MS' : 'Trebuchet MS', + 'Verdana' : 'Verdana' + }, + 'lineheight.lineHeight' : [ + {'1' : '1'}, + {'1.5' : '1.5'}, + {'2' : '2'}, + {'2.5' : '2.5'}, + {'3' : '3'} + ], + 'template.selectTemplate' : 'Шаблон', + 'template.replaceContent' : 'Заменить текущий шаблон', + 'template.fileList' : { + '1.html' : 'Текст и изображения', + '2.html' : 'Таблица', + '3.html' : 'Список' + } +}, 'en'); + +KindEditor.each(KindEditor.options.items, function(i, name) { + if (name == 'baidumap') { + KindEditor.options.items[i] = 'map'; + } +}); +KindEditor.options.langType = 'ru'; diff --git a/php/kindeditor_demo/kindeditor/lang/zh-CN.js b/php/kindeditor_demo/kindeditor/lang/zh-CN.js new file mode 100755 index 0000000..d9aa96e --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lang/zh-CN.js @@ -0,0 +1,238 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.lang({ + source : 'HTML代码', + preview : '预览', + undo : '后退(Ctrl+Z)', + redo : '前进(Ctrl+Y)', + cut : '剪切(Ctrl+X)', + copy : '复制(Ctrl+C)', + paste : '粘贴(Ctrl+V)', + plainpaste : '粘贴为无格式文本', + wordpaste : '从Word粘贴', + selectall : '全选(Ctrl+A)', + justifyleft : '左对齐', + justifycenter : '居中', + justifyright : '右对齐', + justifyfull : '两端对齐', + insertorderedlist : '编号', + insertunorderedlist : '项目符号', + indent : '增加缩进', + outdent : '减少缩进', + subscript : '下标', + superscript : '上标', + formatblock : '段落', + fontname : '字体', + fontsize : '文字大小', + forecolor : '文字颜色', + hilitecolor : '文字背景', + bold : '粗体(Ctrl+B)', + italic : '斜体(Ctrl+I)', + underline : '下划线(Ctrl+U)', + strikethrough : '删除线', + removeformat : '删除格式', + image : '图片', + multiimage : '批量图片上传', + flash : 'Flash', + media : '视音频', + table : '表格', + tablecell : '单元格', + hr : '插入横线', + emoticons : '插入表情', + link : '超级链接', + unlink : '取消超级链接', + fullscreen : '全屏显示', + about : '关于', + print : '打印(Ctrl+P)', + filemanager : '文件空间', + code : '插入程序代码', + map : 'Google地图', + baidumap : '百度地图', + lineheight : '行距', + clearhtml : '清理HTML代码', + pagebreak : '插入分页符', + quickformat : '一键排版', + insertfile : '插入文件', + template : '插入模板', + anchor : '锚点', + yes : '确定', + no : '取消', + close : '关闭', + editImage : '图片属性', + deleteImage : '删除图片', + editFlash : 'Flash属性', + deleteFlash : '删除Flash', + editMedia : '视音频属性', + deleteMedia : '删除视音频', + editLink : '超级链接属性', + deleteLink : '取消超级链接', + editAnchor : '锚点属性', + deleteAnchor : '删除锚点', + tableprop : '表格属性', + tablecellprop : '单元格属性', + tableinsert : '插入表格', + tabledelete : '删除表格', + tablecolinsertleft : '左侧插入列', + tablecolinsertright : '右侧插入列', + tablerowinsertabove : '上方插入行', + tablerowinsertbelow : '下方插入行', + tablerowmerge : '向下合并单元格', + tablecolmerge : '向右合并单元格', + tablerowsplit : '拆分行', + tablecolsplit : '拆分列', + tablecoldelete : '删除列', + tablerowdelete : '删除行', + noColor : '无颜色', + pleaseSelectFile : '请选择文件。', + invalidImg : "请输入有效的URL地址。\n只允许jpg,gif,bmp,png格式。", + invalidMedia : "请输入有效的URL地址。\n只允许swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb格式。", + invalidWidth : "宽度必须为数字。", + invalidHeight : "高度必须为数字。", + invalidBorder : "边框必须为数字。", + invalidUrl : "请输入有效的URL地址。", + invalidRows : '行数为必选项,只允许输入大于0的数字。', + invalidCols : '列数为必选项,只允许输入大于0的数字。', + invalidPadding : '边距必须为数字。', + invalidSpacing : '间距必须为数字。', + invalidJson : '服务器发生故障。', + uploadSuccess : '上传成功。', + cutError : '您的浏览器安全设置不允许使用剪切操作,请使用快捷键(Ctrl+X)来完成。', + copyError : '您的浏览器安全设置不允许使用复制操作,请使用快捷键(Ctrl+C)来完成。', + pasteError : '您的浏览器安全设置不允许使用粘贴操作,请使用快捷键(Ctrl+V)来完成。', + ajaxLoading : '加载中,请稍候 ...', + uploadLoading : '上传中,请稍候 ...', + uploadError : '上传错误', + 'plainpaste.comment' : '请使用快捷键(Ctrl+V)把内容粘贴到下面的方框里。', + 'wordpaste.comment' : '请使用快捷键(Ctrl+V)把内容粘贴到下面的方框里。', + 'code.pleaseInput' : '请输入程序代码。', + 'link.url' : 'URL', + 'link.linkType' : '打开类型', + 'link.newWindow' : '新窗口', + 'link.selfWindow' : '当前窗口', + 'flash.url' : 'URL', + 'flash.width' : '宽度', + 'flash.height' : '高度', + 'flash.upload' : '上传', + 'flash.viewServer' : '文件空间', + 'media.url' : 'URL', + 'media.width' : '宽度', + 'media.height' : '高度', + 'media.autostart' : '自动播放', + 'media.upload' : '上传', + 'media.viewServer' : '文件空间', + 'image.remoteImage' : '网络图片', + 'image.localImage' : '本地上传', + 'image.remoteUrl' : '图片地址', + 'image.localUrl' : '上传文件', + 'image.size' : '图片大小', + 'image.width' : '宽', + 'image.height' : '高', + 'image.resetSize' : '重置大小', + 'image.align' : '对齐方式', + 'image.defaultAlign' : '默认方式', + 'image.leftAlign' : '左对齐', + 'image.rightAlign' : '右对齐', + 'image.imgTitle' : '图片说明', + 'image.upload' : '浏览...', + 'image.viewServer' : '图片空间', + 'multiimage.uploadDesc' : '允许用户同时上传<%=uploadLimit%>张图片,单张图片容量不超过<%=sizeLimit%>', + 'multiimage.startUpload' : '开始上传', + 'multiimage.clearAll' : '全部清空', + 'multiimage.insertAll' : '全部插入', + 'multiimage.queueLimitExceeded' : '文件数量超过限制。', + 'multiimage.fileExceedsSizeLimit' : '文件大小超过限制。', + 'multiimage.zeroByteFile' : '无法上传空文件。', + 'multiimage.invalidFiletype' : '文件类型不正确。', + 'multiimage.unknownError' : '发生异常,无法上传。', + 'multiimage.pending' : '等待上传', + 'multiimage.uploadError' : '上传失败', + 'filemanager.emptyFolder' : '空文件夹', + 'filemanager.moveup' : '移到上一级文件夹', + 'filemanager.viewType' : '显示方式:', + 'filemanager.viewImage' : '缩略图', + 'filemanager.listImage' : '详细信息', + 'filemanager.orderType' : '排序方式:', + 'filemanager.fileName' : '名称', + 'filemanager.fileSize' : '大小', + 'filemanager.fileType' : '类型', + 'insertfile.url' : 'URL', + 'insertfile.title' : '文件说明', + 'insertfile.upload' : '上传', + 'insertfile.viewServer' : '文件空间', + 'table.cells' : '单元格数', + 'table.rows' : '行数', + 'table.cols' : '列数', + 'table.size' : '大小', + 'table.width' : '宽度', + 'table.height' : '高度', + 'table.percent' : '%', + 'table.px' : 'px', + 'table.space' : '边距间距', + 'table.padding' : '边距', + 'table.spacing' : '间距', + 'table.align' : '对齐方式', + 'table.textAlign' : '水平对齐', + 'table.verticalAlign' : '垂直对齐', + 'table.alignDefault' : '默认', + 'table.alignLeft' : '左对齐', + 'table.alignCenter' : '居中', + 'table.alignRight' : '右对齐', + 'table.alignTop' : '顶部', + 'table.alignMiddle' : '中部', + 'table.alignBottom' : '底部', + 'table.alignBaseline' : '基线', + 'table.border' : '边框', + 'table.borderWidth' : '边框', + 'table.borderColor' : '颜色', + 'table.backgroundColor' : '背景颜色', + 'map.address' : '地址: ', + 'map.search' : '搜索', + 'baidumap.address' : '地址: ', + 'baidumap.search' : '搜索', + 'baidumap.insertDynamicMap' : '插入动态地图', + 'anchor.name' : '锚点名称', + 'formatblock.formatBlock' : { + h1 : '标题 1', + h2 : '标题 2', + h3 : '标题 3', + h4 : '标题 4', + p : '正 文' + }, + 'fontname.fontName' : { + 'SimSun' : '宋体', + 'NSimSun' : '新宋体', + 'FangSong_GB2312' : '仿宋_GB2312', + 'KaiTi_GB2312' : '楷体_GB2312', + 'SimHei' : '黑体', + 'Microsoft YaHei' : '微软雅黑', + 'Arial' : 'Arial', + 'Arial Black' : 'Arial Black', + 'Times New Roman' : 'Times New Roman', + 'Courier New' : 'Courier New', + 'Tahoma' : 'Tahoma', + 'Verdana' : 'Verdana' + }, + 'lineheight.lineHeight' : [ + {'1' : '单倍行距'}, + {'1.5' : '1.5倍行距'}, + {'2' : '2倍行距'}, + {'2.5' : '2.5倍行距'}, + {'3' : '3倍行距'} + ], + 'template.selectTemplate' : '可选模板', + 'template.replaceContent' : '替换当前内容', + 'template.fileList' : { + '1.html' : '图片和文字', + '2.html' : '表格', + '3.html' : '项目编号' + } +}, 'zh-CN'); + +KindEditor.options.langType = 'zh-CN'; \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lang/zh-TW.js b/php/kindeditor_demo/kindeditor/lang/zh-TW.js new file mode 100755 index 0000000..4946898 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lang/zh-TW.js @@ -0,0 +1,243 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.lang({ + source : '原始碼', + preview : '預覽', + undo : '復原(Ctrl+Z)', + redo : '重複(Ctrl+Y)', + cut : '剪下(Ctrl+X)', + copy : '複製(Ctrl+C)', + paste : '貼上(Ctrl+V)', + plainpaste : '貼為純文字格式', + wordpaste : '自Word貼上', + selectall : '全選(Ctrl+A)', + justifyleft : '靠左對齊', + justifycenter : '置中', + justifyright : '靠右對齊', + justifyfull : '左右對齊', + insertorderedlist : '編號清單', + insertunorderedlist : '項目清單', + indent : '增加縮排', + outdent : '減少縮排', + subscript : '下標', + superscript : '上標', + formatblock : '標題', + fontname : '字體', + fontsize : '文字大小', + forecolor : '文字顏色', + hilitecolor : '背景顏色', + bold : '粗體(Ctrl+B)', + italic : '斜體(Ctrl+I)', + underline : '底線(Ctrl+U)', + strikethrough : '刪除線', + removeformat : '清除格式', + image : '影像', + multiimage : '批量影像上傳', + flash : 'Flash', + media : '多媒體', + table : '表格', + tablecell : '儲存格', + hr : '插入水平線', + emoticons : '插入表情', + link : '超連結', + unlink : '移除超連結', + fullscreen : '最大化', + about : '關於', + print : '列印(Ctrl+P)', + filemanager : '瀏覽伺服器', + code : '插入程式代碼', + map : 'Google地圖', + baidumap : 'Baidu地圖', + lineheight : '行距', + clearhtml : '清理HTML代碼', + pagebreak : '插入分頁符號', + quickformat : '快速排版', + insertfile : '插入文件', + template : '插入樣板', + anchor : '錨點', + yes : '確定', + no : '取消', + close : '關閉', + editImage : '影像屬性', + deleteImage : '刪除影像', + editFlash : 'Flash屬性', + deleteFlash : '删除Flash', + editMedia : '多媒體屬性', + deleteMedia : '删除多媒體', + editLink : '超連結屬性', + deleteLink : '移除超連結', + editAnchor : '锚点属性', + deleteAnchor : '删除锚点', + tableprop : '表格屬性', + tablecellprop : '儲存格屬性', + tableinsert : '插入表格', + tabledelete : '刪除表格', + tablecolinsertleft : '向左插入列', + tablecolinsertright : '向右插入列', + tablerowinsertabove : '向上插入欄', + tablerowinsertbelow : '下方插入欄', + tablerowmerge : '向下合併單元格', + tablecolmerge : '向右合併單元格', + tablerowsplit : '分割欄', + tablecolsplit : '分割列', + tablecoldelete : '删除列', + tablerowdelete : '删除欄', + noColor : '自動', + pleaseSelectFile : '請選擇文件。', + invalidImg : "請輸入有效的URL。\n只允許jpg,gif,bmp,png格式。", + invalidMedia : "請輸入有效的URL。\n只允許swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb格式。", + invalidWidth : "寬度必須是數字。", + invalidHeight : "高度必須是數字。", + invalidBorder : "邊框必須是數字。", + invalidUrl : "請輸入有效的URL。", + invalidRows : '欄數是必須輸入項目,只允許輸入大於0的數字。', + invalidCols : '列數是必須輸入項目,只允許輸入大於0的數字。', + invalidPadding : '內距必須是數字。', + invalidSpacing : '間距必須是數字。', + invalidJson : '伺服器發生故障。', + uploadSuccess : '上傳成功。', + cutError : '您的瀏覽器安全設置不允許使用剪下操作,請使用快捷鍵(Ctrl+X)完成。', + copyError : '您的瀏覽器安全設置不允許使用剪下操作,請使用快捷鍵(Ctrl+C)完成。', + pasteError : '您的瀏覽器安全設置不允許使用剪下操作,請使用快捷鍵(Ctrl+V)完成。', + ajaxLoading : '加載中,請稍候 ...', + uploadLoading : '上傳中,請稍候 ...', + uploadError : '上傳錯誤', + 'plainpaste.comment' : '請使用快捷鍵(Ctrl+V)把內容貼到下方區域裡。', + 'wordpaste.comment' : '請使用快捷鍵(Ctrl+V)把內容貼到下方區域裡。', + 'code.pleaseInput' : 'Please input code.', + 'link.url' : 'URL', + 'link.linkType' : '打開類型', + 'link.newWindow' : '新窗口', + 'link.selfWindow' : '本頁窗口', + 'flash.url' : 'URL', + 'flash.width' : '寬度', + 'flash.height' : '高度', + 'flash.upload' : '上傳', + 'flash.viewServer' : '瀏覽', + 'media.url' : 'URL', + 'media.width' : '寬度', + 'media.height' : '高度', + 'media.autostart' : '自動播放', + 'media.upload' : '上傳', + 'media.viewServer' : '瀏覽', + 'image.remoteImage' : '網絡影像', + 'image.localImage' : '上傳影像', + 'image.remoteUrl' : '影像URL', + 'image.localUrl' : '影像URL', + 'image.size' : '影像大小', + 'image.width' : '寬度', + 'image.height' : '高度', + 'image.resetSize' : '原始大小', + 'image.align' : '對齊方式', + 'image.defaultAlign' : '未設定', + 'image.leftAlign' : '向左對齊', + 'image.rightAlign' : '向右對齊', + 'image.imgTitle' : '影像說明', + 'image.upload' : '瀏覽...', + 'image.viewServer' : '瀏覽...', + 'multiimage.uploadDesc' : 'Allows users to upload <%=uploadLimit%> images, single image size not exceeding <%=sizeLimit%>', + 'multiimage.startUpload' : 'Start upload', + 'multiimage.clearAll' : 'Clear all', + 'multiimage.insertAll' : 'Insert all', + 'multiimage.queueLimitExceeded' : 'Queue limit exceeded.', + 'multiimage.fileExceedsSizeLimit' : 'File exceeds size limit.', + 'multiimage.zeroByteFile' : 'Zero byte file.', + 'multiimage.invalidFiletype' : 'Invalid file type.', + 'multiimage.unknownError' : 'Unknown upload error.', + 'multiimage.pending' : 'Pending ...', + 'multiimage.uploadError' : 'Upload error', + 'filemanager.emptyFolder' : '空文件夾', + 'filemanager.moveup' : '至上一級文件夾', + 'filemanager.viewType' : '顯示方式:', + 'filemanager.viewImage' : '縮略圖', + 'filemanager.listImage' : '詳細信息', + 'filemanager.orderType' : '排序方式:', + 'filemanager.fileName' : '名稱', + 'filemanager.fileSize' : '大小', + 'filemanager.fileType' : '類型', + 'insertfile.url' : 'URL', + 'insertfile.title' : '文件說明', + 'insertfile.upload' : '上傳', + 'insertfile.viewServer' : '瀏覽', + 'table.cells' : '儲存格數', + 'table.rows' : '欄數', + 'table.cols' : '列數', + 'table.size' : '表格大小', + 'table.width' : '寬度', + 'table.height' : '高度', + 'table.percent' : '%', + 'table.px' : 'px', + 'table.space' : '內距間距', + 'table.padding' : '內距', + 'table.spacing' : '間距', + 'table.align' : '對齊方式', + 'table.textAlign' : '水平對齊', + 'table.verticalAlign' : '垂直對齊', + 'table.alignDefault' : '未設定', + 'table.alignLeft' : '向左對齊', + 'table.alignCenter' : '置中', + 'table.alignRight' : '向右對齊', + 'table.alignTop' : '靠上', + 'table.alignMiddle' : '置中', + 'table.alignBottom' : '靠下', + 'table.alignBaseline' : '基線', + 'table.border' : '表格邊框', + 'table.borderWidth' : '邊框', + 'table.borderColor' : '顏色', + 'table.backgroundColor' : '背景顏色', + 'map.address' : '住所: ', + 'map.search' : '尋找', + 'baidumap.address' : '住所: ', + 'baidumap.search' : '尋找', + 'baidumap.insertDynamicMap' : '插入動態地圖', + 'anchor.name' : '錨點名稱', + 'formatblock.formatBlock' : { + h1 : '標題 1', + h2 : '標題 2', + h3 : '標題 3', + h4 : '標題 4', + p : '一般' + }, + 'fontname.fontName' : { + 'MingLiU' : '細明體', + 'PMingLiU' : '新細明體', + 'DFKai-SB' : '標楷體', + 'SimSun' : '宋體', + 'NSimSun' : '新宋體', + 'FangSong' : '仿宋體', + 'Arial' : 'Arial', + 'Arial Black' : 'Arial Black', + 'Times New Roman' : 'Times New Roman', + 'Courier New' : 'Courier New', + 'Tahoma' : 'Tahoma', + 'Verdana' : 'Verdana' + }, + 'lineheight.lineHeight' : [ + {'1' : '单倍行距'}, + {'1.5' : '1.5倍行距'}, + {'2' : '2倍行距'}, + {'2.5' : '2.5倍行距'}, + {'3' : '3倍行距'} + ], + 'template.selectTemplate' : '可選樣板', + 'template.replaceContent' : '取代當前內容', + 'template.fileList' : { + '1.html' : '影像和文字', + '2.html' : '表格', + '3.html' : '项目清單' + } +}, 'zh-TW'); + +KindEditor.each(KindEditor.options.items, function(i, name) { + if (name == 'baidumap') { + KindEditor.options.items[i] = 'map'; + } +}); +KindEditor.options.langType = 'zh-TW'; \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/.htaccess b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/.htaccess new file mode 100755 index 0000000..cb38bde --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/.htaccess @@ -0,0 +1,15 @@ +AddType "text/javascript;charset=UTF-8" .jgz .js +AddEncoding gzip .jgz + + + ExpiresActive On + ExpiresDefault A86400 + + + + RewriteEngine on + #RewriteCond %{HTTP_USER_AGENT} ".*Safari.*" [OR] + RewriteCond %{HTTP_USER_AGENT} ".*MSIE 6.*" [OR] + RewriteCond %{HTTP:Accept-Encoding} !gzip + RewriteRule (.*)\.jgz$ $1.js [L] + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/build.bat b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/build.bat new file mode 100755 index 0000000..6e71c22 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/build.bat @@ -0,0 +1,21 @@ +rd firebug-lite /s /q +rd pub /s /q + +svn export "../" "./firebug-lite" + +md pub +xcopy ".\firebug-lite\skin\." ".\pub\skin" /s /i +copy "..\docs\beta\index.html" ".\pub\index.html" +copy "..\content\changelog.txt" ".\pub" +copy ".\firebug-lite\build\*.*" ".\pub" +del ".\pub\*.bat" + +tar -cv --file=firebug-lite.tar firebug-lite/* +gzip -9 < firebug-lite.tar > ./pub/firebug-lite.tar.tgz + +del firebug-lite.tar + +rd firebug-lite /s /q + +pause + diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/background.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/background.html new file mode 100755 index 0000000..c4133a1 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/background.html @@ -0,0 +1,187 @@ + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/contentScript.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/contentScript.js new file mode 100755 index 0000000..1dad3c1 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/contentScript.js @@ -0,0 +1,378 @@ +// ************************************************************************************************* + +var isActive = false; +var isOpen = false; +var extensionURL = null; + +var contextMenuElementXPath = null; +var isListeningKeyboardActivation = false; + +// ************************************************************************************************* + +// restore Firebug Lite state +var loadStateData = function() +{ + var FirebugData = localStorage.getItem("Firebug"); + + isActive = false; + isOpen = false; + extensionURL = chrome.extension.getURL(""); + + if (FirebugData) + { + FirebugData = FirebugData.split(","); + isActive = FirebugData[0] == "1"; + isOpen = FirebugData[1] == "1"; + } +} + +// ************************************************************************************************* + +// load Firebug Lite application +var loadFirebug = function() +{ + document.documentElement.setAttribute("debug", isOpen); + + injectScriptText("("+listenConsoleCalls+")()"); + + // TODO: xxxpedro - change to XHR when Issue 41024 is solved + // Issue 41024: XHR using file: and chrome-extension: protocols not working. + // http://code.google.com/p/chromium/issues/detail?id=41024 + injectFirebugScript(); +} + +// TODO: think a better solution than using the stateData parameter, required +// by the keyboard activation. +var loadFirebugAndWait = function(callback, stateData) +{ + stateData = stateData || ('1,1,'+extensionURL); + localStorage.setItem('Firebug', stateData); + loadStateData(); + chrome.extension.sendRequest({name: isActive ? "FB_enableIcon" : "FB_disableIcon"}); + + document.documentElement.setAttribute("debug", isOpen); + + injectFirebugScript(); + + setTimeout(function(){ + waitFirebug(callback); + },0); +}; + +var waitFirebug = function(callback) +{ + if (document && document.getElementById("FirebugChannel")) + { + stopListeningKeyboardActivation(); + callback(); + } + else + setTimeout(function(){ waitFirebug(callback); }, 100); + +}; + +// ************************************************************************************************* + +// inject Firebug Lite script into the page +var injectFirebugScript = function(url) +{ + scriptElement = document.getElementById("FirebugLite"); + if (scriptElement) + { + firebugDispatch("FB_toggle"); + } + else + { + var script = document.createElement("script"); + + script.src = extensionURL + "firebug-lite-beta.js"; + script.setAttribute("id", "FirebugLite"); + script.setAttribute("firebugIgnore", "true"); + script.setAttribute("extension", "Chrome"); + document.documentElement.appendChild(script); + + script.onload = function() { + // TODO: xxxpedro remove this files when deploy the new structure + script = document.createElement("script"); + script.src = extensionURL + "googleChrome.js"; + document.documentElement.appendChild(script); + }; + } +} + +// inject a script into the page +var injectScriptText = function(text) +{ + var script = document.createElement("script"); + var parent = document.documentElement; + + script.text = text; + script.setAttribute("id", "FirebugLite"); + script.setAttribute("firebugIgnore", "true"); + script.setAttribute("extension", "Chrome"); + parent.appendChild(script); + parent.removeChild(script); +} + +// ************************************************************************************************* + +// communication with the background page +chrome.extension.onRequest.addListener +( + function(request, sender, sendResponse) + { + // check if Firebug Lite is active + if (request.name == "FB_isActive") + { + loadStateData(); + sendResponse({value: ""+isActive}); + } + // load Firebug Lite application + else if (request.name == "FB_loadFirebug") + { + setTimeout(function(){ + + loadStateData(); + + //loadFirebug(); + loadFirebugAndWait(function(){ + + isActive = true; + var message = isActive ? "FB_enableIcon" : "FB_disableIcon"; + chrome.extension.sendRequest({name: message}); + + loadChannel(); + }); + + },0); + + sendResponse({}); + } + // handle context menu click by sending "FB_contextMenuClick" message + // to Firebug Lite application + else if (request.name == "FB_contextMenuClick") + { + // TODO: if not active, activate first, wait the activation to complete + // and only then dispatch the event to Firebug Lite application + if (isActive) + firebugDispatch("FB_contextMenuClick,"+contextMenuElementXPath); + else + loadFirebugAndWait(function(){ + firebugDispatch("FB_contextMenuClick,"+contextMenuElementXPath); + }); + } + else if (request.name == "FB_deactivate") + { + listenKeyboardActivation(); + } + else + sendResponse({}); // snub them. + } +); + +// ************************************************************************************************* + +// communication with the page +var channel = null; +var channelEvent; + +var onFirebugChannelEvent = function() +{ + channel = document.getElementById("FirebugChannel"); + + if (channel) + { + chrome.extension.sendRequest({name: channel.innerText}); + } +}; + +var loadChannel = function() +{ + channel = document.getElementById("FirebugChannel"); + + if (channel) + { + channel.addEventListener("FirebugChannelEvent", onFirebugChannelEvent); + channelEvent = document.createEvent("Event"); + channelEvent.initEvent("FirebugChannelEvent", true, true); + } +} + +var firebugDispatch = function(data) +{ + if (!channel) + loadChannel(); + + channel.innerText = data; + channel.dispatchEvent(channelEvent); +}; + +// ************************************************************************************************* + +var onContextMenu = function(event) +{ + contextMenuElementXPath = getElementXPath(event.target); +}; + +var loadListeners = function() +{ + window.addEventListener("contextmenu", onContextMenu); + window.addEventListener("unload", unloadListeners); +}; + +var unloadListeners = function() +{ + if (channel) + { + channel.removeEventListener("FirebugChannelEvent", onFirebugChannelEvent); + } + + window.removeEventListener("contextmenu", onContextMenu); + window.removeEventListener("unload", unloadListeners); +}; + +// ************************************************************************************************* + +// listen to console calls before Firebug Lite finishes to load +var listenConsoleCalls = function() +{ + // TODO: xxxpedro add all console functions + var fns = ["log", "info", "warn", "error"]; + + var listener = {consoleQueue: ["chromeConsoleQueueHack"]}; + var queue = listener.consoleQueue; + + for (var i=0, l=fns.length; i 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; + if (FBL.Env.isChromeExtension) + { + path = productionDir; + FBL.Env.bookmarkletOutdated = false; + script = {innerHTML: "{showIconWhenHidden:false}"}; + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + var Env = FBL.Env; + + // Always use the local skin when running in the same domain + // See Issue 3554: Firebug Lite should use local images when loaded locally + Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0; + + // detecting development and debug modes via file name + if (fileName == "firebug-lite-dev.js") + { + Env.isDevelopmentMode = true; + Env.isDebugMode = true; + } + else if (fileName == "firebug-lite-debug.js") + { + Env.isDebugMode = true; + } + + // process the + if (Env.browser.document.documentElement.getAttribute("debug") == "true") + { + Env.Options.startOpened = true; + } + + // process the Script URL Options + if (fileOptions) + { + var options = fileOptions.split(","); + + for (var i = 0, length = options.length; i < length; i++) + { + var option = options[i]; + var name, value; + + if (option.indexOf("=") != -1) + { + var parts = option.split("="); + name = parts[0]; + value = eval(unescape(parts[1])); + } + else + { + name = option; + value = true; + } + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Script JSON Options + var innerOptions = FBL.trim(script.innerHTML); + if (innerOptions) + { + var innerOptionsObject = eval("(" + innerOptions + ")"); + + for (var name in innerOptionsObject) + { + var value = innerOptionsObject[name]; + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Debug Mode + if (Env.isDebugMode) + { + Env.Options.startOpened = true; + Env.Options.enableTrace = true; + Env.Options.disableWhenFirebugActive = false; + } + + var loc = Env.Location; + var isProductionRelease = path.indexOf(productionDir) != -1; + + loc.sourceDir = path; + loc.baseDir = path.substr(0, path.length - m[1].length - 1); + loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/"; + loc.skin = loc.skinDir + "firebug.html"; + loc.app = path + fileName; + } + else + { + throw new Error("Firebug Error: Library path not found"); + } +}; + +// ************************************************************************************************ +// Basics + +this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }; +}; + +this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, args); }; +}; + +this.extend = function(l, r) +{ + var newOb = {}; + for (var n in l) + newOb[n] = l[n]; + for (var n in r) + newOb[n] = r[n]; + return newOb; +}; + +this.descend = function(prototypeParent, childProperties) +{ + function protoSetter() {}; + protoSetter.prototype = prototypeParent; + var newOb = new protoSetter(); + for (var n in childProperties) + newOb[n] = childProperties[n]; + return newOb; +}; + +this.append = function(l, r) +{ + for (var n in r) + l[n] = r[n]; + + return l; +}; + +this.keys = function(map) // At least sometimes the keys will be on user-level window objects +{ + var keys = []; + try + { + for (var name in map) // enumeration is safe + keys.push(name); // name is string, safe + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + } + + return keys; // return is safe +}; + +this.values = function(map) +{ + var values = []; + try + { + for (var name in map) + { + try + { + values.push(map[name]); + } + catch (exc) + { + // Sometimes we get exceptions trying to access properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + } + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + return values; +}; + +this.remove = function(list, item) +{ + for (var i = 0; i < list.length; ++i) + { + if (list[i] == item) + { + list.splice(i, 1); + break; + } + } +}; + +this.sliceArray = function(array, index) +{ + var slice = []; + for (var i = index; i < array.length; ++i) + slice.push(array[i]); + + return slice; +}; + +function cloneArray(array, fn) +{ + var newArray = []; + + if (fn) + for (var i = 0; i < array.length; ++i) + newArray.push(fn(array[i])); + else + for (var i = 0; i < array.length; ++i) + newArray.push(array[i]); + + return newArray; +} + +function extendArray(array, array2) +{ + var newArray = []; + newArray.push.apply(newArray, array); + newArray.push.apply(newArray, array2); + return newArray; +} + +this.extendArray = extendArray; +this.cloneArray = cloneArray; + +function arrayInsert(array, index, other) +{ + for (var i = 0; i < other.length; ++i) + array.splice(i+index, 0, other[i]); + + return array; +} + +// ************************************************************************************************ + +this.createStyleSheet = function(doc, url) +{ + //TODO: xxxpedro + //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + var style = this.createElement("link"); + style.setAttribute("charset","utf-8"); + style.firebugIgnore = true; + style.setAttribute("rel", "stylesheet"); + style.setAttribute("type", "text/css"); + style.setAttribute("href", url); + + //TODO: xxxpedro + //style.innerHTML = this.getResource(url); + return style; +}; + +this.addStyleSheet = function(doc, style) +{ + var heads = doc.getElementsByTagName("head"); + if (heads.length) + heads[0].appendChild(style); + else + doc.documentElement.appendChild(style); +}; + +this.appendStylesheet = function(doc, uri) +{ + // Make sure the stylesheet is not appended twice. + if (this.$(uri, doc)) + return; + + var styleSheet = this.createStyleSheet(doc, uri); + styleSheet.setAttribute("id", uri); + this.addStyleSheet(doc, styleSheet); +}; + +this.addScript = function(doc, id, src) +{ + var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script"); + element.setAttribute("type", "text/javascript"); + element.setAttribute("id", id); + if (!FBTrace.DBG_CONSOLE) + FBL.unwrapObject(element).firebugIgnore = true; + + element.innerHTML = src; + if (doc.documentElement) + doc.documentElement.appendChild(element); + else + { + // See issue 1079, the svg test case gives this error + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.addScript doc has no documentElement:", doc); + } + return element; +}; + + +// ************************************************************************************************ + +this.getStyle = this.isIE ? + function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : + function(el, name) + { + return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + }; + + +// ************************************************************************************************ +// Whitespace and Entity conversions + +var entityConversionLists = this.entityConversionLists = { + normal : { + whitespace : { + '\t' : '\u200c\u2192', + '\n' : '\u200c\u00b6', + '\r' : '\u200c\u00ac', + ' ' : '\u200c\u00b7' + } + }, + reverse : { + whitespace : { + ' ' : '\t', + ' ' : '\n', + '\u200c\u2192' : '\t', + '\u200c\u00b6' : '\n', + '\u200c\u00ac' : '\r', + '\u200c\u00b7' : ' ' + } + } +}; + +var normal = entityConversionLists.normal, + reverse = entityConversionLists.reverse; + +function addEntityMapToList(ccode, entity) +{ + var lists = Array.prototype.slice.call(arguments, 2), + len = lists.length, + ch = String.fromCharCode(ccode); + for (var i = 0; i < len; i++) + { + var list = lists[i]; + normal[list]=normal[list] || {}; + normal[list][ch] = '&' + entity + ';'; + reverse[list]=reverse[list] || {}; + reverse[list]['&' + entity + ';'] = ch; + } +}; + +var e = addEntityMapToList, + white = 'whitespace', + text = 'text', + attr = 'attributes', + css = 'css', + editor = 'editor'; + +e(0x0022, 'quot', attr, css); +e(0x0026, 'amp', attr, text, css); +e(0x0027, 'apos', css); +e(0x003c, 'lt', attr, text, css); +e(0x003e, 'gt', attr, text, css); +e(0xa9, 'copy', text, editor); +e(0xae, 'reg', text, editor); +e(0x2122, 'trade', text, editor); + +// See http://en.wikipedia.org/wiki/Dash +e(0x2012, '#8210', attr, text, editor); // figure dash +e(0x2013, 'ndash', attr, text, editor); // en dash +e(0x2014, 'mdash', attr, text, editor); // em dash +e(0x2015, '#8213', attr, text, editor); // horizontal bar + +e(0x00a0, 'nbsp', attr, text, white, editor); +e(0x2002, 'ensp', attr, text, white, editor); +e(0x2003, 'emsp', attr, text, white, editor); +e(0x2009, 'thinsp', attr, text, white, editor); +e(0x200c, 'zwnj', attr, text, white, editor); +e(0x200d, 'zwj', attr, text, white, editor); +e(0x200e, 'lrm', attr, text, white, editor); +e(0x200f, 'rlm', attr, text, white, editor); +e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP) + +//************************************************************************************************ +// Entity escaping + +var entityConversionRegexes = { + normal : {}, + reverse : {} + }; + +var escapeEntitiesRegEx = { + normal : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('([' + chars.join('') + '])', 'gm'); + }, + reverse : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('(' + chars.join('|') + ')', 'gm'); + } +}; + +function getEscapeRegexp(direction, lists) +{ + var name = '', re; + var groups = [].concat(lists); + for (i = 0; i < groups.length; i++) + { + name += groups[i].group; + } + re = entityConversionRegexes[direction][name]; + if (!re) + { + var list = {}; + if (groups.length > 1) + { + for ( var i = 0; i < groups.length; i++) + { + var aList = entityConversionLists[direction][groups[i].group]; + for ( var item in aList) + list[item] = aList[item]; + } + } else if (groups.length==1) + { + list = entityConversionLists[direction][groups[0].group]; // faster for special case + } else { + list = {}; // perhaps should print out an error here? + } + re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list); + } + return re; +}; + +function createSimpleEscape(name, direction) +{ + return function(value) + { + var list = entityConversionLists[direction][name]; + return String(value).replace( + getEscapeRegexp(direction, { + group : name, + list : list + }), + function(ch) + { + return list[ch]; + } + ); + }; +}; + +function escapeGroupsForEntities(str, lists) +{ + lists = [].concat(lists); + var re = getEscapeRegexp('normal', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list, last = ''; + if (!len) + return [ { + str : String(str), + group : '', + name : '' + } ]; + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.normal[list.group][cur]; + // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space + // r = ' '; + if (r) + { + results[ri] = { + 'str' : r, + 'class' : list['class'], + 'extra' : list.extra[cur] ? list['class'] + + list.extra[cur] : '' + }; + break; + } + } + // last=cur; + if (!r) + results[ri] = { + 'str' : cur, + 'class' : '', + 'extra' : '' + }; + ri++; + } + return results; +}; + +this.escapeGroupsForEntities = escapeGroupsForEntities; + + +function unescapeEntities(str, lists) +{ + var re = getEscapeRegexp('reverse', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list; + if (!len) + return str; + lists = [].concat(lists); + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.reverse[list.group][cur]; + if (r) + { + results[ri] = r; + break; + } + } + if (!r) + results[ri] = cur; + ri++; + } + return results.join('') || ''; +}; + + +// ************************************************************************************************ +// String escaping + +var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal'); +var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal'); +var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal'); +var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal'); + +// deprecated compatibility functions +//this.deprecateEscapeHTML = createSimpleEscape('text', 'normal'); +//this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse'); +//this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML); +//this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML); + +var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); + +var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); + +this.unescapeForTextNode = function(str) +{ + if (Firebug.showTextNodesWithWhitespace) + str = unescapeWhitespace(str); + if (!Firebug.showTextNodesWithEntities) + str = escapeForElementAttribute(str); + return str; +}; + +this.escapeNewLines = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); +}; + +this.stripNewLines = function(value) +{ + return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; +}; + +this.escapeJS = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); +}; + +function escapeHTMLAttribute(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "&": + return "&"; + case "'": + return apos; + case '"': + return quot; + } + return "?"; + }; + var apos = "'", quot = """, around = '"'; + if( value.indexOf('"') == -1 ) { + quot = '"'; + apos = "'"; + } else if( value.indexOf("'") == -1 ) { + quot = '"'; + around = "'"; + } + return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; +} + + +function escapeHTML(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); +} + +this.escapeHTML = escapeHTML; + +this.cropString = function(text, limit) +{ + text = text + ""; + + if (!limit) + var halfLimit = 50; + else + var halfLimit = limit / 2; + + if (text.length > limit) + return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); + else + return this.escapeNewLines(text); +}; + +this.isWhitespace = function(text) +{ + return !reNotWhitespace.exec(text); +}; + +this.splitLines = function(text) +{ + var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; + var lines; + if (text.match) + { + lines = text.match(reSplitLines2); + } + else + { + var str = text+""; + lines = str.match(reSplitLines2); + } + lines.pop(); + return lines; +}; + + +// ************************************************************************************************ + +this.safeToString = function(ob) +{ + if (this.isIE) + return ob + ""; + + try + { + if (ob && "toString" in ob && typeof ob.toString == "function") + return ob.toString(); + } + catch (exc) + { + // xxxpedro it is not safe to use ob+""? + return ob + ""; + ///return "[an object with no toString() function]"; + } +}; + +// ************************************************************************************************ + +this.hasProperties = function(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + return false; +}; + +// ************************************************************************************************ +// String Util + +var reTrim = /^\s+|\s+$/g; +this.trim = function(s) +{ + return s.replace(reTrim, ""); +}; + + +// ************************************************************************************************ +// Empty + +this.emptyFn = function(){}; + + + +// ************************************************************************************************ +// Visibility + +this.isVisible = function(elt) +{ + /* + if (elt instanceof XULElement) + { + //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); + return (!elt.hidden && !elt.collapsed); + } + /**/ + + return this.getStyle(elt, "visibility") != "hidden" && + ( elt.offsetWidth > 0 || elt.offsetHeight > 0 + || elt.tagName in invisibleTags + || elt.namespaceURI == "http://www.w3.org/2000/svg" + || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" ); +}; + +this.collapse = function(elt, collapsed) +{ + // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector, + // but it is causing a bug (the element disappears when you set the "collapsed" + // attribute, but it doesn't appear when you remove the attribute. So, for those + // cases, we need to use the class attribute. + if (this.isIElt8) + { + if (collapsed) + this.setClass(elt, "collapsed"); + else + this.removeClass(elt, "collapsed"); + } + else + elt.setAttribute("collapsed", collapsed ? "true" : "false"); +}; + +this.obscure = function(elt, obscured) +{ + if (obscured) + this.setClass(elt, "obscured"); + else + this.removeClass(elt, "obscured"); +}; + +this.hide = function(elt, hidden) +{ + elt.style.visibility = hidden ? "hidden" : "visible"; +}; + +this.clearNode = function(node) +{ + var nodeName = " " + node.nodeName.toLowerCase() + " "; + var ignoreTags = " table tbody thead tfoot th tr td "; + + // IE can't use innerHTML of table elements + if (this.isIE && ignoreTags.indexOf(nodeName) != -1) + this.eraseNode(node); + else + node.innerHTML = ""; +}; + +this.eraseNode = function(node) +{ + while (node.lastChild) + node.removeChild(node.lastChild); +}; + +// ************************************************************************************************ +// Window iteration + +this.iterateWindows = function(win, handler) +{ + if (!win || !win.document) + return; + + handler(win); + + if (win == top || !win.frames) return; // XXXjjb hack for chromeBug + + for (var i = 0; i < win.frames.length; ++i) + { + var subWin = win.frames[i]; + if (subWin != win) + this.iterateWindows(subWin, handler); + } +}; + +this.getRootWindow = function(win) +{ + for (; win; win = win.parent) + { + if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) + return win; + } + return null; +}; + +// ************************************************************************************************ +// Graphics + +this.getClientOffset = function(elt) +{ + var addOffset = function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + + var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, ""); + + if (elt.offsetLeft) + coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth); + if (elt.offsetTop) + coords.y += elt.offsetTop + parseInt(style.borderTopWidth); + + if (p) + { + if (p.nodeType == 1) + addOffset(p, coords, view); + } + else + { + var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + if (otherView.frameElement) + addOffset(otherView.frameElement, coords, otherView); + } + }; + + var isIE = this.isIE; + var coords = {x: 0, y: 0}; + if (elt) + { + var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + addOffset(elt, coords, view); + } + + return coords; +}; + +this.getViewOffset = function(elt, singleFrame) +{ + function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); + coords.y += elt.offsetTop - (p ? p.scrollTop : 0); + + if (p) + { + if (p.nodeType == 1) + { + var parentStyle = view.getComputedStyle(p, ""); + if (parentStyle.position != "static") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + + if (p.localName == "TABLE") + { + coords.x += parseInt(parentStyle.paddingLeft); + coords.y += parseInt(parentStyle.paddingTop); + } + else if (p.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.marginLeft); + coords.y += parseInt(style.marginTop); + } + } + else if (p.localName == "BODY") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + } + + var parent = elt.parentNode; + while (p != parent) + { + coords.x -= parent.scrollLeft; + coords.y -= parent.scrollTop; + parent = parent.parentNode; + } + addOffset(p, coords, view); + } + } + else + { + if (elt.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.borderLeftWidth); + coords.y += parseInt(style.borderTopWidth); + + var htmlStyle = view.getComputedStyle(elt.parentNode, ""); + coords.x -= parseInt(htmlStyle.paddingLeft); + coords.y -= parseInt(htmlStyle.paddingTop); + } + + if (elt.scrollLeft) + coords.x += elt.scrollLeft; + if (elt.scrollTop) + coords.y += elt.scrollTop; + + var win = elt.ownerDocument.defaultView; + if (win && (!singleFrame && win.frameElement)) + addOffset(win.frameElement, coords, win); + } + + } + + var coords = {x: 0, y: 0}; + if (elt) + addOffset(elt, coords, elt.ownerDocument.defaultView); + + return coords; +}; + +this.getLTRBWH = function(elt) +{ + var bcrect, + dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; + + if (elt) + { + bcrect = elt.getBoundingClientRect(); + dims.left = bcrect.left; + dims.top = bcrect.top; + dims.right = bcrect.right; + dims.bottom = bcrect.bottom; + + if(bcrect.width) + { + dims.width = bcrect.width; + dims.height = bcrect.height; + } + else + { + dims.width = dims.right - dims.left; + dims.height = dims.bottom - dims.top; + } + } + return dims; +}; + +this.applyBodyOffsets = function(elt, clientRect) +{ + var od = elt.ownerDocument; + if (!od.body) + return clientRect; + + var style = od.defaultView.getComputedStyle(od.body, null); + + var pos = style.getPropertyValue('position'); + if(pos === 'absolute' || pos === 'relative') + { + var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0; + var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0; + var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0; + var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0; + var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0; + var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0; + + var offsetX = borderLeft + paddingLeft + marginLeft; + var offsetY = borderTop + paddingTop + marginTop; + + clientRect.left -= offsetX; + clientRect.top -= offsetY; + clientRect.right -= offsetX; + clientRect.bottom -= offsetY; + } + + return clientRect; +}; + +this.getOffsetSize = function(elt) +{ + return {width: elt.offsetWidth, height: elt.offsetHeight}; +}; + +this.getOverflowParent = function(element) +{ + for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) + { + if (scrollParent.scrollHeight > scrollParent.offsetHeight) + return scrollParent; + } +}; + +this.isScrolledToBottom = function(element) +{ + var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight; + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom); + return onBottom; +}; + +this.scrollToBottom = function(element) +{ + element.scrollTop = element.scrollHeight; + + if (FBTrace.DBG_CONSOLE) + { + FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); + if (element.scrollHeight == element.offsetHeight) + FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element); + } + + return (element.scrollTop == element.scrollHeight); +}; + +this.move = function(element, x, y) +{ + element.style.left = x + "px"; + element.style.top = y + "px"; +}; + +this.resize = function(element, w, h) +{ + element.style.width = w + "px"; + element.style.height = h + "px"; +}; + +this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} +{ + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var split = (scrollBox.clientHeight/2); + var centerY = offset.y - split; + scrollBox.scrollTop = centerY; + topSpace = split; + bottomSpace = split - element.offsetHeight; + } + + return {before: Math.round((topSpace/element.offsetHeight) + 0.5), + after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; +}; + +this.scrollIntoCenterView = function(element, scrollBox, notX, notY) +{ + if (!element) + return; + + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + if (!notY) + { + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var centerY = offset.y - (scrollBox.clientHeight/2); + scrollBox.scrollTop = centerY; + } + } + + if (!notX) + { + var leftSpace = offset.x - scrollBox.scrollLeft; + var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) + - (offset.x + element.clientWidth); + + if (leftSpace < 0 || rightSpace < 0) + { + var centerX = offset.x - (scrollBox.clientWidth/2); + scrollBox.scrollLeft = centerX; + } + } + if (FBTrace.DBG_SOURCEFILES) + FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); +}; + + +// ************************************************************************************************ +// CSS + +var cssKeywordMap = null; +var cssPropNames = null; +var cssColorNames = null; +var imageRules = null; + +this.getCSSKeywordsByProperty = function(propName) +{ + if (!cssKeywordMap) + { + cssKeywordMap = {}; + + for (var name in this.cssInfo) + { + var list = []; + + var types = this.cssInfo[name]; + for (var i = 0; i < types.length; ++i) + { + var keywords = this.cssKeywords[types[i]]; + if (keywords) + list.push.apply(list, keywords); + } + + cssKeywordMap[name] = list; + } + } + + return propName in cssKeywordMap ? cssKeywordMap[propName] : []; +}; + +this.getCSSPropertyNames = function() +{ + if (!cssPropNames) + { + cssPropNames = []; + + for (var name in this.cssInfo) + cssPropNames.push(name); + } + + return cssPropNames; +}; + +this.isColorKeyword = function(keyword) +{ + if (keyword == "transparent") + return false; + + if (!cssColorNames) + { + cssColorNames = []; + + var colors = this.cssKeywords["color"]; + for (var i = 0; i < colors.length; ++i) + cssColorNames.push(colors[i].toLowerCase()); + + var systemColors = this.cssKeywords["systemColor"]; + for (var i = 0; i < systemColors.length; ++i) + cssColorNames.push(systemColors[i].toLowerCase()); + } + + return cssColorNames.indexOf ? // Array.indexOf is not available in IE + cssColorNames.indexOf(keyword.toLowerCase()) != -1 : + (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; +}; + +this.isImageRule = function(rule) +{ + if (!imageRules) + { + imageRules = []; + + for (var i in this.cssInfo) + { + var r = i.toLowerCase(); + var suffix = "image"; + if (r.match(suffix + "$") == suffix || r == "background") + imageRules.push(r); + } + } + + return imageRules.indexOf ? // Array.indexOf is not available in IE + imageRules.indexOf(rule.toLowerCase()) != -1 : + (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; +}; + +this.copyTextStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.fontFamily = style.fontFamily; + + // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE + // returns wrong computed styles for inherited properties (like font-*) + // + // Also would be good to create a FBL.getStyle() + toNode.style.fontSize = style.fontSize; + toNode.style.fontWeight = style.fontWeight; + toNode.style.fontStyle = style.fontStyle; + + return style; + } +}; + +this.copyBoxStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.marginTop = style.marginTop; + toNode.style.marginRight = style.marginRight; + toNode.style.marginBottom = style.marginBottom; + toNode.style.marginLeft = style.marginLeft; + toNode.style.borderTopWidth = style.borderTopWidth; + toNode.style.borderRightWidth = style.borderRightWidth; + toNode.style.borderBottomWidth = style.borderBottomWidth; + toNode.style.borderLeftWidth = style.borderLeftWidth; + + return style; + } +}; + +this.readBoxStyles = function(style) +{ + var styleNames = { + "margin-top": "marginTop", "margin-right": "marginRight", + "margin-left": "marginLeft", "margin-bottom": "marginBottom", + "border-top-width": "borderTop", "border-right-width": "borderRight", + "border-left-width": "borderLeft", "border-bottom-width": "borderBottom", + "padding-top": "paddingTop", "padding-right": "paddingRight", + "padding-left": "paddingLeft", "padding-bottom": "paddingBottom", + "z-index": "zIndex" + }; + + var styles = {}; + for (var styleName in styleNames) + styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0; + if (FBTrace.DBG_INSPECT) + FBTrace.sysout("readBoxStyles ", styles); + return styles; +}; + +this.getBoxFromStyles = function(style, element) +{ + var args = this.readBoxStyles(style); + args.width = element.offsetWidth + - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight); + args.height = element.offsetHeight + - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom); + return args; +}; + +this.getElementCSSSelector = function(element) +{ + var label = element.localName.toLowerCase(); + if (element.id) + label += "#" + element.id; + if (element.hasAttribute("class")) + label += "." + element.getAttribute("class").split(" ")[0]; + + return label; +}; + +this.getURLForStyleSheet= function(styleSheet) +{ + //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null. + return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL); +}; + +this.getDocumentForStyleSheet = function(styleSheet) +{ + while (styleSheet.parentStyleSheet && !styleSheet.ownerNode) + { + styleSheet = styleSheet.parentStyleSheet; + } + if (styleSheet.ownerNode) + return styleSheet.ownerNode.ownerDocument; +}; + +/** + * Retrieves the instance number for a given style sheet. The instance number + * is sheet's index within the set of all other sheets whose URL is the same. + */ +this.getInstanceForStyleSheet = function(styleSheet, ownerDocument) +{ + // System URLs are always unique (or at least we are making this assumption) + if (FBL.isSystemStyleSheet(styleSheet)) + return 0; + + // ownerDocument is an optional hint for performance + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument); + ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet); + + var ret = 0, + styleSheets = ownerDocument.styleSheets, + href = styleSheet.href; + for (var i = 0; i < styleSheets.length; i++) + { + var curSheet = styleSheets[i]; + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode))); + if (curSheet == styleSheet) + break; + if (curSheet.href == href) + ret++; + } + return ret; +}; + +// ************************************************************************************************ +// HTML and XML Serialization + + +var getElementType = this.getElementType = function(node) +{ + if (isElementXUL(node)) + return 'xul'; + else if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else if (isElementXHTML(node)) + return 'xhtml'; + else if (isElementHTML(node)) + return 'html'; +} + +var getElementSimpleType = this.getElementSimpleType = function(node) +{ + if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else + return 'html'; +} + +var isElementHTML = this.isElementHTML = function(node) +{ + return node.nodeName == node.nodeName.toUpperCase(); +} + +var isElementXHTML = this.isElementXHTML = function(node) +{ + return node.nodeName == node.nodeName.toLowerCase(); +} + +var isElementMathML = this.isElementMathML = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; +} + +var isElementSVG = this.isElementSVG = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/2000/svg'; +} + +var isElementXUL = this.isElementXUL = function(node) +{ + return node instanceof XULElement; +} + +this.isSelfClosing = function(element) +{ + if (isElementSVG(element) || isElementMathML(element)) + return true; + var tag = element.localName.toLowerCase(); + return (this.selfClosingTags.hasOwnProperty(tag)); +}; + +this.getElementHTML = function(element) +{ + var self=this; + function toHTML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + html.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + html.push('>'); + + var pureText=true; + for (var child = element.firstChild; child; child = child.nextSibling) + pureText=pureText && (child.nodeType == Node.TEXT_NODE); + + if (pureText) + html.push(escapeForHtmlEditor(elt.textContent)); + else { + for (var child = elt.firstChild; child; child = child.nextSibling) + toHTML(child); + } + + html.push(''); + } + else if (isElementSVG(elt) || isElementMathML(elt)) + { + html.push('/>'); + } + else if (self.isSelfClosing(elt)) + { + html.push((isElementXHTML(elt))?'/>':'>'); + } + else + { + html.push('>'); + } + } + else if (elt.nodeType == Node.TEXT_NODE) + html.push(escapeForTextNode(elt.textContent)); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + html.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + html.push(''); + } + + var html = []; + toHTML(element); + return html.join(""); +}; + +this.getElementXML = function(element) +{ + function toXML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + xml.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + xml.push('>'); + + for (var child = elt.firstChild; child; child = child.nextSibling) + toXML(child); + + xml.push(''); + } + else + xml.push('/>'); + } + else if (elt.nodeType == Node.TEXT_NODE) + xml.push(elt.nodeValue); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + xml.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + xml.push(''); + } + + var xml = []; + toXML(element); + return xml.join(""); +}; + + +// ************************************************************************************************ +// CSS classes + +this.hasClass = function(node, name) // className, className, ... +{ + // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments? + // this function can be optimized a lot if assumed 2 arguments only, + // which seems to be what happens 99% of the time + if (arguments.length == 2) + return (' '+node.className+' ').indexOf(' '+name+' ') != -1; + + if (!node || node.nodeType != 1) + return false; + else + { + for (var i=1; i= 0) + { + var size = name.length; + node.className = node.className.substr(0,index-1) + node.className.substr(index+size); + } + } +}; + +this.toggleClass = function(elt, name) +{ + if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1) + ///if (this.hasClass(elt, name)) + this.removeClass(elt, name); + else + this.setClass(elt, name); +}; + +this.setClassTimed = function(elt, name, context, timeout) +{ + if (!timeout) + timeout = 1300; + + if (elt.__setClassTimeout) + context.clearTimeout(elt.__setClassTimeout); + else + this.setClass(elt, name); + + elt.__setClassTimeout = context.setTimeout(function() + { + delete elt.__setClassTimeout; + + FBL.removeClass(elt, name); + }, timeout); +}; + +this.cancelClassTimed = function(elt, name, context) +{ + if (elt.__setClassTimeout) + { + FBL.removeClass(elt, name); + context.clearTimeout(elt.__setClassTimeout); + delete elt.__setClassTimeout; + } +}; + + +// ************************************************************************************************ +// DOM queries + +this.$ = function(id, doc) +{ + if (doc) + return doc.getElementById(id); + else + { + return FBL.Firebug.chrome.document.getElementById(id); + } +}; + +this.$$ = function(selector, doc) +{ + if (doc || !FBL.Firebug.chrome) + return FBL.Firebug.Selector(selector, doc); + else + { + return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document); + } +}; + +this.getChildByClass = function(node) // ,classname, classname, classname... +{ + for (var i = 1; i < arguments.length; ++i) + { + var className = arguments[i]; + var child = node.firstChild; + node = null; + for (; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + { + node = child; + break; + } + } + } + + return node; +}; + +this.getAncestorByClass = function(node, className) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (this.hasClass(parent, className)) + return parent; + } + + return null; +}; + + +this.getElementsByClass = function(node, className) +{ + var result = []; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + result.push(child); + } + + return result; +}; + +this.getElementByClass = function(node, className) // className, className, ... +{ + var args = cloneArray(arguments); args.splice(0, 1); + for (var child = node.firstChild; child; child = child.nextSibling) + { + var args1 = cloneArray(args); args1.unshift(child); + if (FBL.hasClass.apply(null, args1)) + return child; + else + { + var found = FBL.getElementByClass.apply(null, args1); + if (found) + return found; + } + } + + return null; +}; + +this.isAncestor = function(node, potentialAncestor) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (parent == potentialAncestor) + return true; + } + + return false; +}; + +this.getNextElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.nextSibling; + + return node; +}; + +this.getPreviousElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.previousSibling; + + return node; +}; + +this.getBody = function(doc) +{ + if (doc.body) + return doc.body; + + var body = doc.getElementsByTagName("body")[0]; + if (body) + return body; + + return doc.firstChild; // For non-HTML docs +}; + +this.findNextDown = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (criteria(child)) + return child; + + var next = this.findNextDown(child, criteria); + if (next) + return next; + } +}; + +this.findPreviousUp = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.lastChild; child; child = child.previousSibling) + { + var next = this.findPreviousUp(child, criteria); + if (next) + return next; + + if (criteria(child)) + return child; + } +}; + +this.findNext = function(node, criteria, upOnly, maxRoot) +{ + if (!node) + return null; + + if (!upOnly) + { + var next = this.findNextDown(node, criteria); + if (next) + return next; + } + + for (var sib = node.nextSibling; sib; sib = sib.nextSibling) + { + if (criteria(sib)) + return sib; + + var next = this.findNextDown(sib, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + return this.findNext(node.parentNode, criteria, true); +}; + +this.findPrevious = function(node, criteria, downOnly, maxRoot) +{ + if (!node) + return null; + + for (var sib = node.previousSibling; sib; sib = sib.previousSibling) + { + var prev = this.findPreviousUp(sib, criteria); + if (prev) + return prev; + + if (criteria(sib)) + return sib; + } + + if (!downOnly) + { + var next = this.findPreviousUp(node, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + { + if (criteria(node.parentNode)) + return node.parentNode; + + return this.findPrevious(node.parentNode, criteria, true); + } +}; + +this.getNextByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findNext(root, iter); +}; + +this.getPreviousByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findPrevious(root, iter); +}; + +this.isElement = function(o) +{ + try { + return o && this.instanceOf(o, "Element"); + } + catch (ex) { + return false; + } +}; + + +// ************************************************************************************************ +// DOM Modification + +// TODO: xxxpedro use doc fragments in Context API +var appendFragment = null; + +this.appendInnerHTML = function(element, html, referenceElement) +{ + // if undefined, we must convert it to null otherwise it will throw an error in IE + // when executing element.insertBefore(firstChild, referenceElement) + referenceElement = referenceElement || null; + + var doc = element.ownerDocument; + + // doc.createRange not available in IE + if (doc.createRange) + { + var range = doc.createRange(); // a helper object + range.selectNodeContents(element); // the environment to interpret the html + + var fragment = range.createContextualFragment(html); // parse + var firstChild = fragment.firstChild; + element.insertBefore(fragment, referenceElement); + } + else + { + if (!appendFragment || appendFragment.ownerDocument != doc) + appendFragment = doc.createDocumentFragment(); + + var div = doc.createElement("div"); + div.innerHTML = html; + + var firstChild = div.firstChild; + while (div.firstChild) + appendFragment.appendChild(div.firstChild); + + element.insertBefore(appendFragment, referenceElement); + + div = null; + } + + return firstChild; +}; + + +// ************************************************************************************************ +// DOM creation + +this.createElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = properties.document || FBL.Firebug.chrome.document; + + var element = doc.createElement(tagName); + + for(var name in properties) + { + if (name != "document") + { + element[name] = properties[name]; + } + } + + return element; +}; + +this.createGlobalElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = FBL.Env.browser.document; + + var element = this.NS && doc.createElementNS ? + doc.createElementNS(FBL.NS, tagName) : + doc.createElement(tagName); + + for(var name in properties) + { + var propname = name; + if (FBL.isIE && name == "class") propname = "className"; + + if (name != "document") + { + element.setAttribute(propname, properties[name]); + } + } + + return element; +}; + +//************************************************************************************************ + +this.safeGetWindowLocation = function(window) +{ + try + { + if (window) + { + if (window.closed) + return "(window.closed)"; + if ("location" in window) + return window.location+""; + else + return "(no window.location)"; + } + else + return "(no context.window)"; + } + catch(exc) + { + if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS) + FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc); + FBTrace.sysout("TabContext.getWindowLocation failed window:", window); + return "(getWindowLocation: "+exc+")"; + } +}; + +// ************************************************************************************************ +// Events + +this.isLeftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && // others + this.noKeyModifiers(event); +}; + +this.isMiddleClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 4 : // IE "click" and "dblclick" button model + event.button == 1) && + this.noKeyModifiers(event); +}; + +this.isRightClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 2 : // IE "click" and "dblclick" button model + event.button == 2) && + this.noKeyModifiers(event); +}; + +this.noKeyModifiers = function(event) +{ + return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey; +}; + +this.isControlClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isControl(event); +}; + +this.isShiftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isShift(event); +}; + +this.isControl = function(event) +{ + return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; +}; + +this.isAlt = function(event) +{ + return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey; +}; + +this.isAltClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isAlt(event); +}; + +this.isControlShift = function(event) +{ + return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey; +}; + +this.isShift = function(event) +{ + return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey; +}; + +this.addEvent = function(object, name, handler, useCapture) +{ + if (object.addEventListener) + object.addEventListener(name, handler, useCapture); + else + object.attachEvent("on"+name, handler); +}; + +this.removeEvent = function(object, name, handler, useCapture) +{ + try + { + if (object.removeEventListener) + object.removeEventListener(name, handler, useCapture); + else + object.detachEvent("on"+name, handler); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("FBL.removeEvent error: ", object, name); + } +}; + +this.cancelEvent = function(e, preventDefault) +{ + if (!e) return; + + if (preventDefault) + { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + } + + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.addGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.addEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.addEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.addEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +this.removeGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.removeEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.removeEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.removeEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.dispatch = function(listeners, name, args) +{ + if (!listeners) return; + + try + {/**/ + if (typeof listeners.length != "undefined") + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); + + for (var i = 0; i < listeners.length; ++i) + { + var listener = listeners[i]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + else + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object"); + + for (var prop in listeners) + { + var listener = listeners[prop]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout(" Exception in lib.dispatch "+ name, exc); + //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener); + } + } + /**/ +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var disableTextSelectionHandler = function(event) +{ + FBL.cancelEvent(event, true); + + return false; +}; + +this.disableTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.addEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.addEvent(e, "mousedown", disableTextSelectionHandler); + } + + e.style.cursor = "default"; +}; + +this.restoreTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.removeEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "cursor: default;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.removeEvent(e, "mousedown", disableTextSelectionHandler); + } +}; + +// ************************************************************************************************ +// DOM Events + +var eventTypes = +{ + composition: [ + "composition", + "compositionstart", + "compositionend" ], + contextmenu: [ + "contextmenu" ], + drag: [ + "dragenter", + "dragover", + "dragexit", + "dragdrop", + "draggesture" ], + focus: [ + "focus", + "blur" ], + form: [ + "submit", + "reset", + "change", + "select", + "input" ], + key: [ + "keydown", + "keyup", + "keypress" ], + load: [ + "load", + "beforeunload", + "unload", + "abort", + "error" ], + mouse: [ + "mousedown", + "mouseup", + "click", + "dblclick", + "mouseover", + "mouseout", + "mousemove" ], + mutation: [ + "DOMSubtreeModified", + "DOMNodeInserted", + "DOMNodeRemoved", + "DOMNodeRemovedFromDocument", + "DOMNodeInsertedIntoDocument", + "DOMAttrModified", + "DOMCharacterDataModified" ], + paint: [ + "paint", + "resize", + "scroll" ], + scroll: [ + "overflow", + "underflow", + "overflowchanged" ], + text: [ + "text" ], + ui: [ + "DOMActivate", + "DOMFocusIn", + "DOMFocusOut" ], + xul: [ + "popupshowing", + "popupshown", + "popuphiding", + "popuphidden", + "close", + "command", + "broadcast", + "commandupdate" ] +}; + +this.getEventFamily = function(eventType) +{ + if (!this.families) + { + this.families = {}; + + for (var family in eventTypes) + { + var types = eventTypes[family]; + for (var i = 0; i < types.length; ++i) + this.families[types[i]] = family; + } + } + + return this.families[eventType]; +}; + + +// ************************************************************************************************ +// URLs + +this.getFileName = function(url) +{ + var split = this.splitURLBase(url); + return split.name; +}; + +this.splitURLBase = function(url) +{ + if (this.isDataURL(url)) + return this.splitDataURL(url); + return this.splitURLTrue(url); +}; + +this.splitDataURL = function(url) +{ + var mark = url.indexOf(':', 3); + if (mark != 4) + return false; // the first 5 chars must be 'data:' + + var point = url.indexOf(',', mark+1); + if (point < mark) + return false; // syntax error + + var props = { encodedContent: url.substr(point+1) }; + + var metadataBuffer = url.substr(mark+1, point); + var metadata = metadataBuffer.split(';'); + for (var i = 0; i < metadata.length; i++) + { + var nv = metadata[i].split('='); + if (nv.length == 2) + props[nv[0]] = nv[1]; + } + + // Additional Firebug-specific properties + if (props.hasOwnProperty('fileName')) + { + var caller_URL = decodeURIComponent(props['fileName']); + var caller_split = this.splitURLTrue(caller_URL); + + if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval() + { + props['path'] = caller_split.path; + props['line'] = props['baseLineNumber']; + var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + props['name'] = 'eval->'+hint; + } + else + { + props['name'] = caller_split.name; + props['path'] = caller_split.path; + } + } + else + { + if (!props.hasOwnProperty('path')) + props['path'] = "data:"; + if (!props.hasOwnProperty('name')) + props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + } + + return props; +}; + +this.splitURLTrue = function(url) +{ + var m = reSplitFile.exec(url); + if (!m) + return {name: url, path: url}; + else if (!m[2]) + return {path: m[1], name: m[1]}; + else + return {path: m[1], name: m[2]+m[3]}; +}; + +this.getFileExtension = function(url) +{ + if (!url) + return null; + + // Remove query string from the URL if any. + var queryString = url.indexOf("?"); + if (queryString != -1) + url = url.substr(0, queryString); + + // Now get the file extension. + var lastDot = url.lastIndexOf("."); + return url.substr(lastDot+1); +}; + +this.isSystemURL = function(url) +{ + if (!url) return true; + if (url.length == 0) return true; + if (url[0] == 'h') return false; + if (url.substr(0, 9) == "resource:") + return true; + else if (url.substr(0, 16) == "chrome://firebug") + return true; + else if (url == "XPCSafeJSObjectWrapper.cpp") + return true; + else if (url.substr(0, 6) == "about:") + return true; + else if (url.indexOf("firebug-service.js") != -1) + return true; + else + return false; +}; + +this.isSystemPage = function(win) +{ + try + { + var doc = win.document; + if (!doc) + return false; + + // Detect pages for pretty printed XML + if ((doc.styleSheets.length && doc.styleSheets[0].href + == "chrome://global/content/xml/XMLPrettyPrint.css") + || (doc.styleSheets.length > 1 && doc.styleSheets[1].href + == "chrome://browser/skin/feeds/subscribe.css")) + return true; + + return FBL.isSystemURL(win.location.href); + } + catch (exc) + { + // Sometimes documents just aren't ready to be manipulated here, but don't let that + // gum up the works + ERROR("tabWatcher.isSystemPage document not ready:"+ exc); + return false; + } +}; + +this.isSystemStyleSheet = function(sheet) +{ + var href = sheet && sheet.href; + return href && FBL.isSystemURL(href); +}; + +this.getURIHost = function(uri) +{ + try + { + if (uri) + return uri.host; + else + return ""; + } + catch (exc) + { + return ""; + } +}; + +this.isLocalURL = function(url) +{ + if (url.substr(0, 5) == "file:") + return true; + else if (url.substr(0, 8) == "wyciwyg:") + return true; + else + return false; +}; + +this.isDataURL = function(url) +{ + return (url && url.substr(0,5) == "data:"); +}; + +this.getLocalPath = function(url) +{ + if (this.isLocalURL(url)) + { + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var file = fileHandler.getFileFromURLSpec(url); + return file.path; + } +}; + +this.getURLFromLocalFile = function(file) +{ + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var URL = fileHandler.getURLSpecFromFile(file); + return URL; +}; + +this.getDataURLForContent = function(content, url) +{ + // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10, + var uri = "data:text/html;"; + uri += "fileName="+encodeURIComponent(url)+ ","; + uri += encodeURIComponent(content); + return uri; +}, + +this.getDomain = function(url) +{ + var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url); + return m ? m[1] : ""; +}; + +this.getURLPath = function(url) +{ + var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); + return m ? m[1] : ""; +}; + +this.getPrettyDomain = function(url) +{ + var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); + return m ? m[2] : ""; +}; + +this.absoluteURL = function(url, baseURL) +{ + return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g"); +}; + +this.absoluteURLWithDots = function(url, baseURL) +{ + if (url[0] == "?") + return baseURL + url; + + var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/; + var m = reURL.exec(url); + if (m) + return url; + + var m = reURL.exec(baseURL); + if (!m) + return ""; + + var head = m[1]; + var tail = m[3]; + if (url.substr(0, 2) == "//") + return m[2] + url; + else if (url[0] == "/") + { + return head + url; + } + else if (tail[tail.length-1] == "/") + return baseURL + url; + else + { + var parts = tail.split("/"); + return head + parts.slice(0, parts.length-1).join("/") + "/" + url; + } +}; + +this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome +{ + if (!url) + return ""; + // Replace one or more characters that are not forward-slash followed by /.., by space. + if (url.length < 255) // guard against monsters. + { + // Replace one or more characters that are not forward-slash followed by /.., by space. + url = url.replace(/[^\/]+\/\.\.\//, "", "g"); + // Issue 1496, avoid # + url = url.replace(/#.*/,""); + // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they + // don't match up with the URLs we get back from the DOM + url = url.replace(/file:\/([^\/])/g, "file:///$1"); + if (url.indexOf('chrome:')==0) + { + var m = reChromeCase.exec(url); // 1 is package name, 2 is path + if (m) + { + url = "chrome://"+m[1].toLowerCase()+"/"+m[2]; + } + } + } + return url; +}; + +this.denormalizeURL = function(url) +{ + return url.replace(/file:\/\/\//g, "file:/"); +}; + +this.parseURLParams = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedText(search); +}; + +this.parseURLEncodedText = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: ""}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +// TODO: xxxpedro lib. why loops in domplate are requiring array in parameters +// as in response/request headers and get/post parameters in Net module? +this.parseURLParamsArray = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedTextArray(search); +}; + +this.parseURLEncodedTextArray = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: [""]}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +this.reEncodeURL = function(file, text) +{ + var lines = text.split("\n"); + var params = this.parseURLEncodedText(lines[lines.length-1]); + + var args = []; + for (var i = 0; i < params.length; ++i) + args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); + + var url = file.href; + url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); + + return url; +}; + +this.getResource = function(aURL) +{ + try + { + var channel=ioService.newChannel(aURL,null,null); + var input=channel.open(); + return FBL.readFromStream(input); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getResource FAILS for "+aURL, e); + } +}; + +this.parseJSONString = function(jsonString, originURL) +{ + // See if this is a Prototype style *-secure request. + var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/); + var matches = regex.exec(jsonString); + + if (matches) + { + jsonString = matches[1]; + + if (jsonString[0] == "\\" && jsonString[1] == "n") + jsonString = jsonString.substr(2); + + if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") + jsonString = jsonString.substr(0, jsonString.length-2); + } + + if (jsonString.indexOf("&&&START&&&")) + { + regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); + matches = regex.exec(jsonString); + if (matches) + jsonString = matches[1]; + } + + // throw on the extra parentheses + jsonString = "(" + jsonString + ")"; + + ///var s = Components.utils.Sandbox(originURL); + var jsonObject = null; + + try + { + ///jsonObject = Components.utils.evalInSandbox(jsonString, s); + + //jsonObject = Firebug.context.eval(jsonString); + jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;}); + } + catch(e) + { + /*** + if (e.message.indexOf("is not defined")) + { + var parts = e.message.split(" "); + s[parts[0]] = function(str){ return str; }; + try { + jsonObject = Components.utils.evalInSandbox(jsonString, s); + } catch(ex) { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + } + } + else + {/**/ + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + ///} + } + + return jsonObject; +}; + +// ************************************************************************************************ + +this.objectToString = function(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +// Input Caret Position + +this.setSelectionRange = function(input, start, length) +{ + if (input.createTextRange) + { + var range = input.createTextRange(); + range.moveStart("character", start); + range.moveEnd("character", length - input.value.length); + range.select(); + } + else if (input.setSelectionRange) + { + input.setSelectionRange(start, length); + input.focus(); + } +}; + +// ************************************************************************************************ +// Input Selection Start / Caret Position + +this.getInputSelectionStart = function(input) +{ + if (document.selection) + { + var range = input.ownerDocument.selection.createRange(); + var text = range.text; + + //console.log("range", range.text); + + // if there is a selection, find the start position + if (text) + { + return input.value.indexOf(text); + } + // if there is no selection, find the caret position + else + { + range.moveStart("character", -input.value.length); + + return range.text.length; + } + } + else if (typeof input.selectionStart != "undefined") + return input.selectionStart; + + return 0; +}; + +// ************************************************************************************************ +// Opera Tab Fix + +function onOperaTabBlur(e) +{ + if (this.lastKey == 9) + this.focus(); +}; + +function onOperaTabKeyDown(e) +{ + this.lastKey = e.keyCode; +}; + +function onOperaTabFocus(e) +{ + this.lastKey = null; +}; + +this.fixOperaTabKey = function(el) +{ + el.onfocus = onOperaTabFocus; + el.onblur = onOperaTabBlur; + el.onkeydown = onOperaTabKeyDown; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.Property = function(object, name) +{ + this.object = object; + this.name = name; + + this.getObject = function() + { + return object[name]; + }; +}; + +this.ErrorCopy = function(message) +{ + this.message = message; +}; + +function EventCopy(event) +{ + // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to + // represent them long term in the inspector. + for (var name in event) + { + try { + this[name] = event[name]; + } catch (exc) { } + } +} + +this.EventCopy = EventCopy; + + +// ************************************************************************************************ +// Type Checking + +var toString = Object.prototype.toString; +var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; + +this.isArray = function(object) { + return toString.call(object) === '[object Array]'; +}; + +this.isFunction = function(object) { + if (!object) return false; + + return toString.call(object) === "[object Function]" || + this.isIE && typeof object != "string" && reFunction.test(""+object); +}; + + +// ************************************************************************************************ +// Instance Checking + +this.instanceOf = function(object, className) +{ + if (!object || typeof object != "object") + return false; + + // Try to use the native instanceof operator. We can only use it when we know + // exactly the window where the object is located at + if (object.ownerDocument) + { + // find the correct window of the object + var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow; + + // if the class is accessible in the window, uses the native instanceof operator + // if the instanceof evaluates to "true" we can assume it is a instance, but if it + // evaluates to "false" we must continue with the duck type detection below because + // the native object may be extended, thus breaking the instanceof result + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (className in win && object instanceof win[className]) + return true; + } + // If the object doesn't have the ownerDocument property, we'll try to look at + // the current context's window + else + { + // TODO: xxxpedro context + // Since we're not using yet a Firebug.context, we'll just use the top window + // (browser) as a reference + var win = Firebug.browser.window; + if (className in win) + return object instanceof win[className]; + } + + // get the duck type model from the cache + var cache = instanceCheckMap[className]; + if (!cache) + return false; + + // starts the hacky duck type detection + for(var n in cache) + { + var obj = cache[n]; + var type = typeof obj; + obj = type == "object" ? obj : [obj]; + + for(var name in obj) + { + // avoid problems with extended native objects + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (!obj.hasOwnProperty(name)) + continue; + + var value = obj[name]; + + if( n == "property" && !(value in object) || + n == "method" && !this.isFunction(object[value]) || + n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) + return false; + } + } + + return true; +}; + +var instanceCheckMap = +{ + // DuckTypeCheck: + // { + // property: ["window", "document"], + // method: "setTimeout", + // value: {nodeType: 1} + // }, + + Window: + { + property: ["window", "document"], + method: "setTimeout" + }, + + Document: + { + property: ["body", "cookie"], + method: "getElementById" + }, + + Node: + { + property: "ownerDocument", + method: "appendChild" + }, + + Element: + { + property: "tagName", + value: {nodeType: 1} + }, + + Location: + { + property: ["hostname", "protocol"], + method: "assign" + }, + + HTMLImageElement: + { + property: "useMap", + value: + { + nodeType: 1, + tagName: "img" + } + }, + + HTMLAnchorElement: + { + property: "hreflang", + value: + { + nodeType: 1, + tagName: "a" + } + }, + + HTMLInputElement: + { + property: "form", + value: + { + nodeType: 1, + tagName: "input" + } + }, + + HTMLButtonElement: + { + // ? + }, + + HTMLFormElement: + { + method: "submit", + value: + { + nodeType: 1, + tagName: "form" + } + }, + + HTMLBodyElement: + { + + }, + + HTMLHtmlElement: + { + + }, + + CSSStyleRule: + { + property: ["selectorText", "style"] + } + +}; + + +// ************************************************************************************************ +// DOM Constants + +/* + +Problems: + + - IE does not have window.Node, window.Element, etc + - for (var name in Node.prototype) return nothing on FF + +*/ + + +var domMemberMap2 = {}; + +var domMemberMap2Sandbox = null; + +var getDomMemberMap2 = function(name) +{ + if (!domMemberMap2Sandbox) + { + var doc = Firebug.chrome.document; + var frame = doc.createElement("iframe"); + + frame.id = "FirebugSandbox"; + frame.style.display = "none"; + frame.src = "about:blank"; + + doc.body.appendChild(frame); + + domMemberMap2Sandbox = frame.window || frame.contentWindow; + } + + var props = []; + + //var object = domMemberMap2Sandbox[name]; + //object = object.prototype || object; + + var object = null; + + if (name == "Window") + object = domMemberMap2Sandbox.window; + + else if (name == "Document") + object = domMemberMap2Sandbox.document; + + else if (name == "HTMLScriptElement") + object = domMemberMap2Sandbox.document.createElement("script"); + + else if (name == "HTMLAnchorElement") + object = domMemberMap2Sandbox.document.createElement("a"); + + else if (name.indexOf("Element") != -1) + { + object = domMemberMap2Sandbox.document.createElement("div"); + } + + if (object) + { + //object = object.prototype || object; + + //props = 'addEventListener,document,location,navigator,window'.split(','); + + for (var n in object) + props.push(n); + } + /**/ + + return props; + return extendArray(props, domMemberMap[name]); +}; + +// xxxpedro experimental get DOM members +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + FBL.domMemberCache = domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = getDomMemberMap2(name); + var cache = domMemberCache[name] = {}; + + /* + if (name.indexOf("Element") != -1) + { + this.append(cache, this.getDOMMembers("Node")); + this.append(cache, this.getDOMMembers("Element")); + } + /**/ + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument")) + { return domMemberCache.Document; } + else if (this.instanceOf(object, "Location")) + { return domMemberCache.Location; } + else if (this.instanceOf(object, "HTMLImageElement")) + { return domMemberCache.HTMLImageElement; } + else if (this.instanceOf(object, "HTMLAnchorElement")) + { return domMemberCache.HTMLAnchorElement; } + else if (this.instanceOf(object, "HTMLInputElement")) + { return domMemberCache.HTMLInputElement; } + else if (this.instanceOf(object, "HTMLButtonElement")) + { return domMemberCache.HTMLButtonElement; } + else if (this.instanceOf(object, "HTMLFormElement")) + { return domMemberCache.HTMLFormElement; } + else if (this.instanceOf(object, "HTMLBodyElement")) + { return domMemberCache.HTMLBodyElement; } + else if (this.instanceOf(object, "HTMLHtmlElement")) + { return domMemberCache.HTMLHtmlElement; } + else if (this.instanceOf(object, "HTMLScriptElement")) + { return domMemberCache.HTMLScriptElement; } + else if (this.instanceOf(object, "HTMLTableElement")) + { return domMemberCache.HTMLTableElement; } + else if (this.instanceOf(object, "HTMLTableRowElement")) + { return domMemberCache.HTMLTableRowElement; } + else if (this.instanceOf(object, "HTMLTableCellElement")) + { return domMemberCache.HTMLTableCellElement; } + else if (this.instanceOf(object, "HTMLIFrameElement")) + { return domMemberCache.HTMLIFrameElement; } + else if (this.instanceOf(object, "SVGSVGElement")) + { return domMemberCache.SVGSVGElement; } + else if (this.instanceOf(object, "SVGElement")) + { return domMemberCache.SVGElement; } + else if (this.instanceOf(object, "Element")) + { return domMemberCache.Element; } + else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection")) + { return domMemberCache.Text; } + else if (this.instanceOf(object, "Attr")) + { return domMemberCache.Attr; } + else if (this.instanceOf(object, "Node")) + { return domMemberCache.Node; } + else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy")) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getDOMMembers FAILED ", E); + + return {}; + } +}; + + +/* +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = domMemberMap[name]; + var cache = domMemberCache[name] = {}; + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (object instanceof Document || object instanceof XMLDocument) + { return domMemberCache.Document; } + else if (object instanceof Location) + { return domMemberCache.Location; } + else if (object instanceof HTMLImageElement) + { return domMemberCache.HTMLImageElement; } + else if (object instanceof HTMLAnchorElement) + { return domMemberCache.HTMLAnchorElement; } + else if (object instanceof HTMLInputElement) + { return domMemberCache.HTMLInputElement; } + else if (object instanceof HTMLButtonElement) + { return domMemberCache.HTMLButtonElement; } + else if (object instanceof HTMLFormElement) + { return domMemberCache.HTMLFormElement; } + else if (object instanceof HTMLBodyElement) + { return domMemberCache.HTMLBodyElement; } + else if (object instanceof HTMLHtmlElement) + { return domMemberCache.HTMLHtmlElement; } + else if (object instanceof HTMLScriptElement) + { return domMemberCache.HTMLScriptElement; } + else if (object instanceof HTMLTableElement) + { return domMemberCache.HTMLTableElement; } + else if (object instanceof HTMLTableRowElement) + { return domMemberCache.HTMLTableRowElement; } + else if (object instanceof HTMLTableCellElement) + { return domMemberCache.HTMLTableCellElement; } + else if (object instanceof HTMLIFrameElement) + { return domMemberCache.HTMLIFrameElement; } + else if (object instanceof SVGSVGElement) + { return domMemberCache.SVGSVGElement; } + else if (object instanceof SVGElement) + { return domMemberCache.SVGElement; } + else if (object instanceof Element) + { return domMemberCache.Element; } + else if (object instanceof Text || object instanceof CDATASection) + { return domMemberCache.Text; } + else if (object instanceof Attr) + { return domMemberCache.Attr; } + else if (object instanceof Node) + { return domMemberCache.Node; } + else if (object instanceof Event || object instanceof EventCopy) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + return {}; + } +}; +/**/ + +this.isDOMMember = function(object, propName) +{ + var members = this.getDOMMembers(object); + return members && propName in members; +}; + +var domMemberCache = null; +var domMemberMap = {}; + +domMemberMap.Window = +[ + "document", + "frameElement", + + "innerWidth", + "innerHeight", + "outerWidth", + "outerHeight", + "screenX", + "screenY", + "pageXOffset", + "pageYOffset", + "scrollX", + "scrollY", + "scrollMaxX", + "scrollMaxY", + + "status", + "defaultStatus", + + "parent", + "opener", + "top", + "window", + "content", + "self", + + "location", + "history", + "frames", + "navigator", + "screen", + "menubar", + "toolbar", + "locationbar", + "personalbar", + "statusbar", + "directories", + "scrollbars", + "fullScreen", + "netscape", + "java", + "console", + "Components", + "controllers", + "closed", + "crypto", + "pkcs11", + + "name", + "property", + "length", + + "sessionStorage", + "globalStorage", + + "setTimeout", + "setInterval", + "clearTimeout", + "clearInterval", + "addEventListener", + "removeEventListener", + "dispatchEvent", + "getComputedStyle", + "captureEvents", + "releaseEvents", + "routeEvent", + "enableExternalCapture", + "disableExternalCapture", + "moveTo", + "moveBy", + "resizeTo", + "resizeBy", + "scroll", + "scrollTo", + "scrollBy", + "scrollByLines", + "scrollByPages", + "sizeToContent", + "setResizable", + "getSelection", + "open", + "openDialog", + "close", + "alert", + "confirm", + "prompt", + "dump", + "focus", + "blur", + "find", + "back", + "forward", + "home", + "stop", + "print", + "atob", + "btoa", + "updateCommands", + "XPCNativeWrapper", + "GeckoActiveXObject", + "applicationCache" // FF3 +]; + +domMemberMap.Location = +[ + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + + "assign", + "reload", + "replace" +]; + +domMemberMap.Node = +[ + "id", + "className", + + "nodeType", + "tagName", + "nodeName", + "localName", + "prefix", + "namespaceURI", + "nodeValue", + + "ownerDocument", + "parentNode", + "offsetParent", + "nextSibling", + "previousSibling", + "firstChild", + "lastChild", + "childNodes", + "attributes", + + "dir", + "baseURI", + "textContent", + "innerHTML", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]; + +domMemberMap.Document = extendArray(domMemberMap.Node, +[ + "documentElement", + "body", + "title", + "location", + "referrer", + "cookie", + "contentType", + "lastModified", + "characterSet", + "inputEncoding", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "strictErrorChecking", + "documentURI", + "URL", + + "defaultView", + "doctype", + "implementation", + "styleSheets", + "images", + "links", + "forms", + "anchors", + "embeds", + "plugins", + "applets", + + "width", + "height", + + "designMode", + "compatMode", + "async", + "preferredStylesheetSet", + + "alinkColor", + "linkColor", + "vlinkColor", + "bgColor", + "fgColor", + "domain", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "captureEvents", + "releaseEvents", + "routeEvent", + "clear", + "open", + "close", + "execCommand", + "execCommandShowHelp", + "getElementsByName", + "getSelection", + "queryCommandEnabled", + "queryCommandIndeterm", + "queryCommandState", + "queryCommandSupported", + "queryCommandText", + "queryCommandValue", + "write", + "writeln", + "adoptNode", + "appendChild", + "removeChild", + "renameNode", + "cloneNode", + "compareDocumentPosition", + "createAttribute", + "createAttributeNS", + "createCDATASection", + "createComment", + "createDocumentFragment", + "createElement", + "createElementNS", + "createEntityReference", + "createEvent", + "createExpression", + "createNSResolver", + "createNodeIterator", + "createProcessingInstruction", + "createRange", + "createTextNode", + "createTreeWalker", + "domConfig", + "evaluate", + "evaluateFIXptr", + "evaluateXPointer", + "getAnonymousElementByAttribute", + "getAnonymousNodes", + "addBinding", + "removeBinding", + "getBindingParent", + "getBoxObjectFor", + "setBoxObjectFor", + "getElementById", + "getElementsByTagName", + "getElementsByTagNameNS", + "hasAttributes", + "hasChildNodes", + "importNode", + "insertBefore", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "load", + "loadBindingDocument", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "normalizeDocument", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.Element = extendArray(domMemberMap.Node, +[ + "clientWidth", + "clientHeight", + "offsetLeft", + "offsetTop", + "offsetWidth", + "offsetHeight", + "scrollLeft", + "scrollTop", + "scrollWidth", + "scrollHeight", + + "style", + + "tabIndex", + "title", + "lang", + "align", + "spellcheck", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "focus", + "blur", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "getElementsByTagName", + "getElementsByTagNameNS", + "getAttribute", + "getAttributeNS", + "getAttributeNode", + "getAttributeNodeNS", + "setAttribute", + "setAttributeNS", + "setAttributeNode", + "setAttributeNodeNS", + "removeAttribute", + "removeAttributeNS", + "removeAttributeNode", + "hasAttribute", + "hasAttributeNS", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.SVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + "href", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getPresentationAttribute", + "preserveAspectRatio" +]); + +domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + + "viewBox", + "viewport", + "currentView", + "useCurrentView", + "pixelUnitToMillimeterX", + "pixelUnitToMillimeterY", + "screenPixelToMillimeterX", + "screenPixelToMillimeterY", + "currentScale", + "currentTranslate", + "zoomAndPan", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + "contentScriptType", + "contentStyleType", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getEnclosureList", + "getIntersectionList", + "getViewboxToViewportTransform", + "getPresentationAttribute", + "getElementById", + "checkEnclosure", + "checkIntersection", + "createSVGAngle", + "createSVGLength", + "createSVGMatrix", + "createSVGNumber", + "createSVGPoint", + "createSVGRect", + "createSVGString", + "createSVGTransform", + "createSVGTransformFromMatrix", + "deSelectAll", + "preserveAspectRatio", + "forceRedraw", + "suspendRedraw", + "unsuspendRedraw", + "unsuspendRedrawAll", + "getCurrentTime", + "setCurrentTime", + "animationsPaused", + "pauseAnimations", + "unpauseAnimations" +]); + +domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element, +[ + "src", + "naturalWidth", + "naturalHeight", + "width", + "height", + "x", + "y", + "name", + "alt", + "longDesc", + "lowsrc", + "border", + "complete", + "hspace", + "vspace", + "isMap", + "useMap" +]); + +domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element, +[ + "name", + "target", + "accessKey", + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + "hreflang", + "coords", + "shape", + "text", + "type", + "rel", + "rev", + "charset" +]); + +domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element, +[ + "contentDocument", + "contentWindow", + "frameBorder", + "height", + "longDesc", + "marginHeight", + "marginWidth", + "name", + "scrolling", + "src", + "width" +]); + +domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "border", + "caption", + "cellPadding", + "cellSpacing", + "frame", + "rows", + "rules", + "summary", + "tBodies", + "tFoot", + "tHead", + "width", + + "createCaption", + "createTFoot", + "createTHead", + "deleteCaption", + "deleteRow", + "deleteTFoot", + "deleteTHead", + "insertRow" +]); + +domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "cells", + "ch", + "chOff", + "rowIndex", + "sectionRowIndex", + "vAlign", + + "deleteCell", + "insertCell" +]); + +domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element, +[ + "abbr", + "axis", + "bgColor", + "cellIndex", + "ch", + "chOff", + "colSpan", + "headers", + "height", + "noWrap", + "rowSpan", + "scope", + "vAlign", + "width" + +]); + +domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element, +[ + "src" +]); + +domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element, +[ + "accessKey", + "disabled", + "form", + "name", + "type", + "value", + + "click" +]); + +domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element, +[ + "type", + "value", + "checked", + "accept", + "accessKey", + "alt", + "controllers", + "defaultChecked", + "defaultValue", + "disabled", + "form", + "maxLength", + "name", + "readOnly", + "selectionEnd", + "selectionStart", + "size", + "src", + "textLength", + "useMap", + + "click", + "select", + "setSelectionRange" +]); + +domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element, +[ + "acceptCharset", + "action", + "author", + "elements", + "encoding", + "enctype", + "entry_id", + "length", + "method", + "name", + "post", + "target", + "text", + "url", + + "reset", + "submit" +]); + +domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element, +[ + "aLink", + "background", + "bgColor", + "link", + "text", + "vLink" +]); + +domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element, +[ + "version" +]); + +domMemberMap.Text = extendArray(domMemberMap.Node, +[ + "data", + "length", + + "appendData", + "deleteData", + "insertData", + "replaceData", + "splitText", + "substringData" +]); + +domMemberMap.Attr = extendArray(domMemberMap.Node, +[ + "name", + "value", + "specified", + "ownerElement" +]); + +domMemberMap.Event = +[ + "type", + "target", + "currentTarget", + "originalTarget", + "explicitOriginalTarget", + "relatedTarget", + "rangeParent", + "rangeOffset", + "view", + + "keyCode", + "charCode", + "screenX", + "screenY", + "clientX", + "clientY", + "layerX", + "layerY", + "pageX", + "pageY", + + "detail", + "button", + "which", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + + "eventPhase", + "timeStamp", + "bubbles", + "cancelable", + "cancelBubble", + + "isTrusted", + "isChar", + + "getPreventDefault", + "initEvent", + "initMouseEvent", + "initKeyEvent", + "initUIEvent", + "preventBubble", + "preventCapture", + "preventDefault", + "stopPropagation" +]; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.domConstantMap = +{ + "ELEMENT_NODE": 1, + "ATTRIBUTE_NODE": 1, + "TEXT_NODE": 1, + "CDATA_SECTION_NODE": 1, + "ENTITY_REFERENCE_NODE": 1, + "ENTITY_NODE": 1, + "PROCESSING_INSTRUCTION_NODE": 1, + "COMMENT_NODE": 1, + "DOCUMENT_NODE": 1, + "DOCUMENT_TYPE_NODE": 1, + "DOCUMENT_FRAGMENT_NODE": 1, + "NOTATION_NODE": 1, + + "DOCUMENT_POSITION_DISCONNECTED": 1, + "DOCUMENT_POSITION_PRECEDING": 1, + "DOCUMENT_POSITION_FOLLOWING": 1, + "DOCUMENT_POSITION_CONTAINS": 1, + "DOCUMENT_POSITION_CONTAINED_BY": 1, + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1, + + "UNKNOWN_RULE": 1, + "STYLE_RULE": 1, + "CHARSET_RULE": 1, + "IMPORT_RULE": 1, + "MEDIA_RULE": 1, + "FONT_FACE_RULE": 1, + "PAGE_RULE": 1, + + "CAPTURING_PHASE": 1, + "AT_TARGET": 1, + "BUBBLING_PHASE": 1, + + "SCROLL_PAGE_UP": 1, + "SCROLL_PAGE_DOWN": 1, + + "MOUSEUP": 1, + "MOUSEDOWN": 1, + "MOUSEOVER": 1, + "MOUSEOUT": 1, + "MOUSEMOVE": 1, + "MOUSEDRAG": 1, + "CLICK": 1, + "DBLCLICK": 1, + "KEYDOWN": 1, + "KEYUP": 1, + "KEYPRESS": 1, + "DRAGDROP": 1, + "FOCUS": 1, + "BLUR": 1, + "SELECT": 1, + "CHANGE": 1, + "RESET": 1, + "SUBMIT": 1, + "SCROLL": 1, + "LOAD": 1, + "UNLOAD": 1, + "XFER_DONE": 1, + "ABORT": 1, + "ERROR": 1, + "LOCATE": 1, + "MOVE": 1, + "RESIZE": 1, + "FORWARD": 1, + "HELP": 1, + "BACK": 1, + "TEXT": 1, + + "ALT_MASK": 1, + "CONTROL_MASK": 1, + "SHIFT_MASK": 1, + "META_MASK": 1, + + "DOM_VK_TAB": 1, + "DOM_VK_PAGE_UP": 1, + "DOM_VK_PAGE_DOWN": 1, + "DOM_VK_UP": 1, + "DOM_VK_DOWN": 1, + "DOM_VK_LEFT": 1, + "DOM_VK_RIGHT": 1, + "DOM_VK_CANCEL": 1, + "DOM_VK_HELP": 1, + "DOM_VK_BACK_SPACE": 1, + "DOM_VK_CLEAR": 1, + "DOM_VK_RETURN": 1, + "DOM_VK_ENTER": 1, + "DOM_VK_SHIFT": 1, + "DOM_VK_CONTROL": 1, + "DOM_VK_ALT": 1, + "DOM_VK_PAUSE": 1, + "DOM_VK_CAPS_LOCK": 1, + "DOM_VK_ESCAPE": 1, + "DOM_VK_SPACE": 1, + "DOM_VK_END": 1, + "DOM_VK_HOME": 1, + "DOM_VK_PRINTSCREEN": 1, + "DOM_VK_INSERT": 1, + "DOM_VK_DELETE": 1, + "DOM_VK_0": 1, + "DOM_VK_1": 1, + "DOM_VK_2": 1, + "DOM_VK_3": 1, + "DOM_VK_4": 1, + "DOM_VK_5": 1, + "DOM_VK_6": 1, + "DOM_VK_7": 1, + "DOM_VK_8": 1, + "DOM_VK_9": 1, + "DOM_VK_SEMICOLON": 1, + "DOM_VK_EQUALS": 1, + "DOM_VK_A": 1, + "DOM_VK_B": 1, + "DOM_VK_C": 1, + "DOM_VK_D": 1, + "DOM_VK_E": 1, + "DOM_VK_F": 1, + "DOM_VK_G": 1, + "DOM_VK_H": 1, + "DOM_VK_I": 1, + "DOM_VK_J": 1, + "DOM_VK_K": 1, + "DOM_VK_L": 1, + "DOM_VK_M": 1, + "DOM_VK_N": 1, + "DOM_VK_O": 1, + "DOM_VK_P": 1, + "DOM_VK_Q": 1, + "DOM_VK_R": 1, + "DOM_VK_S": 1, + "DOM_VK_T": 1, + "DOM_VK_U": 1, + "DOM_VK_V": 1, + "DOM_VK_W": 1, + "DOM_VK_X": 1, + "DOM_VK_Y": 1, + "DOM_VK_Z": 1, + "DOM_VK_CONTEXT_MENU": 1, + "DOM_VK_NUMPAD0": 1, + "DOM_VK_NUMPAD1": 1, + "DOM_VK_NUMPAD2": 1, + "DOM_VK_NUMPAD3": 1, + "DOM_VK_NUMPAD4": 1, + "DOM_VK_NUMPAD5": 1, + "DOM_VK_NUMPAD6": 1, + "DOM_VK_NUMPAD7": 1, + "DOM_VK_NUMPAD8": 1, + "DOM_VK_NUMPAD9": 1, + "DOM_VK_MULTIPLY": 1, + "DOM_VK_ADD": 1, + "DOM_VK_SEPARATOR": 1, + "DOM_VK_SUBTRACT": 1, + "DOM_VK_DECIMAL": 1, + "DOM_VK_DIVIDE": 1, + "DOM_VK_F1": 1, + "DOM_VK_F2": 1, + "DOM_VK_F3": 1, + "DOM_VK_F4": 1, + "DOM_VK_F5": 1, + "DOM_VK_F6": 1, + "DOM_VK_F7": 1, + "DOM_VK_F8": 1, + "DOM_VK_F9": 1, + "DOM_VK_F10": 1, + "DOM_VK_F11": 1, + "DOM_VK_F12": 1, + "DOM_VK_F13": 1, + "DOM_VK_F14": 1, + "DOM_VK_F15": 1, + "DOM_VK_F16": 1, + "DOM_VK_F17": 1, + "DOM_VK_F18": 1, + "DOM_VK_F19": 1, + "DOM_VK_F20": 1, + "DOM_VK_F21": 1, + "DOM_VK_F22": 1, + "DOM_VK_F23": 1, + "DOM_VK_F24": 1, + "DOM_VK_NUM_LOCK": 1, + "DOM_VK_SCROLL_LOCK": 1, + "DOM_VK_COMMA": 1, + "DOM_VK_PERIOD": 1, + "DOM_VK_SLASH": 1, + "DOM_VK_BACK_QUOTE": 1, + "DOM_VK_OPEN_BRACKET": 1, + "DOM_VK_BACK_SLASH": 1, + "DOM_VK_CLOSE_BRACKET": 1, + "DOM_VK_QUOTE": 1, + "DOM_VK_META": 1, + + "SVG_ZOOMANDPAN_DISABLE": 1, + "SVG_ZOOMANDPAN_MAGNIFY": 1, + "SVG_ZOOMANDPAN_UNKNOWN": 1 +}; + +this.cssInfo = +{ + "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"], + "background-attachment": ["bgAttachment"], + "background-color": ["color", "systemColor"], + "background-image": ["none"], + "background-position": ["bgPosition"], + "background-repeat": ["bgRepeat"], + + "border": ["borderStyle", "thickness", "color", "systemColor", "none"], + "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-collapse": ["borderCollapse"], + "border-color": ["color", "systemColor"], + "border-top-color": ["color", "systemColor"], + "border-right-color": ["color", "systemColor"], + "border-bottom-color": ["color", "systemColor"], + "border-left-color": ["color", "systemColor"], + "border-spacing": [], + "border-style": ["borderStyle"], + "border-top-style": ["borderStyle"], + "border-right-style": ["borderStyle"], + "border-bottom-style": ["borderStyle"], + "border-left-style": ["borderStyle"], + "border-width": ["thickness"], + "border-top-width": ["thickness"], + "border-right-width": ["thickness"], + "border-bottom-width": ["thickness"], + "border-left-width": ["thickness"], + + "bottom": ["auto"], + "caption-side": ["captionSide"], + "clear": ["clear", "none"], + "clip": ["auto"], + "color": ["color", "systemColor"], + "content": ["content"], + "counter-increment": ["none"], + "counter-reset": ["none"], + "cursor": ["cursor", "none"], + "direction": ["direction"], + "display": ["display", "none"], + "empty-cells": [], + "float": ["float", "none"], + "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"], + + "font-family": ["fontFamily"], + "font-size": ["fontSize"], + "font-size-adjust": [], + "font-stretch": [], + "font-style": ["fontStyle"], + "font-variant": ["fontVariant"], + "font-weight": ["fontWeight"], + + "height": ["auto"], + "left": ["auto"], + "letter-spacing": [], + "line-height": [], + + "list-style": ["listStyleType", "listStylePosition", "none"], + "list-style-image": ["none"], + "list-style-position": ["listStylePosition"], + "list-style-type": ["listStyleType", "none"], + + "margin": [], + "margin-top": [], + "margin-right": [], + "margin-bottom": [], + "margin-left": [], + + "marker-offset": ["auto"], + "min-height": ["none"], + "max-height": ["none"], + "min-width": ["none"], + "max-width": ["none"], + + "outline": ["borderStyle", "color", "systemColor", "none"], + "outline-color": ["color", "systemColor"], + "outline-style": ["borderStyle"], + "outline-width": [], + + "overflow": ["overflow", "auto"], + "overflow-x": ["overflow", "auto"], + "overflow-y": ["overflow", "auto"], + + "padding": [], + "padding-top": [], + "padding-right": [], + "padding-bottom": [], + "padding-left": [], + + "position": ["position"], + "quotes": ["none"], + "right": ["auto"], + "table-layout": ["tableLayout", "auto"], + "text-align": ["textAlign"], + "text-decoration": ["textDecoration", "none"], + "text-indent": [], + "text-shadow": [], + "text-transform": ["textTransform", "none"], + "top": ["auto"], + "unicode-bidi": [], + "vertical-align": ["verticalAlign"], + "white-space": ["whiteSpace"], + "width": ["auto"], + "word-spacing": [], + "z-index": [], + + "-moz-appearance": ["mozAppearance"], + "-moz-border-radius": [], + "-moz-border-radius-bottomleft": [], + "-moz-border-radius-bottomright": [], + "-moz-border-radius-topleft": [], + "-moz-border-radius-topright": [], + "-moz-border-top-colors": ["color", "systemColor"], + "-moz-border-right-colors": ["color", "systemColor"], + "-moz-border-bottom-colors": ["color", "systemColor"], + "-moz-border-left-colors": ["color", "systemColor"], + "-moz-box-align": ["mozBoxAlign"], + "-moz-box-direction": ["mozBoxDirection"], + "-moz-box-flex": [], + "-moz-box-ordinal-group": [], + "-moz-box-orient": ["mozBoxOrient"], + "-moz-box-pack": ["mozBoxPack"], + "-moz-box-sizing": ["mozBoxSizing"], + "-moz-opacity": [], + "-moz-user-focus": ["userFocus", "none"], + "-moz-user-input": ["userInput"], + "-moz-user-modify": [], + "-moz-user-select": ["userSelect", "none"], + "-moz-background-clip": [], + "-moz-background-inline-policy": [], + "-moz-background-origin": [], + "-moz-binding": [], + "-moz-column-count": [], + "-moz-column-gap": [], + "-moz-column-width": [], + "-moz-image-region": [] +}; + +this.inheritedStyleNames = +{ + "border-collapse": 1, + "border-spacing": 1, + "border-style": 1, + "caption-side": 1, + "color": 1, + "cursor": 1, + "direction": 1, + "empty-cells": 1, + "font": 1, + "font-family": 1, + "font-size-adjust": 1, + "font-size": 1, + "font-style": 1, + "font-variant": 1, + "font-weight": 1, + "letter-spacing": 1, + "line-height": 1, + "list-style": 1, + "list-style-image": 1, + "list-style-position": 1, + "list-style-type": 1, + "quotes": 1, + "text-align": 1, + "text-decoration": 1, + "text-indent": 1, + "text-shadow": 1, + "text-transform": 1, + "white-space": 1, + "word-spacing": 1 +}; + +this.cssKeywords = +{ + "appearance": + [ + "button", + "button-small", + "checkbox", + "checkbox-container", + "checkbox-small", + "dialog", + "listbox", + "menuitem", + "menulist", + "menulist-button", + "menulist-textfield", + "menupopup", + "progressbar", + "radio", + "radio-container", + "radio-small", + "resizer", + "scrollbar", + "scrollbarbutton-down", + "scrollbarbutton-left", + "scrollbarbutton-right", + "scrollbarbutton-up", + "scrollbartrack-horizontal", + "scrollbartrack-vertical", + "separator", + "statusbar", + "tab", + "tab-left-edge", + "tabpanels", + "textfield", + "toolbar", + "toolbarbutton", + "toolbox", + "tooltip", + "treeheadercell", + "treeheadersortarrow", + "treeitem", + "treetwisty", + "treetwistyopen", + "treeview", + "window" + ], + + "systemColor": + [ + "ActiveBorder", + "ActiveCaption", + "AppWorkspace", + "Background", + "ButtonFace", + "ButtonHighlight", + "ButtonShadow", + "ButtonText", + "CaptionText", + "GrayText", + "Highlight", + "HighlightText", + "InactiveBorder", + "InactiveCaption", + "InactiveCaptionText", + "InfoBackground", + "InfoText", + "Menu", + "MenuText", + "Scrollbar", + "ThreeDDarkShadow", + "ThreeDFace", + "ThreeDHighlight", + "ThreeDLightShadow", + "ThreeDShadow", + "Window", + "WindowFrame", + "WindowText", + "-moz-field", + "-moz-fieldtext", + "-moz-workspace", + "-moz-visitedhyperlinktext", + "-moz-use-text-color" + ], + + "color": + [ + "AliceBlue", + "AntiqueWhite", + "Aqua", + "Aquamarine", + "Azure", + "Beige", + "Bisque", + "Black", + "BlanchedAlmond", + "Blue", + "BlueViolet", + "Brown", + "BurlyWood", + "CadetBlue", + "Chartreuse", + "Chocolate", + "Coral", + "CornflowerBlue", + "Cornsilk", + "Crimson", + "Cyan", + "DarkBlue", + "DarkCyan", + "DarkGoldenRod", + "DarkGray", + "DarkGreen", + "DarkKhaki", + "DarkMagenta", + "DarkOliveGreen", + "DarkOrange", + "DarkOrchid", + "DarkRed", + "DarkSalmon", + "DarkSeaGreen", + "DarkSlateBlue", + "DarkSlateGray", + "DarkTurquoise", + "DarkViolet", + "DeepPink", + "DarkSkyBlue", + "DimGray", + "DodgerBlue", + "Feldspar", + "FireBrick", + "FloralWhite", + "ForestGreen", + "Fuchsia", + "Gainsboro", + "GhostWhite", + "Gold", + "GoldenRod", + "Gray", + "Green", + "GreenYellow", + "HoneyDew", + "HotPink", + "IndianRed", + "Indigo", + "Ivory", + "Khaki", + "Lavender", + "LavenderBlush", + "LawnGreen", + "LemonChiffon", + "LightBlue", + "LightCoral", + "LightCyan", + "LightGoldenRodYellow", + "LightGrey", + "LightGreen", + "LightPink", + "LightSalmon", + "LightSeaGreen", + "LightSkyBlue", + "LightSlateBlue", + "LightSlateGray", + "LightSteelBlue", + "LightYellow", + "Lime", + "LimeGreen", + "Linen", + "Magenta", + "Maroon", + "MediumAquaMarine", + "MediumBlue", + "MediumOrchid", + "MediumPurple", + "MediumSeaGreen", + "MediumSlateBlue", + "MediumSpringGreen", + "MediumTurquoise", + "MediumVioletRed", + "MidnightBlue", + "MintCream", + "MistyRose", + "Moccasin", + "NavajoWhite", + "Navy", + "OldLace", + "Olive", + "OliveDrab", + "Orange", + "OrangeRed", + "Orchid", + "PaleGoldenRod", + "PaleGreen", + "PaleTurquoise", + "PaleVioletRed", + "PapayaWhip", + "PeachPuff", + "Peru", + "Pink", + "Plum", + "PowderBlue", + "Purple", + "Red", + "RosyBrown", + "RoyalBlue", + "SaddleBrown", + "Salmon", + "SandyBrown", + "SeaGreen", + "SeaShell", + "Sienna", + "Silver", + "SkyBlue", + "SlateBlue", + "SlateGray", + "Snow", + "SpringGreen", + "SteelBlue", + "Tan", + "Teal", + "Thistle", + "Tomato", + "Turquoise", + "Violet", + "VioletRed", + "Wheat", + "White", + "WhiteSmoke", + "Yellow", + "YellowGreen", + "transparent", + "invert" + ], + + "auto": + [ + "auto" + ], + + "none": + [ + "none" + ], + + "captionSide": + [ + "top", + "bottom", + "left", + "right" + ], + + "clear": + [ + "left", + "right", + "both" + ], + + "cursor": + [ + "auto", + "cell", + "context-menu", + "crosshair", + "default", + "help", + "pointer", + "progress", + "move", + "e-resize", + "all-scroll", + "ne-resize", + "nw-resize", + "n-resize", + "se-resize", + "sw-resize", + "s-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "text", + "vertical-text", + "wait", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "-moz-alias", + "-moz-cell", + "-moz-copy", + "-moz-grab", + "-moz-grabbing", + "-moz-contextmenu", + "-moz-zoom-in", + "-moz-zoom-out", + "-moz-spinning" + ], + + "direction": + [ + "ltr", + "rtl" + ], + + "bgAttachment": + [ + "scroll", + "fixed" + ], + + "bgPosition": + [ + "top", + "center", + "bottom", + "left", + "right" + ], + + "bgRepeat": + [ + "repeat", + "repeat-x", + "repeat-y", + "no-repeat" + ], + + "borderStyle": + [ + "hidden", + "dotted", + "dashed", + "solid", + "double", + "groove", + "ridge", + "inset", + "outset", + "-moz-bg-inset", + "-moz-bg-outset", + "-moz-bg-solid" + ], + + "borderCollapse": + [ + "collapse", + "separate" + ], + + "overflow": + [ + "visible", + "hidden", + "scroll", + "-moz-scrollbars-horizontal", + "-moz-scrollbars-none", + "-moz-scrollbars-vertical" + ], + + "listStyleType": + [ + "disc", + "circle", + "square", + "decimal", + "decimal-leading-zero", + "lower-roman", + "upper-roman", + "lower-greek", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "hebrew", + "armenian", + "georgian", + "cjk-ideographic", + "hiragana", + "katakana", + "hiragana-iroha", + "katakana-iroha", + "inherit" + ], + + "listStylePosition": + [ + "inside", + "outside" + ], + + "content": + [ + "open-quote", + "close-quote", + "no-open-quote", + "no-close-quote", + "inherit" + ], + + "fontStyle": + [ + "normal", + "italic", + "oblique", + "inherit" + ], + + "fontVariant": + [ + "normal", + "small-caps", + "inherit" + ], + + "fontWeight": + [ + "normal", + "bold", + "bolder", + "lighter", + "inherit" + ], + + "fontSize": + [ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger" + ], + + "fontFamily": + [ + "Arial", + "Comic Sans MS", + "Georgia", + "Tahoma", + "Verdana", + "Times New Roman", + "Trebuchet MS", + "Lucida Grande", + "Helvetica", + "serif", + "sans-serif", + "cursive", + "fantasy", + "monospace", + "caption", + "icon", + "menu", + "message-box", + "small-caption", + "status-bar", + "inherit" + ], + + "display": + [ + "block", + "inline", + "inline-block", + "list-item", + "marker", + "run-in", + "compact", + "table", + "inline-table", + "table-row-group", + "table-column", + "table-column-group", + "table-header-group", + "table-footer-group", + "table-row", + "table-cell", + "table-caption", + "-moz-box", + "-moz-compact", + "-moz-deck", + "-moz-grid", + "-moz-grid-group", + "-moz-grid-line", + "-moz-groupbox", + "-moz-inline-block", + "-moz-inline-box", + "-moz-inline-grid", + "-moz-inline-stack", + "-moz-inline-table", + "-moz-marker", + "-moz-popup", + "-moz-runin", + "-moz-stack" + ], + + "position": + [ + "static", + "relative", + "absolute", + "fixed", + "inherit" + ], + + "float": + [ + "left", + "right" + ], + + "textAlign": + [ + "left", + "right", + "center", + "justify" + ], + + "tableLayout": + [ + "fixed" + ], + + "textDecoration": + [ + "underline", + "overline", + "line-through", + "blink" + ], + + "textTransform": + [ + "capitalize", + "lowercase", + "uppercase", + "inherit" + ], + + "unicodeBidi": + [ + "normal", + "embed", + "bidi-override" + ], + + "whiteSpace": + [ + "normal", + "pre", + "nowrap" + ], + + "verticalAlign": + [ + "baseline", + "sub", + "super", + "top", + "text-top", + "middle", + "bottom", + "text-bottom", + "inherit" + ], + + "thickness": + [ + "thin", + "medium", + "thick" + ], + + "userFocus": + [ + "ignore", + "normal" + ], + + "userInput": + [ + "disabled", + "enabled" + ], + + "userSelect": + [ + "normal" + ], + + "mozBoxSizing": + [ + "content-box", + "padding-box", + "border-box" + ], + + "mozBoxAlign": + [ + "start", + "center", + "end", + "baseline", + "stretch" + ], + + "mozBoxDirection": + [ + "normal", + "reverse" + ], + + "mozBoxOrient": + [ + "horizontal", + "vertical" + ], + + "mozBoxPack": + [ + "start", + "center", + "end" + ] +}; + +this.nonEditableTags = +{ + "HTML": 1, + "HEAD": 1, + "html": 1, + "head": 1 +}; + +this.innerEditableTags = +{ + "BODY": 1, + "body": 1 +}; + +this.selfClosingTags = +{ // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML + "meta": 1, + "link": 1, + "area": 1, + "base": 1, + "col": 1, + "input": 1, + "img": 1, + "br": 1, + "hr": 1, + "param":1, + "embed":1 +}; + +var invisibleTags = this.invisibleTags = +{ + "HTML": 1, + "HEAD": 1, + "TITLE": 1, + "META": 1, + "LINK": 1, + "STYLE": 1, + "SCRIPT": 1, + "NOSCRIPT": 1, + "BR": 1, + "PARAM": 1, + "COL": 1, + + "html": 1, + "head": 1, + "title": 1, + "meta": 1, + "link": 1, + "style": 1, + "script": 1, + "noscript": 1, + "br": 1, + "param": 1, + "col": 1 + /* + "window": 1, + "browser": 1, + "frame": 1, + "tabbrowser": 1, + "WINDOW": 1, + "BROWSER": 1, + "FRAME": 1, + "TABBROWSER": 1, + */ +}; + + +if (typeof KeyEvent == "undefined") { + this.KeyEvent = { + DOM_VK_CANCEL: 3, + DOM_VK_HELP: 6, + DOM_VK_BACK_SPACE: 8, + DOM_VK_TAB: 9, + DOM_VK_CLEAR: 12, + DOM_VK_RETURN: 13, + DOM_VK_ENTER: 14, + DOM_VK_SHIFT: 16, + DOM_VK_CONTROL: 17, + DOM_VK_ALT: 18, + DOM_VK_PAUSE: 19, + DOM_VK_CAPS_LOCK: 20, + DOM_VK_ESCAPE: 27, + DOM_VK_SPACE: 32, + DOM_VK_PAGE_UP: 33, + DOM_VK_PAGE_DOWN: 34, + DOM_VK_END: 35, + DOM_VK_HOME: 36, + DOM_VK_LEFT: 37, + DOM_VK_UP: 38, + DOM_VK_RIGHT: 39, + DOM_VK_DOWN: 40, + DOM_VK_PRINTSCREEN: 44, + DOM_VK_INSERT: 45, + DOM_VK_DELETE: 46, + DOM_VK_0: 48, + DOM_VK_1: 49, + DOM_VK_2: 50, + DOM_VK_3: 51, + DOM_VK_4: 52, + DOM_VK_5: 53, + DOM_VK_6: 54, + DOM_VK_7: 55, + DOM_VK_8: 56, + DOM_VK_9: 57, + DOM_VK_SEMICOLON: 59, + DOM_VK_EQUALS: 61, + DOM_VK_A: 65, + DOM_VK_B: 66, + DOM_VK_C: 67, + DOM_VK_D: 68, + DOM_VK_E: 69, + DOM_VK_F: 70, + DOM_VK_G: 71, + DOM_VK_H: 72, + DOM_VK_I: 73, + DOM_VK_J: 74, + DOM_VK_K: 75, + DOM_VK_L: 76, + DOM_VK_M: 77, + DOM_VK_N: 78, + DOM_VK_O: 79, + DOM_VK_P: 80, + DOM_VK_Q: 81, + DOM_VK_R: 82, + DOM_VK_S: 83, + DOM_VK_T: 84, + DOM_VK_U: 85, + DOM_VK_V: 86, + DOM_VK_W: 87, + DOM_VK_X: 88, + DOM_VK_Y: 89, + DOM_VK_Z: 90, + DOM_VK_CONTEXT_MENU: 93, + DOM_VK_NUMPAD0: 96, + DOM_VK_NUMPAD1: 97, + DOM_VK_NUMPAD2: 98, + DOM_VK_NUMPAD3: 99, + DOM_VK_NUMPAD4: 100, + DOM_VK_NUMPAD5: 101, + DOM_VK_NUMPAD6: 102, + DOM_VK_NUMPAD7: 103, + DOM_VK_NUMPAD8: 104, + DOM_VK_NUMPAD9: 105, + DOM_VK_MULTIPLY: 106, + DOM_VK_ADD: 107, + DOM_VK_SEPARATOR: 108, + DOM_VK_SUBTRACT: 109, + DOM_VK_DECIMAL: 110, + DOM_VK_DIVIDE: 111, + DOM_VK_F1: 112, + DOM_VK_F2: 113, + DOM_VK_F3: 114, + DOM_VK_F4: 115, + DOM_VK_F5: 116, + DOM_VK_F6: 117, + DOM_VK_F7: 118, + DOM_VK_F8: 119, + DOM_VK_F9: 120, + DOM_VK_F10: 121, + DOM_VK_F11: 122, + DOM_VK_F12: 123, + DOM_VK_F13: 124, + DOM_VK_F14: 125, + DOM_VK_F15: 126, + DOM_VK_F16: 127, + DOM_VK_F17: 128, + DOM_VK_F18: 129, + DOM_VK_F19: 130, + DOM_VK_F20: 131, + DOM_VK_F21: 132, + DOM_VK_F22: 133, + DOM_VK_F23: 134, + DOM_VK_F24: 135, + DOM_VK_NUM_LOCK: 144, + DOM_VK_SCROLL_LOCK: 145, + DOM_VK_COMMA: 188, + DOM_VK_PERIOD: 190, + DOM_VK_SLASH: 191, + DOM_VK_BACK_QUOTE: 192, + DOM_VK_OPEN_BRACKET: 219, + DOM_VK_BACK_SLASH: 220, + DOM_VK_CLOSE_BRACKET: 221, + DOM_VK_QUOTE: 222, + DOM_VK_META: 224 + }; +} + + +// ************************************************************************************************ +// Ajax + +/** + * @namespace + */ +this.Ajax = +{ + + requests: [], + transport: null, + states: ["Uninitialized","Loading","Loaded","Interactive","Complete"], + + initialize: function() + { + this.transport = this.getXHRObject(); + }, + + getXHRObject: function() + { + var xhrObj = false; + try + { + xhrObj = new XMLHttpRequest(); + } + catch(e) + { + var progid = [ + "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" + ]; + + for ( var i=0; i < progid.length; ++i ) { + try + { + xhrObj = new ActiveXObject(progid[i]); + } + catch(e) + { + continue; + } + break; + } + } + finally + { + return xhrObj; + } + }, + + + /** + * Create a AJAX request. + * + * @name request + * @param {Object} options request options + * @param {String} options.url URL to be requested + * @param {String} options.type Request type ("get" ou "post"). Default is "get". + * @param {Boolean} options.async Asynchronous flag. Default is "true". + * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text". + * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded". + * @param {Function} options.onLoading onLoading callback + * @param {Function} options.onLoaded onLoaded callback + * @param {Function} options.onInteractive onInteractive callback + * @param {Function} options.onComplete onComplete callback + * @param {Function} options.onUpdate onUpdate callback + * @param {Function} options.onSuccess onSuccess callback + * @param {Function} options.onFailure onFailure callback + */ + request: function(options) + { + // process options + var o = FBL.extend( + { + // default values + type: "get", + async: true, + dataType: "text", + contentType: "application/x-www-form-urlencoded" + }, + options || {} + ); + + this.requests.push(o); + + var s = this.getState(); + if (s == "Uninitialized" || s == "Complete" || s == "Loaded") + this.sendRequest(); + }, + + serialize: function(data) + { + var r = [""], rl = 0; + if (data) { + if (typeof data == "string") r[rl++] = data; + + else if (data.innerHTML && data.elements) { + for (var i=0,el,l=(el=data.elements).length; i < l; i++) + if (el[i].name) { + r[rl++] = encodeURIComponent(el[i].name); + r[rl++] = "="; + r[rl++] = encodeURIComponent(el[i].value); + r[rl++] = "&"; + } + + } else + for(var param in data) { + r[rl++] = encodeURIComponent(param); + r[rl++] = "="; + r[rl++] = encodeURIComponent(data[param]); + r[rl++] = "&"; + } + } + return r.join("").replace(/&$/, ""); + }, + + sendRequest: function() + { + var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; + + // open XHR object + t.open(r.type, r.url, r.async); + + //setRequestHeaders(); + + // indicates that it is a XHR request to the server + t.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // if data is being sent, sets the appropriate content-type + if (data = FBL.Ajax.serialize(r.data)) + t.setRequestHeader("Content-Type", r.contentType); + + /** @ignore */ + // onreadystatechange handler + t.onreadystatechange = function() + { + FBL.Ajax.onStateChange(r); + }; + + // send the request + t.send(data); + }, + + /** + * Handles the state change + */ + onStateChange: function(options) + { + var fn, o = options, t = this.transport; + var state = this.getState(t); + + if (fn = o["on" + state]) fn(this.getResponse(o), o); + + if (state == "Complete") + { + var success = t.status == 200, response = this.getResponse(o); + + if (fn = o["onUpdate"]) + fn(response, o); + + if (fn = o["on" + (success ? "Success" : "Failure")]) + fn(response, o); + + t.onreadystatechange = FBL.emptyFn; + + if (this.requests.length > 0) + setTimeout(this.sendRequest, 10); + } + }, + + /** + * gets the appropriate response value according the type + */ + getResponse: function(options) + { + var t = this.transport, type = options.dataType; + + if (t.status != 200) return t.statusText; + else if (type == "text") return t.responseText; + else if (type == "html") return t.responseText; + else if (type == "xml") return t.responseXML; + else if (type == "json") return eval("(" + t.responseText + ")"); + }, + + /** + * returns the current state of the XHR object + */ + getState: function() + { + return this.states[this.transport.readyState]; + } + +}; + + +// ************************************************************************************************ +// Cookie, from http://www.quirksmode.org/js/cookies.html + +this.createCookie = function(name,value,days) +{ + if ('cookie' in document) + { + if (days) + { + var date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + var expires = "; expires="+date.toGMTString(); + } + else + var expires = ""; + + document.cookie = name+"="+value+expires+"; path=/"; + } +}; + +this.readCookie = function (name) +{ + if ('cookie' in document) + { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + + for(var i=0; i < ca.length; i++) + { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + } + + return null; +}; + +this.removeCookie = function(name) +{ + this.createCookie(name, "", -1); +}; + + +// ************************************************************************************************ +// http://www.mister-pixel.com/#Content__state=is_that_simple +var fixIE6BackgroundImageCache = function(doc) +{ + doc = doc || document; + try + { + doc.execCommand("BackgroundImageCache", false, true); + } + catch(E) + { + + } +}; + +// ************************************************************************************************ +// calculatePixelsPerInch + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; + +var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body) +{ + var inch = FBL.createGlobalElement("div"); + inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;"; + body.appendChild(inch); + + FBL.pixelsPerInch = { + x: inch.offsetWidth, + y: inch.offsetHeight + }; + + body.removeChild(inch); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceLink = function(url, line, type, object, instance) +{ + this.href = url; + this.instance = instance; + this.line = line; + this.type = type; + this.object = object; +}; + +this.SourceLink.prototype = +{ + toString: function() + { + return this.href; + }, + toJSON: function() // until 3.1... + { + return "{\"href\":\""+this.href+"\", "+ + (this.line?("\"line\":"+this.line+","):"")+ + (this.type?(" \"type\":\""+this.type+"\","):"")+ + "}"; + } + +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceText = function(lines, owner) +{ + this.lines = lines; + this.owner = owner; +}; + +this.SourceText.getLineAsHTML = function(lineNo) +{ + return escapeForSourceLine(this.lines[lineNo-1]); +}; + + +// ************************************************************************************************ +}).apply(FBL); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-i18n */ function() { with (FBL) { +// ************************************************************************************************ + +// TODO: xxxpedro localization +var oSTR = +{ + "NoMembersWarning": "There are no properties to show for this object.", + + "EmptyStyleSheet": "There are no rules in this stylesheet.", + "EmptyElementCSS": "This element has no style rules.", + "AccessRestricted": "Access to restricted URI denied.", + + "net.label.Parameters": "Parameters", + "net.label.Source": "Source", + "URLParameters": "Params", + + "EditStyle": "Edit Element Style...", + "NewRule": "New Rule...", + + "NewProp": "New Property...", + "EditProp": 'Edit "%s"', + "DeleteProp": 'Delete "%s"', + "DisableProp": 'Disable "%s"' +}; + +// ************************************************************************************************ + +FBL.$STR = function(name) +{ + return oSTR.hasOwnProperty(name) ? oSTR[name] : name; +}; + +FBL.$STRF = function(name, args) +{ + if (!oSTR.hasOwnProperty(name)) return name; + + var format = oSTR[name]; + var objIndex = 0; + + var parts = parseFormat(format); + var trialIndex = objIndex; + var objects = args; + + for (var i= 0; i < parts.length; i++) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + + var result = []; + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + result.push(""+args.shift()); + } + else + result.push(part); + } + + return result.join(""); +}; + +// ************************************************************************************************ + +var parseFormat = function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-firebug */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; +var reps = []; + +var parentPanelMap = {}; + + +// ************************************************************************************************ +// Firebug + +/** + * @namespace describe Firebug + * @exports window.Firebug as Firebug + */ +window.Firebug = FBL.Firebug = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + version: "Firebug Lite 1.3.2", + revision: "$Revision: 9759 $", + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + modules: modules, + panelTypes: panelTypes, + panelTypeMap: panelTypeMap, + reps: reps, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Initialization + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); + + Firebug.browser = new Context(Env.browser); + Firebug.context = Firebug.browser; + + // Document must be cached before chrome initialization + cacheDocument(); + + if (Firebug.Inspector) + Firebug.Inspector.create(); + + if (FBL.processAllStyleSheets) + processAllStyleSheets(Firebug.browser.document); + + FirebugChrome.initialize(); + + dispatch(modules, "initialize", []); + + if (Env.onLoad) + { + var onLoad = Env.onLoad; + delete Env.onLoad; + + setTimeout(onLoad, 200); + } + }, + + shutdown: function() + { + if (Firebug.Inspector) + Firebug.Inspector.destroy(); + + dispatch(modules, "shutdown", []); + + var chromeMap = FirebugChrome.chromeMap; + + for (var name in chromeMap) + { + if (chromeMap.hasOwnProperty(name)) + { + chromeMap[name].destroy(); + } + } + + Firebug.Lite.Cache.Element.clear(); + Firebug.Lite.Cache.StyleSheet.clear(); + + Firebug.browser = null; + Firebug.context = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + modules.push.apply(modules, arguments); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + panelTypeMap[panelType.prototype.name] = arguments[i]; + + if (panelType.prototype.parentPanel) + parentPanelMap[panelType.prototype.parentPanel] = 1; + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + }, + + registerRep: function() + { + reps.push.apply(reps, arguments); + }, + + unregisterRep: function() + { + for (var i = 0; i < arguments.length; ++i) + remove(reps, arguments[i]); + }, + + setDefaultReps: function(funcRep, rep) + { + FBL.defaultRep = rep; + FBL.defaultFuncRep = funcRep; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Reps + + getRep: function(object) + { + var type = typeof object; + if (isIE && isFunction(object)) + type = "function"; + + for (var i = 0; i < reps.length; ++i) + { + var rep = reps[i]; + try + { + if (rep.supportsObject(object, type)) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("getRep type: "+type+" object: "+object, rep); + return rep; + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc); + FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className); + // TODO: xxxpedro add trace to FBTrace logs like in Firebug + //firebug.trace(); + } + } + } + + return (type == 'function') ? defaultFuncRep : defaultRep; + }, + + getRepObject: function(node) + { + var target = null; + for (var child = node; child; child = child.parentNode) + { + if (hasClass(child, "repTarget")) + target = child; + + if (child.repObject) + { + if (!target && hasClass(child, "repIgnore")) + break; + else + return child.repObject; + } + } + }, + + getRepNode: function(node) + { + for (var child = node; child; child = child.parentNode) + { + if (child.repObject) + return child; + } + }, + + getElementByRepObject: function(element, object) + { + for (var child = element.firstChild; child; child = child.nextSibling) + { + if (child.repObject == object) + return child; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Preferences + + getPref: function(name) + { + return Firebug[name]; + }, + + setPref: function(name, value) + { + Firebug[name] = value; + + this.savePrefs(); + }, + + setPrefs: function(prefs) + { + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + + this.savePrefs(); + }, + + restorePrefs: function() + { + var Options = Env.Options; + + for (var name in Options) + { + Firebug[name] = Options[name]; + } + }, + + loadPrefs: function(prefs) + { + this.restorePrefs(); + + prefs = prefs || eval("(" + readCookie("FirebugLite") + ")"); + + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + }, + + savePrefs: function() + { + var json = ['{'], jl = 0; + var Options = Env.Options; + + for (var name in Options) + { + if (Options.hasOwnProperty(name)) + { + var value = Firebug[name]; + + json[++jl] = '"'; + json[++jl] = name; + + var type = typeof value; + if (type == "boolean" || type == "number") + { + json[++jl] = '":'; + json[++jl] = value; + json[++jl] = ','; + } + else + { + json[++jl] = '":"'; + json[++jl] = value; + json[++jl] = '",'; + } + } + } + + json.length = jl--; + json[++jl] = '}'; + + createCookie("FirebugLite", json.join("")); + }, + + erasePrefs: function() + { + removeCookie("FirebugLite"); + } +}; + +Firebug.restorePrefs(); + +if (!Env.Options.enablePersistent || + Env.Options.enablePersistent && Env.isChromeContext || + Env.isDebugMode) + Env.browser.window.Firebug = FBL.Firebug; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Other methods + +FBL.cacheDocument = function cacheDocument() +{ + var ElementCache = Firebug.Lite.Cache.Element; + var els = Firebug.browser.document.getElementsByTagName("*"); + for (var i=0, l=els.length, el; iFirebug.registerModule method. There is always one instance of a module object + * per browser window. + * @extends Firebug.Listener + */ +Firebug.Module = extend(new Firebug.Listener(), +/** @extend Firebug.Module */ +{ + /** + * Called when the window is opened. + */ + initialize: function() + { + }, + + /** + * Called when the window is closed. + */ + shutdown: function() + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Called when a new context is created but before the page is loaded. + */ + initContext: function(context) + { + }, + + /** + * Called after a context is detached to a separate window; + */ + reattachContext: function(browser, context) + { + }, + + /** + * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. + */ + destroyContext: function(context, persistedState) + { + }, + + // Called when a FF tab is create or activated (user changes FF tab) + // Called after context is created or with context == null (to abort?) + showContext: function(browser, context) + { + }, + + /** + * Called after a context's page gets DOMContentLoaded + */ + loadedContext: function(context) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + showPanel: function(browser, panel) + { + }, + + showSidePanel: function(browser, panel) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateOption: function(name, value) + { + }, + + getObjectByURL: function(context, url) + { + } +}); + +// ************************************************************************************************ +// Panel + +/** + * @panel Base class for all panels. Every derived panel must define a constructor and + * register with "Firebug.registerPanel" method. An instance of the panel + * object is created by the framework for each browser tab where Firebug is activated. + */ +Firebug.Panel = +{ + name: "HelloWorld", + title: "Hello World!", + + parentPanel: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + options: { + hasCommandLine: false, + hasStatusBar: false, + hasToolButtons: false, + + // Pre-rendered panels are those included in the skin file (firebug.html) + isPreRendered: false, + innerHTMLSync: false + + /* + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // To be used by external extensions + panelHTML: "", + panelCSS: "", + + toolButtonsHTML: "" + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + tabNode: null, + panelNode: null, + sidePanelNode: null, + statusBarNode: null, + toolButtonsNode: null, + + panelBarNode: null, + + sidePanelBarBoxNode: null, + sidePanelBarNode: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + sidePanelBar: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + searchable: false, + editable: true, + order: 2147483647, + statusSeparator: "<", + + create: function(context, doc) + { + this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name); + + this.panelBarNode = $("fbPanelBar1"); + this.sidePanelBarBoxNode = $("fbPanelBar2"); + + if (this.hasSidePanel) + { + this.sidePanelBar = extend({}, PanelBar); + this.sidePanelBar.create(this); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + if (options.isPreRendered) + { + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + } + else + { + var containerSufix = this.parentPanel ? "2" : "1"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel + var panelNode = this.panelNode = createElement("div", { + id: panelId, + className: "fbPanel" + }); + + $("fbPanel" + containerSufix).appendChild(panelNode); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel Tab + var tabHTML = '' + + this.title + ''; + + var tabNode = this.tabNode = createElement("a", { + id: panelId + "Tab", + className: "fbTab fbHover", + innerHTML: tabHTML + }); + + if (isIE6) + { + tabNode.href = "javascript:void(0)"; + } + + var panelBarNode = this.parentPanel ? + Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode : + this.panelBarNode; + + panelBarNode.appendChild(tabNode); + tabNode.style.display = "block"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create ToolButtons + if (options.hasToolButtons) + { + this.toolButtonsNode = createElement("span", { + id: panelId + "Buttons", + className: "fbToolbarButtons" + }); + + $("fbToolbarButtons").appendChild(this.toolButtonsNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create StatusBar + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + + this.statusBarNode = createElement("span", { + id: panelId + "StatusBar", + className: "fbToolbarButtons fbStatusBar" + }); + + this.statusBarBox.appendChild(this.statusBarNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create SidePanel + } + + this.containerNode = this.panelNode.parentNode; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name); + + // xxxpedro contextMenu + this.onContextMenu = bind(this.onContextMenu, this); + + /* + this.context = context; + this.document = doc; + + this.panelNode = doc.createElement("div"); + this.panelNode.ownerPanel = this; + + setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); + doc.body.appendChild(this.panelNode); + + if (FBTrace.DBG_INITIALIZE) + FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); + + this.initializeNode(this.panelNode); + /**/ + }, + + destroy: function(state) // Panel may store info on state + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name); + + if (this.hasSidePanel) + { + this.sidePanelBar.destroy(); + this.sidePanelBar = null; + } + + this.options = null; + this.name = null; + this.parentPanel = null; + + this.tabNode = null; + this.panelNode = null; + this.containerNode = null; + + this.toolButtonsNode = null; + this.statusBarBox = null; + this.statusBarNode = null; + + //if (this.panelNode) + // delete this.panelNode.ownerPanel; + + //this.destroyNode(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + this.sidePanelBar.initialize(); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + this.containerNode = this.panelNode.parentNode; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // restore persistent state + this.containerNode.scrollTop = this.lastScrollTop; + + // xxxpedro contextMenu + addEvent(this.containerNode, "contextmenu", this.onContextMenu); + + + /// TODO: xxxpedro infoTip Hack + Firebug.chrome.currentPanel = + Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ? + Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel : + Firebug.chrome.selectedPanel; + + Firebug.showInfoTips = true; + Firebug.InfoTip.initializeBrowser(Firebug.chrome); + }, + + shutdown: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); + + /// TODO: xxxpedro infoTip Hack + Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); + + if (Firebug.chrome.largeCommandLineVisible) + Firebug.chrome.hideLargeCommandLine(); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + // TODO: xxxpedro firebug1.3a6 + // new PanelBar mechanism will need to call shutdown to hide the panels (so it + // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement + // a "remember selected panel" feature in the sidePanelBar + //this.sidePanelBar.shutdown(); + } + + // store persistent state + this.lastScrollTop = this.containerNode.scrollTop; + + // xxxpedro contextMenu + removeEvent(this.containerNode, "contextmenu", this.onContextMenu); + }, + + detach: function(oldChrome, newChrome) + { + if (oldChrome.selectedPanel.name == this.name) + this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop; + }, + + reattach: function(doc) + { + if (this.options.innerHTMLSync) + this.synchronizeUI(); + }, + + synchronizeUI: function() + { + this.containerNode.scrollTop = this.lastScrollTop || 0; + }, + + show: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "inline"; + this.statusBarNode.style.display = "inline"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "inline"; + } + + this.panelNode.style.display = "block"; + + this.visible = true; + + if (!this.parentPanel) + Firebug.chrome.layout(this); + }, + + hide: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "none"; + this.statusBarNode.style.display = "none"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "none"; + } + + this.panelNode.style.display = "none"; + + this.visible = false; + }, + + watchWindow: function(win) + { + }, + + unwatchWindow: function(win) + { + }, + + updateOption: function(name, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Toolbar helpers + */ + showToolbarButtons: function(buttonsId, show) + { + try + { + if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext. + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this); + + return; + } + var buttons = this.context.browser.chrome.$(buttonsId); + if (buttons) + collapse(buttons, show ? "false" : "true"); + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc); + if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser"); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Returns a number indicating the view's ability to inspect the object. + * + * Zero means not supported, and higher numbers indicate specificity. + */ + supportsObject: function(object) + { + return 0; + }, + + hasObject: function(object) // beyond type testing, is this object selectable? + { + return false; + }, + + select: function(object, forceUpdate) + { + if (!object) + object = this.getDefaultSelection(this.context); + + if(FBTrace.DBG_PANELS) + FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); + + if (forceUpdate || object != this.selection) + { + this.selection = object; + this.updateSelection(object); + + // TODO: xxxpedro + // XXXjoe This is kind of cheating, but, feh. + //Firebug.chrome.onPanelSelect(object, this); + //if (uiListeners.length > 0) + // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener + } + }, + + updateSelection: function(object) + { + }, + + markChange: function(skipSelf) + { + if (this.dependents) + { + if (skipSelf) + { + for (var i = 0; i < this.dependents.length; ++i) + { + var panelName = this.dependents[i]; + if (panelName != this.name) + this.context.invalidatePanels(panelName); + } + } + else + this.context.invalidatePanels.apply(this.context, this.dependents); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + startInspecting: function() + { + }, + + stopInspecting: function(object, cancelled) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + search: function(text, reverse) + { + }, + + /** + * Retrieves the search options that this modules supports. + * This is used by the search UI to present the proper options. + */ + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive") + ]; + }, + + /** + * Navigates to the next document whose match parameter returns true. + */ + navigateToNextDocument: function(match, reverse) + { + // This is an approximation of the UI that is displayed by the location + // selector. This should be close enough, although it may be better + // to simply generate the sorted list within the module, rather than + // sorting within the UI. + var self = this; + function compare(a, b) { + var locA = self.getObjectDescription(a); + var locB = self.getObjectDescription(b); + if(locA.path > locB.path) + return 1; + if(locA.path < locB.path) + return -1; + if(locA.name > locB.name) + return 1; + if(locA.name < locB.name) + return -1; + return 0; + } + var allLocs = this.getLocationList().sort(compare); + for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++); + + function transformIndex(index) { + if (reverse) { + // For the reverse case we need to implement wrap around. + var intermediate = curPos - index - 1; + return (intermediate < 0 ? allLocs.length : 0) + intermediate; + } else { + return (curPos + index + 1) % allLocs.length; + } + }; + + for (var next = 0; next < allLocs.length - 1; next++) + { + var object = allLocs[transformIndex(next)]; + + if (match(object)) + { + this.navigate(object); + return object; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // Called when "Options" clicked. Return array of + // {label: 'name', nol10n: true, type: "checkbox", checked: , command:function to set } + getOptionsMenuItems: function() + { + return null; + }, + + /* + * Called by chrome.onContextMenu to build the context menu when this panel has focus. + * See also FirebugRep for a similar function also called by onContextMenu + * Extensions may monkey patch and chain off this call + * @param object: the 'realObject', a model value, eg a DOM property + * @param target: the HTML element clicked on. + * @return an array of menu items. + */ + getContextMenuItems: function(object, target) + { + return []; + }, + + getBreakOnMenuItems: function() + { + return []; + }, + + getEditor: function(target, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getDefaultSelection: function() + { + return null; + }, + + browseObject: function(object) + { + }, + + getPopupObject: function(target) + { + return Firebug.getRepObject(target); + }, + + getTooltipObject: function(target) + { + return Firebug.getRepObject(target); + }, + + showInfoTip: function(infoTip, x, y) + { + + }, + + getObjectPath: function(object) + { + return null; + }, + + // An array of objects that can be passed to getObjectLocation. + // The list of things a panel can show, eg sourceFiles. + // Only shown if panel.location defined and supportsObject true + getLocationList: function() + { + return null; + }, + + getDefaultLocation: function() + { + return null; + }, + + getObjectLocation: function(object) + { + return ""; + }, + + // Text for the location list menu eg script panel source file list + // return.path: group/category label, return.name: item label + getObjectDescription: function(object) + { + var url = this.getObjectLocation(object); + return FBL.splitURLBase(url); + }, + + /* + * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint + * @param: show boolean, true turns on. + */ + highlight: function(show) + { + var tab = this.getTab(); + if (!tab) + return; + + if (show) + tab.setAttribute("highlight", "true"); + else + tab.removeAttribute("highlight"); + }, + + getTab: function() + { + var chrome = Firebug.chrome; + + var tab = chrome.$("fbPanelBar2").getTab(this.name); + if (!tab) + tab = chrome.$("fbPanelBar1").getTab(this.name); + return tab; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for Break On Next + + /** + * Called by the framework when the user clicks on the Break On Next button. + * @param {Boolean} armed Set to true if the Break On Next feature is + * to be armed for action and set to false if the Break On Next should be disarmed. + * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|. + */ + breakOnNext: function(armed) + { + }, + + /** + * Called when a panel is selected/displayed. The method should return true + * if the Break On Next feature is currently armed for this panel. + */ + shouldBreakOnNext: function() + { + return false; + }, + + /** + * Returns labels for Break On Next tooltip (one for enabled and one for disabled state). + * @param {Boolean} enabled Set to true if the Break On Next feature is + * currently activated for this panel. + */ + getBreakOnNextTooltip: function(enabled) + { + return null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // xxxpedro contextMenu + onContextMenu: function(event) + { + if (!this.getContextMenuItems) + return; + + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + var menu = this.getContextMenuItems(this.selection, target); + if (!menu) + return; + + var contextMenu = new Menu( + { + id: "fbPanelContextMenu", + + items: menu + }); + + contextMenu.show(event.clientX, event.clientY); + + return true; + + /* + // TODO: xxxpedro move code to somewhere. code to get cross-browser + // window to screen coordinates + var box = Firebug.browser.getElementPosition(Firebug.chrome.node); + + var screenY = 0; + + // Firefox + if (typeof window.mozInnerScreenY != "undefined") + { + screenY = window.mozInnerScreenY; + } + // Chrome + else if (typeof window.innerHeight != "undefined") + { + screenY = window.outerHeight - window.innerHeight; + } + // IE + else if (typeof window.screenTop != "undefined") + { + screenY = window.screenTop; + } + + contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top); + /**/ + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * MeasureBox + * To get pixels size.width and size.height: + *
      • this.startMeasuring(view);
      • + *
      • var size = this.measureText(lineNoCharsSpacer);
      • + *
      • this.stopMeasuring();
      • + *
      + * + * @namespace + */ +Firebug.MeasureBox = +{ + startMeasuring: function(target) + { + if (!this.measureBox) + { + this.measureBox = target.ownerDocument.createElement("span"); + this.measureBox.className = "measureBox"; + } + + copyTextStyles(target, this.measureBox); + target.ownerDocument.body.appendChild(this.measureBox); + }, + + getMeasuringElement: function() + { + return this.measureBox; + }, + + measureText: function(value) + { + this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m"; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + measureInputText: function(value) + { + value = value ? escapeForTextNode(value) : "m"; + if (!Firebug.showTextNodesWithWhitespace) + value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m'); + this.measureBox.innerHTML = value; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + getBox: function(target) + { + var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, ""); + var box = getBoxFromStyles(style, this.measureBox); + return box; + }, + + stopMeasuring: function() + { + this.measureBox.parentNode.removeChild(this.measureBox); + } +}; + + +// ************************************************************************************************ +if (FBL.domplate) Firebug.Rep = domplate( +{ + className: "", + inspectable: true, + + supportsObject: function(object, type) + { + return false; + }, + + inspectObject: function(object, context) + { + Firebug.chrome.select(object); + }, + + browseObject: function(object, context) + { + }, + + persistObject: function(object, context) + { + }, + + getRealObject: function(object, context) + { + return object; + }, + + getTitle: function(object) + { + var label = safeToString(object); + + var re = /\[object (.*?)\]/; + var m = re.exec(label); + + ///return m ? m[1] : label; + + // if the label is in the "[object TYPE]" format return its type + if (m) + { + return m[1]; + } + // if it is IE we need to handle some special cases + else if ( + // safeToString() fails to recognize some objects in IE + isIE && + // safeToString() returns "[object]" for some objects like window.Image + (label == "[object]" || + // safeToString() returns undefined for some objects like window.clientInformation + typeof object == "object" && typeof label == "undefined") + ) + { + return "Object"; + } + else + { + return label; + } + }, + + getTooltip: function(object) + { + return null; + }, + + getContextMenuItems: function(object, target, context) + { + return []; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Convenience for domplates + + STR: function(name) + { + return $STR(name); + }, + + cropString: function(text) + { + return cropString(text); + }, + + cropMultipleLines: function(text, limit) + { + return cropMultipleLines(text, limit); + }, + + toLowerCase: function(text) + { + return text ? text.toLowerCase() : text; + }, + + plural: function(n) + { + return n == 1 ? "" : "s"; + } +}); + +// ************************************************************************************************ + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-gui */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Controller + +/**@namespace*/ +FBL.Controller = { + + controllers: null, + controllerContext: null, + + initialize: function(context) + { + this.controllers = []; + this.controllerContext = context || Firebug.chrome; + }, + + shutdown: function() + { + this.removeControllers(); + + //this.controllers = null; + //this.controllerContext = null; + }, + + addController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + // If the first argument is a string, make a selector query + // within the controller node context + if (typeof arg[0] == "string") + { + arg[0] = $$(arg[0], this.controllerContext); + } + + // bind the handler to the proper context + var handler = arg[2]; + arg[2] = bind(handler, this); + // save the original handler as an extra-argument, so we can + // look for it later, when removing a particular controller + arg[3] = handler; + + this.controllers.push(arg); + addEvent.apply(this, arg); + } + }, + + removeController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + for (var j=0, c; c=this.controllers[j]; j++) + { + if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3]) + removeEvent.apply(this, c); + } + } + }, + + removeControllers: function() + { + for (var i=0, c; c=this.controllers[i]; i++) + { + removeEvent.apply(this, c); + } + } +}; + + +// ************************************************************************************************ +// PanelBar + +/**@namespace*/ +FBL.PanelBar = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + panelMap: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + selectedPanel: null, + parentPanelName: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function(ownerPanel) + { + this.panelMap = {}; + this.ownerPanel = ownerPanel; + + if (ownerPanel) + { + ownerPanel.sidePanelBarNode = createElement("span"); + ownerPanel.sidePanelBarNode.style.display = "none"; + ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode); + } + + var panels = Firebug.panelTypes; + for (var i=0, p; p=panels[i]; i++) + { + if ( // normal Panel of the Chrome's PanelBar + !ownerPanel && !p.prototype.parentPanel || + // Child Panel of the current Panel's SidePanelBar + ownerPanel && p.prototype.parentPanel && + ownerPanel.name == p.prototype.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + }, + + destroy: function() + { + PanelBar.shutdown.call(this); + + for (var name in this.panelMap) + { + this.removePanel(name); + + var panel = this.panelMap[name]; + panel.destroy(); + + this.panelMap[name] = null; + delete this.panelMap[name]; + } + + this.panelMap = null; + this.ownerPanel = null; + }, + + initialize: function() + { + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "inline"; + + for(var name in this.panelMap) + { + (function(self, name){ + + // tab click handler + var onTabClick = function onTabClick() + { + self.selectPanel(name); + return false; + }; + + Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]); + + })(this, name); + } + }, + + shutdown: function() + { + var selectedPanel = this.selectedPanel; + + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.hide(); + selectedPanel.shutdown(); + } + + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "none"; + + this.selectedPanel = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + addPanel: function(panelName, parentPanel) + { + var PanelType = Firebug.panelTypeMap[panelName]; + var panel = this.panelMap[panelName] = new PanelType(); + + panel.create(); + }, + + removePanel: function(panelName) + { + var panel = this.panelMap[panelName]; + if (panel.hasOwnProperty(panelName)) + panel.destroy(); + }, + + selectPanel: function(panelName) + { + var selectedPanel = this.selectedPanel; + var panel = this.panelMap[panelName]; + + if (panel && selectedPanel != panel) + { + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.shutdown(); + selectedPanel.hide(); + } + + if (!panel.parentPanel) + FirebugChrome.selectedPanelName = panelName; + + this.selectedPanel = panel; + + setClass(panel.tabNode, "fbSelectedTab"); + panel.show(); + panel.initialize(); + } + }, + + getPanel: function(panelName) + { + var panel = this.panelMap[panelName]; + + return panel; + } + +}; + +//************************************************************************************************ +// Button + +/** + * options.element + * options.caption + * options.title + * + * options.owner + * options.className + * options.pressedClassName + * + * options.onPress + * options.onUnpress + * options.onClick + * + * @class + * @extends FBL.Controller + * + */ + +FBL.Button = function(options) +{ + options = options || {}; + + append(this, options); + + this.state = "unpressed"; + this.display = "unpressed"; + + if (this.element) + { + this.container = this.element.parentNode; + } + else + { + this.shouldDestroy = true; + + this.container = this.owner.getPanel().toolButtonsNode; + + this.element = createElement("a", { + className: this.baseClassName + " " + this.className + " fbHover", + innerHTML: this.caption + }); + + if (this.title) + this.element.title = this.title; + + this.container.appendChild(this.element); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +Button.prototype = extend(Controller, +/**@extend FBL.Button.prototype*/ +{ + type: "normal", + caption: "caption", + title: null, + + className: "", // custom class + baseClassName: "fbButton", // control class + pressedClassName: "fbBtnPressed", // control pressed class + + element: null, + container: null, + owner: null, + + state: null, + display: null, + + destroy: function() + { + this.shutdown(); + + // only remove if it is a dynamically generated button (not pre-rendered) + if (this.shouldDestroy) + this.container.removeChild(this.element); + + this.element = null; + this.container = null; + this.owner = null; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var element = this.element; + + this.addController([element, "mousedown", this.handlePress]); + + if (this.type == "normal") + this.addController( + [element, "mouseup", this.handleUnpress], + [element, "mouseout", this.handleUnpress], + [element, "click", this.handleClick] + ); + }, + + shutdown: function() + { + Controller.shutdown.apply(this); + }, + + restore: function() + { + this.changeState("unpressed"); + }, + + changeState: function(state) + { + this.state = state; + this.changeDisplay(state); + }, + + changeDisplay: function(display) + { + if (display != this.display) + { + if (display == "pressed") + { + setClass(this.element, this.pressedClassName); + } + else if (display == "unpressed") + { + removeClass(this.element, this.pressedClassName); + } + this.display = display; + } + }, + + handlePress: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + this.changeDisplay("pressed"); + this.beforeClick = true; + } + else if (this.type == "toggle") + { + if (this.state == "pressed") + { + this.changeState("unpressed"); + + if (this.onUnpress) + this.onUnpress.apply(this.owner, arguments); + } + else + { + this.changeState("pressed"); + + if (this.onPress) + this.onPress.apply(this.owner, arguments); + } + + if (this.onClick) + this.onClick.apply(this.owner, arguments); + } + + return false; + }, + + handleUnpress: function(event) + { + cancelEvent(event, true); + + if (this.beforeClick) + this.changeDisplay("unpressed"); + + return false; + }, + + handleClick: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + if (this.onClick) + this.onClick.apply(this.owner); + + this.changeState("unpressed"); + } + + this.beforeClick = false; + + return false; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * @class + * @extends FBL.Button + */ +FBL.IconButton = function() +{ + Button.apply(this, arguments); +}; + +IconButton.prototype = extend(Button.prototype, +/**@extend FBL.IconButton.prototype*/ +{ + baseClassName: "fbIconButton", + pressedClassName: "fbIconPressed" +}); + + +//************************************************************************************************ +// Menu + +var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value", + _command: "$item.command"}; + +if (isIE6) + menuItemProps.href = "javascript:void(0)"; + +// Allow GUI to be loaded even when Domplate module is not installed. +if (FBL.domplate) +var MenuPlate = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "fbMenu fbShadow"}, + DIV({"class": "fbMenuContent fbShadowContent"}, + FOR("item", "$object.items|memberIterator", + TAG("$item.tag", {item: "$item"}) + ) + ) + ), + + itemTag: + A(menuItemProps, + "$item.label" + ), + + checkBoxTag: + A(extend(menuItemProps, {checked : "$item.checked"}), + + "$item.label" + ), + + radioButtonTag: + A(extend(menuItemProps, {selected : "$item.selected"}), + + "$item.label" + ), + + groupTag: + A(extend(menuItemProps, {child: "$item.child"}), + "$item.label" + ), + + shortcutTag: + A(menuItemProps, + "$item.label", + SPAN({"class": "fbMenuShortcutKey"}, + "$item.key" + ) + ), + + separatorTag: + SPAN({"class": "fbMenuSeparator"}), + + memberIterator: function(items) + { + var result = []; + + for (var i=0, length=items.length; i width || el.scrollHeight > height)) + { + width = el.scrollWidth; + height = el.scrollHeight; + } + + return {width: width, height: height}; + }, + + getWindowScrollPosition: function() + { + var top=0, left=0, el; + + if(typeof this.window.pageYOffset == "number") + { + top = this.window.pageYOffset; + left = this.window.pageXOffset; + } + else if((el=this.document.body) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + + return {top:top, left:left}; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Element Methods + + getElementFromPoint: function(x, y) + { + if (shouldFixElementFromPoint) + { + var scroll = this.getWindowScrollPosition(); + return this.document.elementFromPoint(x + scroll.left, y + scroll.top); + } + else + return this.document.elementFromPoint(x, y); + }, + + getElementPosition: function(el) + { + var left = 0 + var top = 0; + + do + { + left += el.offsetLeft; + top += el.offsetTop; + } + while (el = el.offsetParent); + + return {left:left, top:top}; + }, + + getElementBox: function(el) + { + var result = {}; + + if (el.getBoundingClientRect) + { + var rect = el.getBoundingClientRect(); + + // fix IE problem with offset when not in fullscreen mode + var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; + + var scroll = this.getWindowScrollPosition(); + + result.top = Math.round(rect.top - offset + scroll.top); + result.left = Math.round(rect.left - offset + scroll.left); + result.height = Math.round(rect.bottom - rect.top); + result.width = Math.round(rect.right - rect.left); + } + else + { + var position = this.getElementPosition(el); + + result.top = position.top; + result.left = position.left; + result.height = el.offsetHeight; + result.width = el.offsetWidth; + } + + return result; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Measurement Methods + + getMeasurement: function(el, name) + { + var result = {value: 0, unit: "px"}; + + var cssValue = this.getStyle(el, name); + + if (!cssValue) return result; + if (cssValue.toLowerCase() == "auto") return result; + + var reMeasure = /(\d+\.?\d*)(.*)/; + var m = cssValue.match(reMeasure); + + if (m) + { + result.value = m[1]-0; + result.unit = m[2].toLowerCase(); + } + + return result; + }, + + getMeasurementInPixels: function(el, name) + { + if (!el) return null; + + var m = this.getMeasurement(el, name); + var value = m.value; + var unit = m.unit; + + if (unit == "px") + return value; + + else if (unit == "pt") + return this.pointsToPixels(name, value); + + if (unit == "em") + return this.emToPixels(el, value); + + else if (unit == "%") + return this.percentToPixels(el, value); + }, + + getMeasurementBox1: function(el, name) + { + var sufixes = ["Top", "Left", "Bottom", "Right"]; + var result = []; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getMeasurementBox: function(el, name) + { + var result = []; + var sufixes = name == "border" ? + ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : + ["Top", "Left", "Bottom", "Right"]; + + if (isIE) + { + var propName, cssValue; + var autoMargin = null; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + { + propName = name + sufix; + + cssValue = el.currentStyle[propName] || el.style[propName]; + + if (cssValue == "auto") + { + if (!autoMargin) + autoMargin = this.getCSSAutoMarginBox(el); + + result[i] = autoMargin[sufix.toLowerCase()]; + } + else + result[i] = this.getMeasurementInPixels(el, propName); + + } + + } + else + { + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = this.getMeasurementInPixels(el, name + sufix); + } + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getCSSAutoMarginBox: function(el) + { + if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + var offsetTop = 0; + if (false && isIEStantandMode) + { + var scrollSize = Firebug.browser.getWindowScrollSize(); + offsetTop = scrollSize.height; + } + + var box = this.document.createElement("div"); + //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;"; + box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;"; + + var clone = el.cloneNode(false); + var text = this.document.createTextNode(" "); + clone.appendChild(text); + + box.appendChild(clone); + + this.document.body.appendChild(box); + + var marginTop = clone.offsetTop - box.offsetTop - 1; + var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; + + var marginLeft = clone.offsetLeft - box.offsetLeft - 1; + var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; + + this.document.body.removeChild(box); + + return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight}; + }, + + getFontSizeInPixels: function(el) + { + var size = this.getMeasurement(el, "fontSize"); + + if (size.unit == "px") return size.value; + + // get font size, the dirty way + var computeDirtyFontSize = function(el, calibration) + { + var div = this.document.createElement("div"); + var divStyle = offscreenStyle; + + if (calibration) + divStyle += " font-size:"+calibration+"px;"; + + div.style.cssText = divStyle; + div.innerHTML = "A"; + el.appendChild(div); + + var value = div.offsetHeight; + el.removeChild(div); + return value; + } + + /* + var calibrationBase = 200; + var calibrationValue = computeDirtyFontSize(el, calibrationBase); + var rate = calibrationBase / calibrationValue; + /**/ + + // the "dirty technique" fails in some environments, so we're using a static value + // based in some tests. + var rate = 200 / 225; + + var value = computeDirtyFontSize(el); + + return value * rate; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Unit Funtions + + pointsToPixels: function(name, value, returnFloat) + { + var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; + + var result = value * pixelsPerInch[axis] / 72; + + return returnFloat ? result : Math.round(result); + }, + + emToPixels: function(el, value) + { + if (!el) return null; + + var fontSize = this.getFontSizeInPixels(el); + + return Math.round(value * fontSize); + }, + + exToPixels: function(el, value) + { + if (!el) return null; + + // get ex value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "ex;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + percentToPixels: function(el, value) + { + if (!el) return null; + + // get % value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "%;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getStyle: isIE ? function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : function(el, name) + { + return this.document.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + } + +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Window Options + +var WindowDefaultOptions = + { + type: "frame", + id: "FirebugUI", + height: 250 + }, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Instantiated objects + + commandLine, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Interface Elements Cache + + fbTop, + fbContent, + fbContentStyle, + fbBottom, + fbBtnInspect, + + fbToolbar, + + fbPanelBox1, + fbPanelBox1Style, + fbPanelBox2, + fbPanelBox2Style, + fbPanelBar2Box, + fbPanelBar2BoxStyle, + + fbHSplitter, + fbVSplitter, + fbVSplitterStyle, + + fbPanel1, + fbPanel1Style, + fbPanel2, + fbPanel2Style, + + fbConsole, + fbConsoleStyle, + fbHTML, + + fbCommandLine, + fbLargeCommandLine, + fbLargeCommandButtons, + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Cached size values + + topHeight, + topPartialHeight, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastSelectedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLineState = 0, + lastFocusedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastHSplitterMouseMove = 0, + onHSplitterMouseMoveBuffer = null, + onHSplitterMouseMoveTimer = null, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastVSplitterMouseMove = 0; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// FirebugChrome + +/**@namespace*/ +FBL.FirebugChrome = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + isOpen: false, + height: 250, + sidePanelWidth: 350, + + selectedPanelName: "Console", + selectedHTMLElementId: null, + + chromeMap: {}, + + htmlSelectionStack: [], + consoleMessageQueue: [], + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); + + createChromeWindow(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); + + if (Env.chrome.type == "frame" || Env.chrome.type == "div") + ChromeMini.create(Env.chrome); + + var chrome = Firebug.chrome = new Chrome(Env.chrome); + FirebugChrome.chromeMap[chrome.type] = chrome; + + addGlobalEvent("keydown", onGlobalKeyDown); + + if (Env.Options.enablePersistent && chrome.type == "popup") + { + // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode + var frame = FirebugChrome.chromeMap.frame; + if (frame) + frame.close(); + + //chrome.reattach(frame, chrome); + //TODO: xxxpedro persist synchronize? + chrome.initialize(); + } + }, + + clone: function(FBChrome) + { + for (var name in FBChrome) + { + var prop = FBChrome[name]; + if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) + { + this[name] = prop; + } + } + } +}; + + + +// ************************************************************************************************ +// Chrome Window Creation + +var createChromeWindow = function(options) +{ + options = extend(WindowDefaultOptions, options || {}); + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Locals + + var chrome = {}, + + context = options.context || Env.browser, + + type = chrome.type = Env.Options.enablePersistent ? + "popup" : + options.type, + + isChromeFrame = type == "frame", + + useLocalSkin = Env.useLocalSkin, + + url = useLocalSkin ? + Env.Location.skin : + "about:blank", + + // document.body not available in XML+XSL documents in Firefox + body = context.document.getElementsByTagName("body")[0], + + formatNode = function(node) + { + if (!Env.isDebugMode) + { + node.firebugIgnore = true; + } + + node.style.border = "0"; + node.style.visibility = "hidden"; + node.style.zIndex = "2147483647"; // MAX z-index = 2147483647 + node.style.position = noFixedPosition ? "absolute" : "fixed"; + node.style.width = "100%"; // "102%"; IE auto margin bug + node.style.left = "0"; + node.style.bottom = noFixedPosition ? "-1px" : "0"; + node.style.height = options.height + "px"; + + // avoid flickering during chrome rendering + if (isFirefox) + node.style.display = "none"; + }, + + createChromeDiv = function() + { + //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed."); + + var node = chrome.node = createGlobalElement("div"), + style = createGlobalElement("style"), + + css = FirebugChrome.Skin.CSS + /* + .replace(/;/g, " !important;") + .replace(/!important\s!important/g, "!important") + .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/, + + // reset some styles to minimize interference from the main page's style + rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" + + // load the chrome styles + css + + // adjust some remaining styles + ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}"; + /* + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + rules += ".fbBody table.fbChrome{position: static !important;}"; + }/**/ + + style.type = "text/css"; + + if (style.styleSheet) + style.styleSheet.cssText = rules; + else + style.appendChild(context.document.createTextNode(rules)); + + document.getElementsByTagName("head")[0].appendChild(style); + + node.className = "fbBody"; + node.style.overflow = "hidden"; + node.innerHTML = getChromeDivTemplate(); + + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + setTimeout(function(){ + node.firstChild.style.height = "1px"; + node.firstChild.style.position = "static"; + },0); + /**/ + } + + formatNode(node); + + body.appendChild(node); + + chrome.window = window; + chrome.document = document; + onChromeLoad(chrome); + }; + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + try + { + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "div" (windowless mode) + if (type == "div") + { + createChromeDiv(); + return; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // cretate the Chrome as an "iframe" + else if (isChromeFrame) + { + // Create the Chrome Frame + var node = chrome.node = createGlobalElement("iframe"); + node.setAttribute("src", url); + node.setAttribute("frameBorder", "0"); + + formatNode(node); + + body.appendChild(node); + + // must set the id after appending to the document, otherwise will cause an + // strange error in IE, making the iframe load the page in which the bookmarklet + // was created (like getfirebug.com), before loading the injected UI HTML, + // generating an "Access Denied" error. + node.id = options.id; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "popup" + else + { + var height = FirebugChrome.height || options.height, + + options = [ + "true,top=", + Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0), + ",left=0,height=", + height, + ",width=", + screen.availWidth-10, // Opera opens popup in a new tab if it's too big! + ",resizable" + ].join(""), + + node = chrome.node = context.window.open( + url, + "popup", + options + ); + + if (node) + { + try + { + node.focus(); + } + catch(E) + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + else + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inject the interface HTML if it is not using the local skin + + if (!useLocalSkin) + { + var tpl = getChromeTemplate(!isChromeFrame), + doc = isChromeFrame ? node.contentWindow.document : node.document; + + doc.write(tpl); + doc.close(); + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Wait the Window to be loaded + + var win, + + waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100, + + waitForWindow = function() + { + if ( // Frame loaded... OR + isChromeFrame && (win=node.contentWindow) && + node.contentWindow.document.getElementById("fbCommandLine") || + + // Popup loaded + !isChromeFrame && (win=node.window) && node.document && + node.document.getElementById("fbCommandLine") ) + { + chrome.window = win.window; + chrome.document = win.document; + + // Prevent getting the wrong chrome height in FF when opening a popup + setTimeout(function(){ + onChromeLoad(chrome); + },0); + } + else + setTimeout(waitForWindow, waitDelay); + }; + + waitForWindow(); + } + catch(e) + { + var msg = e.message || e; + + if (/access/i.test(msg)) + { + // Firebug Lite could not create a window for its Graphical User Interface due to + // a access restriction. This happens in some pages, when loading via bookmarklet. + // In such cases, the only way is to load the GUI in a "windowless mode". + + if (isChromeFrame) + body.removeChild(node); + else if(type == "popup") + node.close(); + + // Load the GUI in a "windowless mode" + createChromeDiv(); + } + else + { + alert("Firebug Error: Firebug GUI could not be created."); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var onChromeLoad = function onChromeLoad(chrome) +{ + Env.chrome = chrome; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded"); + + if (Env.Options.enablePersistent) + { + // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode + Env.FirebugChrome = FirebugChrome; + + chrome.window.Firebug = chrome.window.Firebug || {}; + chrome.window.Firebug.SharedEnv = Env; + + if (Env.isDevelopmentMode) + { + Env.browser.window.FBDev.loadChromeApplication(chrome); + } + else + { + var doc = chrome.document; + var script = doc.createElement("script"); + script.src = Env.Location.app + "#remote,persist"; + doc.getElementsByTagName("head")[0].appendChild(script); + } + } + else + { + if (chrome.type == "frame" || chrome.type == "div") + { + // initialize the chrome application + setTimeout(function(){ + FBL.Firebug.initialize(); + },0); + } + else if (chrome.type == "popup") + { + var oldChrome = FirebugChrome.chromeMap.frame; + + var newChrome = new Chrome(chrome); + + // TODO: xxxpedro sync detach reattach attach + dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); + + if (oldChrome) + oldChrome.close(); + + newChrome.reattach(oldChrome, newChrome); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var getChromeDivTemplate = function() +{ + return FirebugChrome.Skin.HTML; +}; + +var getChromeTemplate = function(isPopup) +{ + var tpl = FirebugChrome.Skin; + var r = [], i = -1; + + r[++i] = ''; + r[++i] = ''; + r[++i] = Firebug.version; + + /* + r[++i] = ''; + /**/ + + r[++i] = ''; + /**/ + + r[++i] = ''; + r[++i] = tpl.HTML; + r[++i] = ''; + + return r.join(""); +}; + + +// ************************************************************************************************ +// Chrome Class + +/**@class*/ +var Chrome = function Chrome(chrome) +{ + var type = chrome.type; + var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; + + append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase) + append(this, chrome); // inherit chrome window properties + append(this, new Context(chrome.window)); // inherit from Context class + + FirebugChrome.chromeMap[type] = this; + Firebug.chrome = this; + Env.chrome = chrome.window; + + this.commandLineVisible = false; + this.sidePanelVisible = false; + + this.create(); + + return this; +}; + +// ************************************************************************************************ +// ChromeBase + +/** + * @namespace + * @extends FBL.Controller + * @extends FBL.PanelBar + **/ +var ChromeBase = {}; +append(ChromeBase, Controller); +append(ChromeBase, PanelBar); +append(ChromeBase, +/**@extend ns-chrome-ChromeBase*/ +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited properties + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from createChrome function + + node: null, + type: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from Context.prototype + + document: null, + window: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // value properties + + sidePanelVisible: false, + commandLineVisible: false, + largeCommandLineVisible: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // object properties + + inspectButton: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + PanelBar.create.call(this); + + if (Firebug.Inspector) + this.inspectButton = new Button({ + type: "toggle", + element: $("fbChrome_btInspect"), + owner: Firebug.Inspector, + + onPress: Firebug.Inspector.startInspecting, + onUnpress: Firebug.Inspector.stopInspecting + }); + }, + + destroy: function() + { + if(Firebug.Inspector) + this.inspectButton.destroy(); + + PanelBar.destroy.call(this); + + this.shutdown(); + }, + + testMenu: function() + { + var firebugMenu = new Menu( + { + id: "fbFirebugMenu", + + items: + [ + { + label: "Open Firebug", + type: "shortcut", + key: isFirefox ? "Shift+F12" : "F12", + checked: true, + command: "toggleChrome" + }, + { + label: "Open Firebug in New Window", + type: "shortcut", + key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12", + command: "openPopup" + }, + { + label: "Inspect Element", + type: "shortcut", + key: "Ctrl+Shift+C", + command: "toggleInspect" + }, + { + label: "Command Line", + type: "shortcut", + key: "Ctrl+Shift+L", + command: "focusCommandLine" + }, + "-", + { + label: "Options", + type: "group", + child: "fbFirebugOptionsMenu" + }, + "-", + { + label: "Firebug Lite Website...", + command: "visitWebsite" + }, + { + label: "Discussion Group...", + command: "visitDiscussionGroup" + }, + { + label: "Issue Tracker...", + command: "visitIssueTracker" + } + ], + + onHide: function() + { + iconButton.restore(); + }, + + toggleChrome: function() + { + Firebug.chrome.toggle(); + }, + + openPopup: function() + { + Firebug.chrome.toggle(true, true); + }, + + toggleInspect: function() + { + Firebug.Inspector.toggleInspect(); + }, + + focusCommandLine: function() + { + Firebug.chrome.focusCommandLine(); + }, + + visitWebsite: function() + { + this.visit("http://getfirebug.com/lite.html"); + }, + + visitDiscussionGroup: function() + { + this.visit("http://groups.google.com/group/firebug"); + }, + + visitIssueTracker: function() + { + this.visit("http://code.google.com/p/fbug/issues/list"); + }, + + visit: function(url) + { + window.open(url); + } + + }); + + /**@private*/ + var firebugOptionsMenu = + { + id: "fbFirebugOptionsMenu", + + getItems: function() + { + var cookiesDisabled = !Firebug.saveCookies; + + return [ + { + label: "Save Options in Cookies", + type: "checkbox", + value: "saveCookies", + checked: Firebug.saveCookies, + command: "saveOptions" + }, + "-", + { + label: "Start Opened", + type: "checkbox", + value: "startOpened", + checked: Firebug.startOpened, + disabled: cookiesDisabled + }, + { + label: "Start in New Window", + type: "checkbox", + value: "startInNewWindow", + checked: Firebug.startInNewWindow, + disabled: cookiesDisabled + }, + { + label: "Show Icon When Hidden", + type: "checkbox", + value: "showIconWhenHidden", + checked: Firebug.showIconWhenHidden, + disabled: cookiesDisabled + }, + { + label: "Override Console Object", + type: "checkbox", + value: "overrideConsole", + checked: Firebug.overrideConsole, + disabled: cookiesDisabled + }, + { + label: "Ignore Firebug Elements", + type: "checkbox", + value: "ignoreFirebugElements", + checked: Firebug.ignoreFirebugElements, + disabled: cookiesDisabled + }, + { + label: "Disable When Firebug Active", + type: "checkbox", + value: "disableWhenFirebugActive", + checked: Firebug.disableWhenFirebugActive, + disabled: cookiesDisabled + }, + { + label: "Disable XHR Listener", + type: "checkbox", + value: "disableXHRListener", + checked: Firebug.disableXHRListener, + disabled: cookiesDisabled + }, + { + label: "Enable Trace Mode", + type: "checkbox", + value: "enableTrace", + checked: Firebug.enableTrace, + disabled: cookiesDisabled + }, + { + label: "Enable Persistent Mode (experimental)", + type: "checkbox", + value: "enablePersistent", + checked: Firebug.enablePersistent, + disabled: cookiesDisabled + }, + "-", + { + label: "Reset All Firebug Options", + command: "restorePrefs", + disabled: cookiesDisabled + } + ]; + }, + + onCheck: function(target, value, checked) + { + Firebug.setPref(value, checked); + }, + + saveOptions: function(target) + { + var saveEnabled = target.getAttribute("checked"); + + if (!saveEnabled) this.restorePrefs(); + + this.updateMenu(target); + + return false; + }, + + restorePrefs: function(target) + { + Firebug.restorePrefs(); + + if(Firebug.saveCookies) + Firebug.savePrefs(); + else + Firebug.erasePrefs(); + + if (target) + this.updateMenu(target); + + return false; + }, + + updateMenu: function(target) + { + var options = getElementsByClass(target.parentNode, "fbMenuOption"); + + var firstOption = options[0]; + var enabled = Firebug.saveCookies; + if (enabled) + Menu.check(firstOption); + else + Menu.uncheck(firstOption); + + if (enabled) + Menu.check(options[0]); + else + Menu.uncheck(options[0]); + + for (var i = 1, length = options.length; i < length; i++) + { + var option = options[i]; + + var value = option.getAttribute("value"); + var pref = Firebug[value]; + + if (pref) + Menu.check(option); + else + Menu.uncheck(option); + + if (enabled) + Menu.enable(option); + else + Menu.disable(option); + } + } + }; + + Menu.register(firebugOptionsMenu); + + var menu = firebugMenu; + + var testMenuClick = function(event) + { + //console.log("testMenuClick"); + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + if (menu.isVisible) + menu.hide(); + else + { + var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position + + chrome = Firebug.chrome, + + box = chrome.getElementBox(target), + + offset = chrome.type == "div" ? + chrome.getElementPosition(chrome.node) : + {top: 0, left: 0}; + + menu.show( + box.left + offsetLeft - offset.left, + box.top + box.height -5 - offset.top + ); + } + + return false; + }; + + var iconButton = new IconButton({ + type: "toggle", + element: $("fbFirebugButton"), + + onClick: testMenuClick + }); + + iconButton.initialize(); + + //addEvent($("fbToolbarIcon"), "click", testMenuClick); + }, + + initialize: function() + { + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Env.bookmarkletOutdated) + Firebug.Console.logFormatted([ + "A new bookmarklet version is available. " + + "Please visit http://getfirebug.com/firebuglite#Install and update it." + ], Firebug.context, "warn"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Firebug.Console) + Firebug.Console.flush(); + + if (Firebug.Trace) + FBTrace.flush(Firebug.Trace); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize inherited classes + Controller.initialize.call(this); + PanelBar.initialize.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the interface elements cache + + fbTop = $("fbTop"); + fbContent = $("fbContent"); + fbContentStyle = fbContent.style; + fbBottom = $("fbBottom"); + fbBtnInspect = $("fbBtnInspect"); + + fbToolbar = $("fbToolbar"); + + fbPanelBox1 = $("fbPanelBox1"); + fbPanelBox1Style = fbPanelBox1.style; + fbPanelBox2 = $("fbPanelBox2"); + fbPanelBox2Style = fbPanelBox2.style; + fbPanelBar2Box = $("fbPanelBar2Box"); + fbPanelBar2BoxStyle = fbPanelBar2Box.style; + + fbHSplitter = $("fbHSplitter"); + fbVSplitter = $("fbVSplitter"); + fbVSplitterStyle = fbVSplitter.style; + + fbPanel1 = $("fbPanel1"); + fbPanel1Style = fbPanel1.style; + fbPanel2 = $("fbPanel2"); + fbPanel2Style = fbPanel2.style; + + fbConsole = $("fbConsole"); + fbConsoleStyle = fbConsole.style; + fbHTML = $("fbHTML"); + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + topHeight = fbTop.offsetHeight; + topPartialHeight = fbToolbar.offsetHeight; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + disableTextSelection($("fbToolbar")); + disableTextSelection($("fbPanelBarBox")); + disableTextSelection($("fbPanelBar1")); + disableTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6 + if (isIE6 && Firebug.Selector) + { + // TODO: xxxpedro change to getElementsByClass + var as = $$(".fbHover"); + for (var i=0, a; a=as[i]; i++) + { + a.setAttribute("href", "javascript:void(0)"); + } + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize all panels + /* + var panelMap = Firebug.panelTypes; + for (var i=0, p; p=panelMap[i]; i++) + { + if (!p.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + /**/ + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.initialize(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + this.addController( + [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine] + ); + + // ************************************************************************************************ + + // Select the first registered panel + // TODO: BUG IE7 + var self = this; + setTimeout(function(){ + self.selectPanel(FirebugChrome.selectedPanelName); + + if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine) + Firebug.chrome.focusCommandLine(); + },0); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + //this.draw(); + + + + + + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + var onPanelMouseDown = function onPanelMouseDown(event) + { + //console.log("onPanelMouseDown", event.target || event.srcElement, event); + + var target = event.target || event.srcElement; + + if (FBL.isLeftClick(event)) + { + var editable = FBL.getAncestorByClass(target, "editable"); + + // if an editable element has been clicked then start editing + if (editable) + { + Firebug.Editor.startEditing(editable); + FBL.cancelEvent(event); + } + // if any other element has been clicked then stop editing + else + { + if (!hasClass(target, "textEditorInner")) + Firebug.Editor.stopEditing(); + } + } + else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target)) + { + // Prevent auto-scroll when middle-clicking a rep object + FBL.cancelEvent(event); + } + }; + + Firebug.getElementPanel = function(element) + { + var panelNode = getAncestorByClass(element, "fbPanel"); + var id = panelNode.id.substr(2); + + var panel = Firebug.chrome.panelMap[id]; + + if (!panel) + { + if (Firebug.chrome.selectedPanel.sidePanelBar) + panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; + } + + return panel; + }; + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // TODO: xxxpedro port to Firebug + + // Improved window key code event listener. Only one "keydown" event will be attached + // to the window, and the onKeyCodeListen() function will delegate which listeners + // should be called according to the event.keyCode fired. + var onKeyCodeListenersMap = []; + var onKeyCodeListen = function(event) + { + for (var keyCode in onKeyCodeListenersMap) + { + var listeners = onKeyCodeListenersMap[keyCode]; + + for (var i = 0, listener; listener = listeners[i]; i++) + { + var filter = listener.filter || FBL.noKeyModifiers; + + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener.listener(); + FBL.cancelEvent(event, true); + return false; + } + } + } + }; + + addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); + + /** + * @name keyCodeListen + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + var keyCode = KeyEvent["DOM_VK_"+key]; + + if (!onKeyCodeListenersMap[keyCode]) + onKeyCodeListenersMap[keyCode] = []; + + onKeyCodeListenersMap[keyCode].push({ + filter: filter, + listener: listener + }); + + return keyCode; + }; + + /** + * @name keyIgnore + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyIgnore = function(keyCode) + { + onKeyCodeListenersMap[keyCode] = null; + delete onKeyCodeListenersMap[keyCode]; + }; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /**/ + // move to shutdown + //removeEvent(Firebug.chrome.document, "keydown", listener[0]); + + + /* + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + if (!filter) + filter = FBL.noKeyModifiers; + + var keyCode = KeyEvent["DOM_VK_"+key]; + + var fn = function fn(event) + { + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener(); + FBL.cancelEvent(event, true); + return false; + } + } + + addEvent(Firebug.chrome.document, "keydown", fn); + + return [fn, capture]; + }; + + Firebug.chrome.keyIgnore = function(listener) + { + removeEvent(Firebug.chrome.document, "keydown", listener[0]); + }; + /**/ + + + this.addController( + [fbPanel1, "mousedown", onPanelMouseDown], + [fbPanel2, "mousedown", onPanelMouseDown] + ); +/**/ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + + // menus can be used without domplate + if (FBL.domplate) + this.testMenu(); + /**/ + + //test XHR + /* + setTimeout(function(){ + + FBL.Ajax.request({url: "../content/firebug/boot.js"}); + FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); + + },1000); + /**/ + }, + + shutdown: function() + { + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.shutdown(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // remove disableTextSelection event handlers + restoreTextSelection($("fbToolbar")); + restoreTextSelection($("fbPanelBarBox")); + restoreTextSelection($("fbPanelBar1")); + restoreTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // shutdown inherited classes + Controller.shutdown.call(this); + PanelBar.shutdown.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Remove the interface elements cache (this must happen after calling + // the shutdown method of all dependent components to avoid errors) + + fbTop = null; + fbContent = null; + fbContentStyle = null; + fbBottom = null; + fbBtnInspect = null; + + fbToolbar = null; + + fbPanelBox1 = null; + fbPanelBox1Style = null; + fbPanelBox2 = null; + fbPanelBox2Style = null; + fbPanelBar2Box = null; + fbPanelBar2BoxStyle = null; + + fbHSplitter = null; + fbVSplitter = null; + fbVSplitterStyle = null; + + fbPanel1 = null; + fbPanel1Style = null; + fbPanel2 = null; + + fbConsole = null; + fbConsoleStyle = null; + fbHTML = null; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + + topHeight = null; + topPartialHeight = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + toggle: function(forceOpen, popup) + { + if(popup) + { + this.detach(); + } + else + { + if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) + { + var frame = FirebugChrome.chromeMap.frame; + frame.reattach(); + + FirebugChrome.chromeMap.popup = null; + + frame.open(); + + return; + } + + // If the context is a popup, ignores the toggle process + if (Firebug.chrome.type == "popup") return; + + var shouldOpen = forceOpen || !FirebugChrome.isOpen; + + if(shouldOpen) + this.open(); + else + this.close(); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + detach: function() + { + if(!FirebugChrome.chromeMap.popup) + { + createChromeWindow({type: "popup"}); + } + }, + + reattach: function(oldChrome, newChrome) + { + Firebug.browser.window.Firebug = Firebug; + + // chrome synchronization + var newPanelMap = newChrome.panelMap; + var oldPanelMap = oldChrome.panelMap; + + var panel; + for(var name in newPanelMap) + { + // TODO: xxxpedro innerHTML + panel = newPanelMap[name]; + if (panel.options.innerHTMLSync) + panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; + } + + Firebug.chrome = newChrome; + + // TODO: xxxpedro sync detach reattach attach + //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); + + if (newChrome.type == "popup") + { + newChrome.initialize(); + //dispatch(Firebug.modules, "initialize", []); + } + else + { + // TODO: xxxpedro only needed in persistent + // should use FirebugChrome.clone, but popup FBChrome + // isn't acessible + FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name; + } + + dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + draw: function() + { + var size = this.getSize(); + + // Height related values + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, + + y = Math.max(size.height /* chrome height */, topHeight), + + heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), + + height = heightValue + "px", + + // Width related values + sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0, + + width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Height related rendering + fbPanelBox1Style.height = height; + fbPanel1Style.height = height; + + if (isIE || isOpera) + { + // Fix IE and Opera problems with auto resizing the verticall splitter + fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px"; + } + //xxxpedro FF2 only? + /* + else if (isFirefox) + { + // Fix Firefox problem with table rows with 100% height (fit height) + fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px"; + }/**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Width related rendering + fbPanelBox1Style.width = width; + fbPanel1Style.width = width; + + // SidePanel rendering + if (Firebug.chrome.sidePanelVisible) + { + sideWidthValue = Math.max(sideWidthValue - 6, 0); + + var sideWidth = sideWidthValue + "px"; + + fbPanelBox2Style.width = sideWidth; + + fbVSplitterStyle.right = sideWidth; + + if (Firebug.chrome.largeCommandLineVisible) + { + fbLargeCommandLine = $("fbLargeCommandLine"); + + fbLargeCommandLine.style.height = heightValue - 4 + "px"; + fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; + + fbLargeCommandButtons = $("fbLargeCommandButtons"); + fbLargeCommandButtons.style.width = sideWidth; + } + else + { + fbPanel2Style.height = height; + fbPanel2Style.width = sideWidth; + + fbPanelBar2BoxStyle.width = sideWidth; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getSize: function() + { + return this.type == "div" ? + { + height: this.node.offsetHeight, + width: this.node.offsetWidth + } + : + this.getWindowSize(); + }, + + resize: function() + { + var self = this; + + // avoid partial resize when maximizing window + setTimeout(function(){ + self.draw(); + + if (noFixedPosition && (self.type == "frame" || self.type == "div")) + self.fixIEPosition(); + }, 0); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + layout: function(panel) + { + if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); + + var options = panel.options; + + changeCommandLineVisibility(options.hasCommandLine); + changeSidePanelVisibility(panel.hasSidePanel); + + Firebug.chrome.draw(); + }, + + showLargeCommandLine: function(hideToggleIcon) + { + var chrome = Firebug.chrome; + + if (!chrome.largeCommandLineVisible) + { + chrome.largeCommandLineVisible = true; + + if (chrome.selectedPanel.options.hasCommandLine) + { + if (Firebug.CommandLine) + Firebug.CommandLine.blur(); + + changeCommandLineVisibility(false); + } + + changeSidePanelVisibility(true); + + fbLargeCommandLine.style.display = "block"; + fbLargeCommandButtons.style.display = "block"; + + fbPanel2Style.display = "none"; + fbPanelBar2BoxStyle.display = "none"; + + chrome.draw(); + + fbLargeCommandLine.focus(); + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(true); + } + }, + + hideLargeCommandLine: function() + { + if (Firebug.chrome.largeCommandLineVisible) + { + Firebug.chrome.largeCommandLineVisible = false; + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(false); + + fbLargeCommandLine.blur(); + + fbPanel2Style.display = "block"; + fbPanelBar2BoxStyle.display = "block"; + + fbLargeCommandLine.style.display = "none"; + fbLargeCommandButtons.style.display = "none"; + + changeSidePanelVisibility(false); + + if (Firebug.chrome.selectedPanel.options.hasCommandLine) + changeCommandLineVisibility(true); + + Firebug.chrome.draw(); + + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLine: function() + { + var selectedPanelName = this.selectedPanel.name, panelToSelect; + + if (focusCommandLineState == 0 || selectedPanelName != "Console") + { + focusCommandLineState = 0; + lastFocusedPanelName = selectedPanelName; + + panelToSelect = "Console"; + } + if (focusCommandLineState == 1) + { + panelToSelect = lastFocusedPanelName; + } + + this.selectPanel(panelToSelect); + + try + { + if (Firebug.CommandLine) + { + if (panelToSelect == "Console") + Firebug.CommandLine.focus(); + else + Firebug.CommandLine.blur(); + } + } + catch(e) + { + //TODO: xxxpedro trace error + } + + focusCommandLineState = ++focusCommandLineState % 2; + } + +}); + +// ************************************************************************************************ +// ChromeFrameBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromeFrameBase = extend(ChromeBase, +/**@extend ns-chrome-ChromeFrameBase*/ +{ + create: function() + { + ChromeBase.create.call(this); + + // restore display for the anti-flicker trick + if (isFirefox) + this.node.style.display = "block"; + + if (Env.Options.startInNewWindow) + { + this.close(); + this.toggle(true, true); + return; + } + + if (Env.Options.startOpened) + this.open(); + else + this.close(); + }, + + destroy: function() + { + removeGlobalEvent("keydown", onGlobalKeyDown); + + ChromeBase.destroy.call(this); + + this.document = null; + delete this.document; + + this.window = null; + delete this.window; + + this.node.parentNode.removeChild(this.node); + this.node = null; + delete this.node; + }, + + initialize: function() + { + //FBTrace.sysout("Frame", "initialize();") + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.browser.window, "resize", this.resize], + [$("fbWindow_btClose"), "click", this.close], + [$("fbWindow_btDetach"), "click", this.detach], + [$("fbWindow_btDeactivate"), "click", this.deactivate] + ); + + if (!Env.Options.enablePersistent) + this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + fbVSplitter.onmousedown = onVSplitterMouseDown; + fbHSplitter.onmousedown = onHSplitterMouseDown; + + this.isInitialized = true; + }, + + shutdown: function() + { + fbVSplitter.onmousedown = null; + fbHSplitter.onmousedown = null; + + ChromeBase.shutdown.apply(this); + + this.isInitialized = false; + }, + + reattach: function() + { + var frame = FirebugChrome.chromeMap.frame; + + ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); + }, + + open: function() + { + if (!FirebugChrome.isOpen) + { + FirebugChrome.isOpen = true; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,1"); + + var node = this.node; + + node.style.visibility = "hidden"; // Avoid flickering + + if (Firebug.showIconWhenHidden) + { + if (ChromeMini.isInitialized) + { + ChromeMini.shutdown(); + } + + } + else + node.style.display = "block"; + + var main = $("fbChrome"); + + // IE6 throws an error when setting this property! why? + //main.style.display = "table"; + main.style.display = ""; + + var self = this; + setTimeout(function(){ + node.style.visibility = "visible"; + + //dispatch(Firebug.modules, "initialize", []); + self.initialize(); + + if (noFixedPosition) + self.fixIEPosition(); + + self.draw(); + + }, 10); + } + }, + + close: function() + { + if (FirebugChrome.isOpen || !this.isInitialized) + { + if (this.isInitialized) + { + //dispatch(Firebug.modules, "shutdown", []); + this.shutdown(); + } + + FirebugChrome.isOpen = false; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,0"); + + var node = this.node; + + if (Firebug.showIconWhenHidden) + { + node.style.visibility = "hidden"; // Avoid flickering + + // TODO: xxxpedro - persist IE fixed? + var main = $("fbChrome", FirebugChrome.chromeMap.frame.document); + main.style.display = "none"; + + ChromeMini.initialize(); + + node.style.visibility = "visible"; + } + else + node.style.display = "none"; + } + }, + + deactivate: function() + { + // if it is running as a Chrome extension, dispatch a message to the extension signaling + // that Firebug should be deactivated for the current tab + if (Env.isChromeExtension) + { + localStorage.removeItem("Firebug"); + Firebug.GoogleChrome.dispatch("FB_deactivate"); + + // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole + // app, otherwise it won't be able to be reactivated without reloading the page. + // but we need to stop listening global keys, otherwise the key activation won't work. + Firebug.chrome.close(); + } + else + { + Firebug.shutdown(); + } + }, + + fixIEPosition: function() + { + // fix IE problem with offset when not in fullscreen mode + var doc = this.document; + var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0; + + var size = Firebug.browser.getWindowSize(); + var scroll = Firebug.browser.getWindowScrollPosition(); + var maxHeight = size.height; + var height = this.node.offsetHeight; + + var bodyStyle = doc.body.currentStyle; + + this.node.style.top = maxHeight - height + scroll.top + "px"; + + if ((this.type == "frame" || this.type == "div") && + (bodyStyle.marginLeft || bodyStyle.marginRight)) + { + this.node.style.width = size.width + "px"; + } + + if (fbVSplitterStyle) + fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px"; + + this.draw(); + } + +}); + + +// ************************************************************************************************ +// ChromeMini + +/** + * @namespace + * @extends FBL.Controller + */ +var ChromeMini = extend(Controller, +/**@extend ns-chrome-ChromeMini*/ +{ + create: function(chrome) + { + append(this, chrome); + this.type = "mini"; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "block"; + + var miniIcon = $("fbMiniIcon", doc); + var width = miniIcon.offsetWidth + 10; + miniIcon.title = "Open " + Firebug.version; + + var errors = $("fbMiniErrors", doc); + if (errors.offsetWidth) + width += errors.offsetWidth + 10; + + var node = this.node; + node.style.height = "27px"; + node.style.width = width + "px"; + node.style.left = ""; + node.style.right = 0; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "true"); + this.document.body.style.backgroundColor = "transparent"; + } + else + node.style.background = "transparent"; + + if (noFixedPosition) + this.fixIEPosition(); + + this.addController( + [$("fbMiniIcon", doc), "click", onMiniIconClick] + ); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + this.isInitialized = true; + }, + + shutdown: function() + { + var node = this.node; + node.style.height = FirebugChrome.height + "px"; + node.style.width = "100%"; + node.style.left = 0; + node.style.right = ""; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "false"); + this.document.body.style.backgroundColor = "#fff"; + } + else + node.style.background = "#fff"; + + if (noFixedPosition) + this.fixIEPosition(); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "none"; + + Controller.shutdown.apply(this); + + this.isInitialized = false; + }, + + draw: function() + { + + }, + + fixIEPosition: ChromeFrameBase.fixIEPosition + +}); + + +// ************************************************************************************************ +// ChromePopupBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromePopupBase = extend(ChromeBase, +/**@extend ns-chrome-ChromePopupBase*/ +{ + + initialize: function() + { + setClass(this.document.body, "FirebugPopup"); + + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.chrome.window, "resize", this.resize], + [Firebug.chrome.window, "unload", this.destroy] + ); + + if (Env.Options.enablePersistent) + { + this.persist = bind(this.persist, this); + addEvent(Firebug.browser.window, "unload", this.persist); + } + else + this.addController( + [Firebug.browser.window, "unload", this.close] + ); + + fbVSplitter.onmousedown = onVSplitterMouseDown; + }, + + destroy: function() + { + // TODO: xxxpedro sync detach reattach attach + var frame = FirebugChrome.chromeMap.frame; + + if(frame) + { + dispatch(frame.panelMap, "detach", [this, frame]); + + frame.reattach(this, frame); + } + + if (Env.Options.enablePersistent) + { + removeEvent(Firebug.browser.window, "unload", this.persist); + } + + ChromeBase.destroy.apply(this); + + FirebugChrome.chromeMap.popup = null; + + this.node.close(); + }, + + persist: function() + { + persistTimeStart = new Date().getTime(); + + removeEvent(Firebug.browser.window, "unload", this.persist); + + Firebug.Inspector.destroy(); + Firebug.browser.window.FirebugOldBrowser = true; + + var persistTimeStart = new Date().getTime(); + + var waitMainWindow = function() + { + var doc, head; + + try + { + if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && + doc.documentElement && (head = doc.documentElement.firstChild)*/) + { + + try + { + // exposes the FBL to the global namespace when in debug mode + if (Env.isDebugMode) + { + window.FBL = FBL; + } + + window.Firebug = Firebug; + window.opener.Firebug = Firebug; + + Env.browser = window.opener; + Firebug.browser = Firebug.context = new Context(Env.browser); + + registerConsole(); + + // the delay time should be calculated right after registering the + // console, once right after the console registration, call log messages + // will be properly handled + var persistDelay = new Date().getTime() - persistTimeStart; + + var chrome = Firebug.chrome; + addEvent(Firebug.browser.window, "unload", chrome.persist); + + FBL.cacheDocument(); + Firebug.Inspector.create(); + + var htmlPanel = chrome.getPanel("HTML"); + htmlPanel.createUI(); + + Firebug.Console.logFormatted( + ["Firebug could not capture console calls during " + + persistDelay + "ms"], + Firebug.context, + "info" + ); + } + catch(pE) + { + alert("persist error: " + (pE.message || pE)); + } + + } + else + { + window.setTimeout(waitMainWindow, 0); + } + + } catch (E) { + window.close(); + } + }; + + waitMainWindow(); + }, + + close: function() + { + this.destroy(); + } + +}); + + +//************************************************************************************************ +// UI helpers + +var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) +{ + var last = Firebug.chrome.commandLineVisible; + var visible = Firebug.chrome.commandLineVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; + + if (visible != last) + { + if (visible) + { + fbBottom.className = ""; + + if (Firebug.CommandLine) + Firebug.CommandLine.activate(); + } + else + { + if (Firebug.CommandLine) + Firebug.CommandLine.deactivate(); + + fbBottom.className = "hide"; + } + } +}; + +var changeSidePanelVisibility = function changeSidePanelVisibility(visibility) +{ + var last = Firebug.chrome.sidePanelVisible; + Firebug.chrome.sidePanelVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible; + + if (Firebug.chrome.sidePanelVisible != last) + { + fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + } +}; + + +// ************************************************************************************************ +// F12 Handler + +var onGlobalKeyDown = function onGlobalKeyDown(event) +{ + var keyCode = event.keyCode; + var shiftKey = event.shiftKey; + var ctrlKey = event.ctrlKey; + + if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox)) + { + Firebug.chrome.toggle(false, ctrlKey); + cancelEvent(event, true); + + // TODO: xxxpedro replace with a better solution. we're doing this + // to allow reactivating with the F12 key after being deactivated + if (Env.isChromeExtension) + { + Firebug.GoogleChrome.dispatch("FB_enableIcon"); + } + } + else if (keyCode == 67 /* C */ && ctrlKey && shiftKey) + { + Firebug.Inspector.toggleInspect(); + cancelEvent(event, true); + } + else if (keyCode == 76 /* L */ && ctrlKey && shiftKey) + { + Firebug.chrome.focusCommandLine(); + cancelEvent(event, true); + } +}; + +var onMiniIconClick = function onMiniIconClick(event) +{ + Firebug.chrome.toggle(false, event.ctrlKey); + cancelEvent(event, true); +}; + + +// ************************************************************************************************ +// Horizontal Splitter Handling + +var onHSplitterMouseDown = function onHSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onHSplitterMouseMove); + addGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = "fbOnMovingHSplitter"; + + return false; +}; + +var onHSplitterMouseMove = function onHSplitterMouseMove(event) +{ + cancelEvent(event, true); + + var clientY = event.clientY; + var win = isIE + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument && event.target.ownerDocument.defaultView; + + if (!win) + return; + + if (win != win.parent) + { + var frameElement = win.frameElement; + if (frameElement) + { + var framePos = Firebug.browser.getElementPosition(frameElement).top; + clientY += framePos; + + if (frameElement.style.position != "fixed") + clientY -= Firebug.browser.getWindowScrollPosition().top; + } + } + + if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI") + { + clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY; + } + /* + console.log( + typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome", + //win.frameElement.id, + event.target, + clientY + );/**/ + + onHSplitterMouseMoveBuffer = clientY; // buffer + + if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + lastHSplitterMouseMove = new Date().getTime(); + handleHSplitterMouseMove(); + } + else + if (!onHSplitterMouseMoveTimer) + onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate); + + // improving the resizing performance by canceling the mouse event. + // canceling events will prevent the page to receive such events, which would imply + // in more processing being expended. + cancelEvent(event, true); + return false; +}; + +var handleHSplitterMouseMove = function() +{ + if (onHSplitterMouseMoveTimer) + { + clearTimeout(onHSplitterMouseMoveTimer); + onHSplitterMouseMoveTimer = null; + } + + var clientY = onHSplitterMouseMoveBuffer; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + + // compute chrome fixed size (top bar and command line) + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0; + var fixedHeight = topHeight + commandLineHeight; + var chromeNode = Firebug.chrome.node; + + var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; + + //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; + var height = windowSize.height; + + // compute the min and max size of the chrome + var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight); + chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize); + + FirebugChrome.height = chromeHeight; + chromeNode.style.height = chromeHeight + "px"; + + if (noFixedPosition) + Firebug.chrome.fixIEPosition(); + + Firebug.chrome.draw(); +}; + +var onHSplitterMouseUp = function onHSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onHSplitterMouseMove); + removeGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = ""; + + Firebug.chrome.draw(); + + // avoid text selection in IE when returning to the document + // after the mouse leaves the document during the resizing + return false; +}; + + +// ************************************************************************************************ +// Vertical Splitter Handling + +var onVSplitterMouseDown = function onVSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onVSplitterMouseMove); + addGlobalEvent("mouseup", onVSplitterMouseUp); + + return false; +}; + +var onVSplitterMouseMove = function onVSplitterMouseMove(event) +{ + if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + var target = event.target || event.srcElement; + if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome + { + var clientX = event.clientX; + var win = document.all + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument.defaultView; + + if (win != win.parent) + clientX += win.frameElement ? win.frameElement.offsetLeft : 0; + + var size = Firebug.chrome.getSize(); + var x = Math.max(size.width - clientX + 3, 6); + + FirebugChrome.sidePanelWidth = x; + Firebug.chrome.draw(); + } + + lastVSplitterMouseMove = new Date().getTime(); + } + + cancelEvent(event, true); + return false; +}; + +var onVSplitterMouseUp = function onVSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onVSplitterMouseMove); + removeGlobalEvent("mouseup", onVSplitterMouseUp); + + Firebug.chrome.draw(); +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Browser = function(window) +{ + this.contentWindow = window; + this.contentDocument = window.document; + this.currentURI = + { + spec: window.location.href + }; +}; + +Firebug.Lite.Browser.prototype = +{ + toString: function() + { + return "Firebug.Lite.Browser"; + } +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Cache = +{ + ID: "firebug" + new Date().getTime() +}; + +// ************************************************************************************************ + +/** + * TODO: if a cached element is cloned, the expando property will be cloned too in IE + * which will result in a bug. Firebug Lite will think the new cloned node is the old + * one. + * + * TODO: Investigate a possibility of cache validation, to be customized by each + * kind of cache. For ElementCache it should validate if the element still is + * inserted at the DOM. + */ +var cacheUID = 0; +var createCache = function() +{ + var map = {}; + var CID = Firebug.Lite.Cache.ID; + + // better detection + var supportsDeleteExpando = !document.all; + + var cacheFunction = function(element) + { + return cacheAPI.set(element); + }; + + var cacheAPI = + { + get: function(key) + { + return map.hasOwnProperty(key) ? + map[key] : + null; + }, + + set: function(element) + { + var id = element[CID]; + + if (!id) + { + id = ++cacheUID; + element[CID] = id; + } + + if (!map.hasOwnProperty(id)) + { + map[id] = element; + } + + return id; + }, + + unset: function(element) + { + var id = element[CID]; + + if (supportsDeleteExpando) + { + delete element[CID]; + } + else if (element.removeAttribute) + { + element.removeAttribute(CID); + } + + delete map[id]; + + }, + + key: function(element) + { + return element[CID]; + }, + + has: function(element) + { + return map.hasOwnProperty(element[CID]); + }, + + clear: function() + { + for (var id in map) + { + var element = map[id]; + cacheAPI.unset(element); + } + } + }; + + FBL.append(cacheFunction, cacheAPI); + + return cacheFunction; +}; + +// ************************************************************************************************ + +// TODO: xxxpedro : check if we need really this on FBL scope +Firebug.Lite.Cache.StyleSheet = createCache(); +Firebug.Lite.Cache.Element = createCache(); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Proxy = +{ + // jsonp callbacks + _callbacks: {}, + + /** + * Load a resource, either locally (directly) or externally (via proxy) using + * synchronous XHR calls. Loading external resources requires the proxy plugin to + * be installed and configured (see /plugin/proxy/proxy.php). + */ + load: function(url) + { + var resourceDomain = getDomain(url); + var isLocalResource = + // empty domain means local URL + !resourceDomain || + // same domain means local too + resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context + + return isLocalResource ? fetchResource(url) : fetchProxyResource(url); + }, + + /** + * Load a resource using JSONP technique. + */ + loadJSONP: function(url, callback) + { + var script = createGlobalElement("script"), + doc = Firebug.context.document, + + uid = "" + new Date().getTime(), + callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, + + jsonpURL = url.indexOf("?") != -1 ? + url + "&" + callbackName : + url + "?" + callbackName; + + Firebug.Lite.Proxy._callbacks[uid] = function(data) + { + if (callback) + callback(data); + + script.parentNode.removeChild(script); + delete Firebug.Lite.Proxy._callbacks[uid]; + }; + + script.src = jsonpURL; + + if (doc.documentElement) + doc.documentElement.appendChild(script); + }, + + /** + * Load a resource using YQL (not reliable). + */ + YQL: function(url, callback) + { + var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + + encodeURIComponent(url) + "%22&format=xml"; + + this.loadJSONP(yql, function(data) + { + var source = data.results[0]; + + // clean up YQL bogus elements + var match = /\s+

      ([\s\S]+)<\/p>\s+<\/body>$/.exec(source); + if (match) + source = match[1]; + + console.log(source); + }); + } +}; + +// ************************************************************************************************ + +var fetchResource = function(url) +{ + var xhr = FBL.Ajax.getXHRObject(); + xhr.open("get", url, false); + xhr.send(); + + return xhr.responseText; +}; + +var fetchProxyResource = function(url) +{ + var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); + var response = fetchResource(proxyURL); + + try + { + var data = eval("(" + response + ")"); + } + catch(E) + { + return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; + } + + return data ? data.contents : ""; +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Script = function(window) +{ + this.fileName = null; + this.isValid = null; + this.baseLineNumber = null; + this.lineExtent = null; + this.tag = null; + + this.functionName = null; + this.functionSource = null; +}; + +Firebug.Lite.Script.prototype = +{ + isLineExecutable: function(){}, + pcToLine: function(){}, + lineToPc: function(){}, + + toString: function() + { + return "Firebug.Lite.Script"; + } +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Style = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-selector*/ function() { with (FBL) { +// ************************************************************************************************ + +/* + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +/** + * @name Firebug.Selector + * @namespace + */ + +/** + * @exports Sizzle as Firebug.Selector + */ +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +/**#@+ @ignore */ +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + if ( div.getElementsByClassName("e").length === 0 ) + return; + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE + +Firebug.Selector = Sizzle; + +/**#@-*/ + +// ************************************************************************************************ +}}); + +// Problems in IE +// FIXED - eval return +// FIXED - addEventListener problem in IE +// FIXED doc.createRange? +// +// class reserved word +// test all honza examples in IE6 and IE7 + + +/* See license.txt for terms of usage */ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function DomplateTag(tagName) +{ + this.tagName = tagName; +} + +function DomplateEmbed() +{ +} + +function DomplateLoop() +{ +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +( /** @scope ns-domplate */ function() { + +var womb = null; + +var domplate = FBL.domplate = function() +{ + var lastSubject; + for (var i = 0; i < arguments.length; ++i) + lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i]; + + for (var name in lastSubject) + { + var val = lastSubject[name]; + if (isTag(val)) + val.tag.subject = lastSubject; + } + + return lastSubject; +}; + +domplate.context = function(context, fn) +{ + var lastContext = domplate.lastContext; + domplate.topContext = context; + fn.apply(context); + domplate.topContext = lastContext; +}; + +FBL.TAG = function() +{ + var embed = new DomplateEmbed(); + return embed.merge(arguments); +}; + +FBL.FOR = function() +{ + var loop = new DomplateLoop(); + return loop.merge(arguments); +}; + +DomplateTag.prototype = +{ + merge: function(args, oldTag) + { + if (oldTag) + this.tagName = oldTag.tagName; + + this.context = oldTag ? oldTag.context : null; + this.subject = oldTag ? oldTag.subject : null; + this.attrs = oldTag ? copyObject(oldTag.attrs) : {}; + this.classes = oldTag ? copyObject(oldTag.classes) : {}; + this.props = oldTag ? copyObject(oldTag.props) : null; + this.listeners = oldTag ? copyArray(oldTag.listeners) : null; + this.children = oldTag ? copyArray(oldTag.children) : []; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args.length ? args[0] : null; + var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); + + this.children = []; + + if (domplate.topContext) + this.context = domplate.topContext; + + if (args.length) + parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); + + if (hasAttrs) + this.parseAttrs(attrs); + + return creator(this, DomplateTag); + }, + + parseAttrs: function(args) + { + for (var name in args) + { + var val = parseValue(args[name]); + readPartNames(val, this.vars); + + if (name.indexOf("on") == 0) + { + var eventName = name.substr(2); + if (!this.listeners) + this.listeners = []; + this.listeners.push(eventName, val); + } + else if (name.indexOf("_") == 0) + { + var propName = name.substr(1); + if (!this.props) + this.props = {}; + this.props[propName] = val; + } + else if (name.indexOf("$") == 0) + { + var className = name.substr(1); + if (!this.classes) + this.classes = {}; + this.classes[className] = val; + } + else + { + if (name == "class" && this.attrs.hasOwnProperty(name) ) + this.attrs[name] += " " + val; + else + this.attrs[name] = val; + } + } + }, + + compile: function() + { + if (this.renderMarkup) + return; + + this.compileMarkup(); + this.compileDOM(); + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs); + }, + + compileMarkup: function() + { + this.markupArgs = []; + var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; + + this.generateMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + + var fnBlock = ['r=(function (__code__, __context__, __in__, __out__']; + for (var i = 0; i < info.argIndex; ++i) + fnBlock.push(', s', i); + fnBlock.push(') {'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (__context__) {'); + fnBlock.push('with (__in__) {'); + + fnBlock.push.apply(fnBlock, blocks); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('}})'); + + function __link__(tag, code, outputs, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var tagOutputs = []; + var markupArgs = [code, tag.tag.context, args, tagOutputs]; + markupArgs.push.apply(markupArgs, tag.tag.markupArgs); + tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs); + + outputs.push(tag); + outputs.push(tagOutputs); + } + + function __escape__(value) + { + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); + } + + function __loop__(iter, outputs, fn) + { + var iterOuts = []; + outputs.push(iterOuts); + + if (iter instanceof Array) + iter = new ArrayIterator(iter); + + try + { + while (1) + { + var value = iter.next(); + var itemOuts = [0,0]; + iterOuts.push(itemOuts); + fn.apply(this, [value, itemOuts]); + } + } + catch (exc) + { + if (exc != StopIteration) + throw exc; + } + } + + var js = fnBlock.join(""); + var r = null; + eval(js); + this.renderMarkup = r; + }, + + getVarNames: function(args) + { + if (this.vars) + args.push.apply(args, this.vars); + + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.getVarNames(args); + else if (child instanceof Parts) + { + for (var i = 0; i < child.parts.length; ++i) + { + if (child.parts[i] instanceof Variable) + { + var name = child.parts[i].name; + var names = name.split("."); + args.push(names[0]); + } + } + } + } + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + topBlock.push(',"<', this.tagName, '"'); + + for (var name in this.attrs) + { + if (name != "class") + { + var val = this.attrs[name]; + topBlock.push(', " ', name, '=\\""'); + addParts(val, ',', topBlock, info, true); + topBlock.push(', "\\""'); + } + } + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + readPartNames(this.listeners[i+1], topOuts); + } + + if (this.props) + { + for (var name in this.props) + readPartNames(this.props[name], topOuts); + } + + if ( this.attrs.hasOwnProperty("class") || this.classes) + { + topBlock.push(', " class=\\""'); + if (this.attrs.hasOwnProperty("class")) + addParts(this.attrs["class"], ',', topBlock, info, true); + topBlock.push(', " "'); + for (var name in this.classes) + { + topBlock.push(', ('); + addParts(this.classes[name], '', topBlock, info); + topBlock.push(' ? "', name, '" + " " : "")'); + } + topBlock.push(', "\\""'); + } + topBlock.push(',">"'); + + this.generateChildMarkup(topBlock, topOuts, blocks, info); + topBlock.push(',""'); + }, + + generateChildMarkup: function(topBlock, topOuts, blocks, info) + { + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.generateMarkup(topBlock, topOuts, blocks, info); + else + addParts(child, ',', topBlock, info, true); + } + }, + + addCode: function(topBlock, topOuts, blocks) + { + if (topBlock.length) + blocks.push('__code__.push(""', topBlock.join(""), ');'); + if (topOuts.length) + blocks.push('__out__.push(', topOuts.join(","), ');'); + topBlock.splice(0, topBlock.length); + topOuts.splice(0, topOuts.length); + }, + + addLocals: function(blocks) + { + var varNames = []; + this.getVarNames(varNames); + + var map = {}; + for (var i = 0; i < varNames.length; ++i) + { + var name = varNames[i]; + if ( map.hasOwnProperty(name) ) + continue; + + map[name] = 1; + var names = name.split("."); + blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); + } + }, + + compileDOM: function() + { + var path = []; + var blocks = []; + this.domArgs = []; + path.embedIndex = 0; + path.loopIndex = 0; + path.staticIndex = 0; + path.renderIndex = 0; + var nodeCount = this.generateDOM(path, blocks, this.domArgs); + + var fnBlock = ['r=(function (root, context, o']; + + for (var i = 0; i < path.staticIndex; ++i) + fnBlock.push(', ', 's'+i); + + for (var i = 0; i < path.renderIndex; ++i) + fnBlock.push(', ', 'd'+i); + + fnBlock.push(') {'); + for (var i = 0; i < path.loopIndex; ++i) + fnBlock.push('var l', i, ' = 0;'); + for (var i = 0; i < path.embedIndex; ++i) + fnBlock.push('var e', i, ' = 0;'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (context) {'); + + fnBlock.push(blocks.join("")); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('return ', nodeCount, ';'); + fnBlock.push('})'); + + function __bind__(object, fn) + { + return function(event) { return fn.apply(object, [event]); }; + } + + function __link__(node, tag, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var domArgs = [node, tag.tag.context, 0]; + domArgs.push.apply(domArgs, tag.tag.domArgs); + domArgs.push.apply(domArgs, args); + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs); + return tag.tag.renderDOM.apply(tag.tag.subject, domArgs); + } + + var self = this; + function __loop__(iter, fn) + { + var nodeCount = 0; + for (var i = 0; i < iter.length; ++i) + { + iter[i][0] = i; + iter[i][1] = nodeCount; + nodeCount += fn.apply(this, iter[i]); + //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount); + } + return nodeCount; + } + + function __path__(parent, offset) + { + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); + var root = parent; + + for (var i = 2; i < arguments.length; ++i) + { + var index = arguments[i]; + if (i == 3) + index += offset; + + if (index == -1) + parent = parent.parentNode; + else + parent = parent.childNodes[index]; + } + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); + return parent; + } + + var js = fnBlock.join(""); + //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); + var r = null; + eval(js); + this.renderDOM = r; + }, + + generateDOM: function(path, blocks, args) + { + if (this.listeners || this.props) + this.generateNodePath(path, blocks); + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + { + var val = this.listeners[i+1]; + var arg = generateArg(val, path, args); + //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + } + } + + if (this.props) + { + for (var name in this.props) + { + var val = this.props[name]; + var arg = generateArg(val, path, args); + blocks.push('node.', name, ' = ', arg, ';'); + } + } + + this.generateChildDOM(path, blocks, args); + return 1; + }, + + generateNodePath: function(path, blocks) + { + blocks.push("var node = __path__(root, o"); + for (var i = 0; i < path.length; ++i) + blocks.push(",", path[i]); + blocks.push(");"); + }, + + generateChildDOM: function(path, blocks, args) + { + path.push(0); + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args); + else + path[path.length-1] += '+1'; + } + path.pop(); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateEmbed.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.value = oldTag ? oldTag.value : parseValue(args[0]); + this.attrs = oldTag ? oldTag.attrs : {}; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args[1]; + for (var name in attrs) + { + var val = parseValue(attrs[name]); + this.attrs[name] = val; + readPartNames(val, this.vars); + } + + return creator(this, DomplateEmbed); + }, + + getVarNames: function(names) + { + if (this.value instanceof Parts) + names.push(this.value.parts[0].name); + + if (this.vars) + names.push.apply(names, this.vars); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + blocks.push('__link__('); + addParts(this.value, '', blocks, info); + blocks.push(', __code__, __out__, {'); + + var lastName = null; + for (var name in this.attrs) + { + if (lastName) + blocks.push(','); + lastName = name; + + var val = this.attrs[name]; + blocks.push('"', name, '":'); + addParts(val, '', blocks, info); + } + + blocks.push('});'); + //this.generateChildMarkup(topBlock, topOuts, blocks, info); + }, + + generateDOM: function(path, blocks, args) + { + var embedName = 'e'+path.embedIndex++; + + this.generateNodePath(path, blocks); + + var valueName = 'd' + path.renderIndex++; + var argsName = 'd' + path.renderIndex++; + blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); + + return embedName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateLoop.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.varName = oldTag ? oldTag.varName : args[0]; + this.iter = oldTag ? oldTag.iter : parseValue(args[1]); + this.vars = []; + + this.children = oldTag ? copyArray(oldTag.children) : []; + + var offset = Math.min(args.length, 2); + parseChildren(args, offset, this.vars, this.children); + + return creator(this, DomplateLoop); + }, + + getVarNames: function(names) + { + if (this.iter instanceof Parts) + names.push(this.iter.parts[0].name); + + DomplateTag.prototype.getVarNames.apply(this, [names]); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + var iterName; + if (this.iter instanceof Parts) + { + var part = this.iter.parts[0]; + iterName = part.name; + + if (part.format) + { + for (var i = 0; i < part.format.length; ++i) + iterName = part.format[i] + "(" + iterName + ")"; + } + } + else + iterName = this.iter; + + blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {'); + this.generateChildMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + blocks.push('}]);'); + }, + + generateDOM: function(path, blocks, args) + { + var iterName = 'd'+path.renderIndex++; + var counterName = 'i'+path.loopIndex; + var loopName = 'l'+path.loopIndex++; + + if (!path.length) + path.push(-1, 0); + + var preIndex = path.renderIndex; + path.renderIndex = 0; + + var nodeCount = 0; + + var subBlocks = []; + var basePath = path[path.length-1]; + for (var i = 0; i < this.children.length; ++i) + { + path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount; + + var child = this.children[i]; + if (isTag(child)) + nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args); + else + nodeCount += '+1'; + } + + path[path.length-1] = basePath+'+'+loopName; + + blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName); + for (var i = 0; i < path.renderIndex; ++i) + blocks.push(',d'+i); + blocks.push(') {'); + blocks.push(subBlocks.join("")); + blocks.push('return ', nodeCount, ';'); + blocks.push('}]);'); + + path.renderIndex = preIndex; + + return loopName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function Variable(name, format) +{ + this.name = name; + this.format = format; +} + +function Parts(parts) +{ + this.parts = parts; +} + +// ************************************************************************************************ + +function parseParts(str) +{ + var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g; + var index = 0; + var parts = []; + + var m; + while (m = re.exec(str)) + { + var pre = str.substr(index, (re.lastIndex-m[0].length)-index); + if (pre) + parts.push(pre); + + var expr = m[1].split("|"); + parts.push(new Variable(expr[0], expr.slice(1))); + index = re.lastIndex; + } + + if (!index) + return str; + + var post = str.substr(index); + if (post) + parts.push(post); + + return new Parts(parts); +} + +function parseValue(val) +{ + return typeof(val) == 'string' ? parseParts(val) : val; +} + +function parseChildren(args, offset, vars, children) +{ + for (var i = offset; i < args.length; ++i) + { + var val = parseValue(args[i]); + children.push(val); + readPartNames(val, vars); + } +} + +function readPartNames(val, vars) +{ + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + vars.push(part.name); + } + } +} + +function generateArg(val, path, args) +{ + if (val instanceof Parts) + { + var vals = []; + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var varName = 'd'+path.renderIndex++; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + varName = part.format[j] + '(' + varName + ')'; + } + + vals.push(varName); + } + else + vals.push('"'+part.replace(/"/g, '\\"')+'"'); + } + + return vals.join('+'); + } + else + { + args.push(val); + return 's' + path.staticIndex++; + } +} + +function addParts(val, delim, block, info, escapeIt) +{ + var vals = []; + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var partName = part.name; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + partName = part.format[j] + "(" + partName + ")"; + } + + if (escapeIt) + vals.push("__escape__(" + partName + ")"); + else + vals.push(partName); + } + else + vals.push('"'+ part + '"'); + } + } + else if (isTag(val)) + { + info.args.push(val); + vals.push('s'+info.argIndex++); + } + else + vals.push('"'+ val + '"'); + + var parts = vals.join(delim); + if (parts) + block.push(delim, parts); +} + +function isTag(obj) +{ + return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag; +} + +function creator(tag, cons) +{ + var fn = new Function( + "var tag = arguments.callee.tag;" + + "var cons = arguments.callee.cons;" + + "var newTag = new cons();" + + "return newTag.merge(arguments, tag);"); + + fn.tag = tag; + fn.cons = cons; + extend(fn, Renderer); + + return fn; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function copyArray(oldArray) +{ + var ary = []; + if (oldArray) + for (var i = 0; i < oldArray.length; ++i) + ary.push(oldArray[i]); + return ary; +} + +function copyObject(l, r) +{ + var m = {}; + extend(m, l); + extend(m, r); + return m; +} + +function extend(l, r) +{ + for (var n in r) + l[n] = r[n]; +} + +function addEvent(object, name, handler) +{ + if (document.all) + object.attachEvent("on"+name, handler); + else + object.addEventListener(name, handler, false); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function ArrayIterator(array) +{ + var index = -1; + + this.next = function() + { + if (++index >= array.length) + throw StopIteration; + + return array[index]; + }; +} + +function StopIteration() {} + +FBL.$break = function() +{ + throw StopIteration; +}; + +// ************************************************************************************************ + +var Renderer = +{ + renderHTML: function(args, outputs, self) + { + var code = []; + var markupArgs = [code, this.tag.context, args, outputs]; + markupArgs.push.apply(markupArgs, this.tag.markupArgs); + this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs); + return code.join(""); + }, + + insertRows: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + var div = doc.createElement("div"); + div.innerHTML = ""+html+"
      "; + + var tbody = div.firstChild.firstChild; + var parent = before.tagName == "TR" ? before.parentNode : before; + var after = before.tagName == "TR" ? before.nextSibling : null; + + var firstRow = tbody.firstChild, lastRow; + while (tbody.firstChild) + { + lastRow = tbody.firstChild; + if (after) + parent.insertBefore(lastRow, after); + else + parent.appendChild(lastRow); + } + + var offset = 0; + if (before.tagName == "TR") + { + var node = firstRow.parentNode.firstChild; + for (; node && node != firstRow; node = node.nextSibling) + ++offset; + } + + var domArgs = [firstRow, this.tag.context, offset]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + return [firstRow, lastRow]; + }, + + insertBefore: function(args, before, self) + { + return this.insertNode(args, before.ownerDocument, before, false, self); + }, + + insertAfter: function(args, after, self) + { + return this.insertNode(args, after.ownerDocument, after, true, self); + }, + + insertNode: function(args, doc, element, isAfter, self) + { + if (!args) + args = {}; + + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode html: "+html+"\n"); + + var doc = element.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + if (isAfter) + { + while (womb.firstChild) + if (element.nextSibling) + element.parentNode.insertBefore(womb.firstChild, element.nextSibling); + else + element.parentNode.appendChild(womb.firstChild); + } + else + { + while (womb.lastChild) + element.parentNode.insertBefore(womb.lastChild, element); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + /**/ + + /* + insertAfter: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + while (womb.firstChild) + if (before.nextSibling) + before.parentNode.insertBefore(womb.firstChild, before.nextSibling); + else + before.parentNode.appendChild(womb.firstChild); + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), + domArgs); + + return root; + }, + /**/ + + replace: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var root; + if (parent.nodeType == 1) + { + parent.innerHTML = html; + root = parent.firstChild; + } + else + { + if (!parent || parent.nodeType != 9) + parent = document; + + if (!womb || womb.ownerDocument != parent) + womb = parent.createElement("div"); + womb.innerHTML = html; + + root = womb.firstChild; + //womb.removeChild(root); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + + append: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n"); + + if (!womb || womb.ownerDocument != parent.ownerDocument) + womb = parent.ownerDocument.createElement("div"); + womb.innerHTML = html; + + // TODO: xxxpedro domplate port to Firebug + var root = womb.firstChild; + while (womb.firstChild) + parent.appendChild(womb.firstChild); + + // clearing element reference to avoid reference error in IE8 when switching contexts + womb = null; + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + } +}; + +// ************************************************************************************************ + +function defineTags() +{ + for (var i = 0; i < arguments.length; ++i) + { + var tagName = arguments[i]; + var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);"); + fn.DomplateTag = DomplateTag; + + var fnName = tagName.toUpperCase(); + FBL[fnName] = fn; + } +} + +defineTags( + "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr", + "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select", + "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe" +); + +})(); + + +/* See license.txt for terms of usage */ + +var FirebugReps = FBL.ns(function() { with (FBL) { + + +// ************************************************************************************************ +// Common Tags + +var OBJECTBOX = this.OBJECTBOX = + SPAN({"class": "objectBox objectBox-$className"}); + +var OBJECTBLOCK = this.OBJECTBLOCK = + DIV({"class": "objectBox objectBox-$className"}); + +var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation + A({ + "class": "objectLink objectLink-$className a11yFocus", + href: "javascript:void(0)", + _repObject: "$object" + }) + : // Other browsers + A({ + "class": "objectLink objectLink-$className a11yFocus", + _repObject: "$object" + }); + + +// ************************************************************************************************ + +this.Undefined = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("undefined"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "undefined", + + supportsObject: function(object, type) + { + return type == "undefined"; + } +}); + +// ************************************************************************************************ + +this.Null = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("null"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "null", + + supportsObject: function(object, type) + { + return object == null; + } +}); + +// ************************************************************************************************ + +this.Nada = domplate(Firebug.Rep, +{ + tag: SPAN(""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "nada" +}); + +// ************************************************************************************************ + +this.Number = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "number", + + supportsObject: function(object, type) + { + return type == "boolean" || type == "number"; + } +}); + +// ************************************************************************************************ + +this.String = domplate(Firebug.Rep, +{ + tag: OBJECTBOX(""$object""), + + shortTag: OBJECTBOX(""$object|cropString""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "string", + + supportsObject: function(object, type) + { + return type == "string"; + } +}); + +// ************************************************************************************************ + +this.Text = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + shortTag: OBJECTBOX("$object|cropString"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "text" +}); + +// ************************************************************************************************ + +this.Caption = domplate(Firebug.Rep, +{ + tag: SPAN({"class": "caption"}, "$object") +}); + +// ************************************************************************************************ + +this.Warning = domplate(Firebug.Rep, +{ + tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR") +}); + +// ************************************************************************************************ + +this.Func = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("$object|summarizeFunction"), + + summarizeFunction: function(fn) + { + var fnRegex = /function ([^(]+\([^)]*\)) \{/; + var fnText = safeToString(fn); + + var m = fnRegex.exec(fnText); + return m ? m[1] : "function()"; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copySource: function(fn) + { + copyToClipboard(safeToString(fn)); + }, + + monitor: function(fn, script, monitored) + { + if (monitored) + Firebug.Debugger.unmonitorScript(fn, script, "monitor"); + else + Firebug.Debugger.monitorScript(fn, script, "monitor"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "function", + + supportsObject: function(object, type) + { + return isFunction(object); + }, + + inspectObject: function(fn, context) + { + var sourceLink = findSourceForFunction(fn, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + if (FBTrace.DBG_FUNCTION_NAME) + FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink); + }, + + getTooltip: function(fn, context) + { + var script = findScriptForFunctionInContext(context, fn); + if (script) + return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]); + else + if (fn.toString) + return fn.toString(); + }, + + getTitle: function(fn, context) + { + var name = fn.name ? fn.name : "function"; + return name + "()"; + }, + + getContextMenuItems: function(fn, target, context, script) + { + if (!script) + script = findScriptForFunctionInContext(context, fn); + if (!script) + return; + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = script ? getFunctionName(script, context) : fn.name; + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, fn) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); + +// ************************************************************************************************ +/* +this.jsdScript = domplate(Firebug.Rep, +{ + copySource: function(script) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.copySource(fn); + }, + + monitor: function(fn, script, monitored) + { + fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.monitor(fn, script, monitored); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "jsdScript", + inspectable: false, + + supportsObject: function(object, type) + { + return object instanceof jsdIScript; + }, + + inspectObject: function(script, context) + { + var sourceLink = getSourceLinkForScript(script, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + }, + + getRealObject: function(script, context) + { + return script; + }, + + getTooltip: function(script) + { + return $STRF("jsdIScript", [script.tag]); + }, + + getTitle: function(script, context) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.getTitle(fn, context); + }, + + getContextMenuItems: function(script, target, context) + { + var fn = script.functionObject.getWrappedValue(); + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = getFunctionName(script, context); + + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, script) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); +/**/ +//************************************************************************************************ + +this.Obj = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + SPAN({"class": "objectTitle"}, "$object|getTitle "), + + SPAN({"class": "objectProps"}, + SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"), + FOR("prop", "$object|propIterator", + SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"), + SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"), + TAG("$prop.tag", {object: "$prop.object"}), + SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim") + ), + SPAN({"class": "objectRightBrace"}, "}") + ) + ), + + propNumberTag: + SPAN({"class": "objectProp-number"}, "$object"), + + propStringTag: + SPAN({"class": "objectProp-string"}, ""$object""), + + propObjectTag: + SPAN({"class": "objectProp-object"}, "$object"), + + propIterator: function (object) + { + ///Firebug.ObjectShortIteratorMax; + var maxLength = 55; // default max length for long representation + + if (!object) + return []; + + var props = []; + var length = 0; + + var numProperties = 0; + var numPropertiesShown = 0; + var maxLengthReached = false; + + var lib = this; + + var propRepsMap = + { + "boolean": this.propNumberTag, + "number": this.propNumberTag, + "string": this.propStringTag, + "object": this.propObjectTag + }; + + try + { + var title = Firebug.Rep.getTitle(object); + length += title.length; + + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var type = typeof(value); + if (type == "boolean" || + type == "number" || + (type == "string" && value) || + (type == "object" && value && value.toString)) + { + var tag = propRepsMap[type]; + + var value = (type == "object") ? + Firebug.getRep(value).getTitle(value) : + value + ""; + + length += name.length + value.length + 4; + + if (length <= maxLength) + { + props.push({ + tag: tag, + name: name, + object: value, + equal: "=", + delim: ", " + }); + + numPropertiesShown++; + } + else + maxLengthReached = true; + + } + + numProperties++; + + if (maxLengthReached && numProperties > numPropertiesShown) + break; + } + + if (numProperties > numPropertiesShown) + { + props.push({ + object: "...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }); + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + fb_1_6_propIterator: function (object, max) + { + max = max || 3; + if (!object) + return []; + + var props = []; + var len = 0, count = 0; + + try + { + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof(value); + if (t == "boolean" || t == "number" || (t == "string" && value) + || (t == "object" && value && value.toString)) + { + var rep = Firebug.getRep(value); + var tag = rep.shortTag || rep.tag; + if (t == "object") + { + value = rep.getTitle(value); + tag = rep.titleTag; + } + count++; + if (count <= max) + props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "}); + else + break; + } + } + if (count > max) + { + props[Math.max(1,max-1)] = { + object: "more...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }; + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + /* + propIterator: function (object) + { + if (!object) + return []; + + var props = []; + var len = 0; + + try + { + for (var name in object) + { + var val; + try + { + val = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof val; + if (t == "boolean" || t == "number" || (t == "string" && val) + || (t == "object" && !isFunction(val) && val && val.toString)) + { + var title = (t == "object") + ? Firebug.getRep(val).getTitle(val) + : val+""; + + len += name.length + title.length + 1; + if (len < 50) + props.push({name: name, value: title}); + else + break; + } + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + + return props; + }, + /**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object, type) + { + return true; + } +}); + + +// ************************************************************************************************ + +this.Arr = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|arrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + SPAN({"class": "arrayRightBracket", role : "presentation"}, "]") + ), + + shortTag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|shortArrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + // TODO: xxxpedro - confirm this on Firebug + //FOR("prop", "$object|shortPropIterator", + // " $prop.name=", + // SPAN({"class": "objectPropValue"}, "$prop.value|cropString") + //), + SPAN({"class": "arrayRightBracket"}, "]") + ), + + arrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + return items; + }, + + shortArrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length && i < 3; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + if (array.length > 3) + items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""}); + + return items; + }, + + shortPropIterator: this.Obj.propIterator, + + getItemIndex: function(child) + { + var arrayIndex = 0; + for (child = child.previousSibling; child; child = child.previousSibling) + { + if (child.repObject) + ++arrayIndex; + } + return arrayIndex; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "array", + + supportsObject: function(object) + { + return this.isArray(object); + }, + + // http://code.google.com/p/fbug/issues/detail?id=874 + // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007 + isArray: function(obj) { + try { + if (!obj) + return false; + else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8) + return true; + else if (isFinite(obj.length) && isFunction(obj.splice)) + return true; + else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments + return true; + else if (instanceOf(obj, "HTMLCollection")) + return true; + else if (instanceOf(obj, "NodeList")) + return true; + else + return false; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */ + FBTrace.sysout("isArray Fails on obj", obj); + } + } + + return false; + }, + // END Yahoo BSD SOURCE See license below. + + getTitle: function(object, context) + { + return "[" + object.length + "]"; + } +}); + +// ************************************************************************************************ + +this.Property = domplate(Firebug.Rep, +{ + supportsObject: function(object) + { + return object instanceof Property; + }, + + getRealObject: function(prop, context) + { + return prop.object[prop.name]; + }, + + getTitle: function(prop, context) + { + return prop.name; + } +}); + +// ************************************************************************************************ + +this.NetFile = domplate(this.Obj, +{ + supportsObject: function(object) + { + return object instanceof Firebug.NetFile; + }, + + browseObject: function(file, context) + { + openNewTab(file.href); + return true; + }, + + getRealObject: function(file, context) + { + return null; + } +}); + +// ************************************************************************************************ + +this.Except = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, "$object.message"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "exception", + + supportsObject: function(object) + { + return object instanceof ErrorCopy; + } +}); + + +// ************************************************************************************************ + +this.Element = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), + FOR("attr", "$object|attrIterator", + " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ + ), + ">" + ), + + shortTag: + OBJECTLINK( + SPAN({"class": "$object|getVisible"}, + SPAN({"class": "selectorTag"}, "$object|getSelectorTag"), + SPAN({"class": "selectorId"}, "$object|getSelectorId"), + SPAN({"class": "selectorClass"}, "$object|getSelectorClass"), + SPAN({"class": "selectorValue"}, "$object|getValue") + ) + ), + + getVisible: function(elt) + { + return isVisible(elt) ? "" : "selectorHidden"; + }, + + getSelectorTag: function(elt) + { + return elt.nodeName.toLowerCase(); + }, + + getSelectorId: function(elt) + { + return elt.id ? "#" + elt.id : ""; + }, + + getSelectorClass: function(elt) + { + return elt.className ? "." + elt.className.split(" ")[0] : ""; + }, + + getValue: function(elt) + { + // TODO: xxxpedro + return ""; + var value; + if (elt instanceof HTMLImageElement) + value = getFileName(elt.src); + else if (elt instanceof HTMLAnchorElement) + value = getFileName(elt.href); + else if (elt instanceof HTMLInputElement) + value = elt.value; + else if (elt instanceof HTMLFormElement) + value = getFileName(elt.action); + else if (elt instanceof HTMLScriptElement) + value = getFileName(elt.src); + + return value ? " " + cropString(value, 20) : ""; + }, + + attrIterator: function(elt) + { + var attrs = []; + var idAttr, classAttr; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName && attr.nodeName.indexOf("firebug-") != -1) + continue; + else if (attr.nodeName == "id") + idAttr = attr; + else if (attr.nodeName == "class") + classAttr = attr; + else + attrs.push(attr); + } + } + if (classAttr) + attrs.splice(0, 0, classAttr); + if (idAttr) + attrs.splice(0, 0, idAttr); + + return attrs; + }, + + shortAttrIterator: function(elt) + { + var attrs = []; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName == "id" || attr.nodeName == "class") + attrs.push(attr); + } + } + + return attrs; + }, + + getHidden: function(elt) + { + return isVisible(elt) ? "" : "nodeHidden"; + }, + + getXPath: function(elt) + { + return getElementTreeXPath(elt); + }, + + // TODO: xxxpedro remove this? + getNodeText: function(element) + { + var text = element.textContent; + if (Firebug.showFullTextNodes) + return text; + else + return cropString(text, 50); + }, + /**/ + + getNodeTextGroups: function(element) + { + var text = element.textContent; + if (!Firebug.showFullTextNodes) + { + text=cropString(text,50); + } + + var escapeGroups=[]; + + if (Firebug.showTextNodesWithWhitespace) + escapeGroups.push({ + 'group': 'whitespace', + 'class': 'nodeWhiteSpace', + 'extra': { + '\t': '_Tab', + '\n': '_Para', + ' ' : '_Space' + } + }); + if (Firebug.showTextNodesWithEntities) + escapeGroups.push({ + 'group':'text', + 'class':'nodeTextEntity', + 'extra':{} + }); + + if (escapeGroups.length) + return escapeGroupsForEntities(text, escapeGroups); + else + return [{str:text,'class':'',extra:''}]; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyHTML: function(elt) + { + var html = getElementXML(elt); + copyToClipboard(html); + }, + + copyInnerHTML: function(elt) + { + copyToClipboard(elt.innerHTML); + }, + + copyXPath: function(elt) + { + var xpath = getElementXPath(elt); + copyToClipboard(xpath); + }, + + persistor: function(context, xpath) + { + var elts = xpath + ? getElementsByXPath(context.window.document, xpath) + : null; + + return elts && elts.length ? elts[0] : null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "element", + + supportsObject: function(object) + { + //return object instanceof Element || object.nodeType == 1 && typeof object.nodeName == "string"; + return instanceOf(object, "Element"); + }, + + browseObject: function(elt, context) + { + var tag = elt.nodeName.toLowerCase(); + if (tag == "script") + openNewTab(elt.src); + else if (tag == "link") + openNewTab(elt.href); + else if (tag == "a") + openNewTab(elt.href); + else if (tag == "img") + openNewTab(elt.src); + + return true; + }, + + persistObject: function(elt, context) + { + var xpath = getElementXPath(elt); + + return bind(this.persistor, top, xpath); + }, + + getTitle: function(element, context) + { + return getElementCSSSelector(element); + }, + + getTooltip: function(elt) + { + return this.getXPath(elt); + }, + + getContextMenuItems: function(elt, target, context) + { + var monitored = areEventsMonitored(elt, null, context); + + return [ + {label: "CopyHTML", command: bindFixed(this.copyHTML, this, elt) }, + {label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) }, + {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) }, + "-", + {label: "ShowEventsInConsole", type: "checkbox", checked: monitored, + command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) }, + "-", + {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) } + ]; + } +}); + +// ************************************************************************************************ + +this.TextNode = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "TextNode"), + " textContent="", SPAN({"class": "nodeValue"}, "$object.textContent|cropString"), """, + ">" + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "textNode", + + supportsObject: function(object) + { + return object instanceof Text; + } +}); + +// ************************************************************************************************ + +this.Document = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(doc) + { + return doc.location ? getFileName(doc.location.href) : ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Document || object instanceof XMLDocument; + return instanceOf(object, "Document"); + }, + + browseObject: function(doc, context) + { + openNewTab(doc.location.href); + return true; + }, + + persistObject: function(doc, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window.document; + }, + + getTitle: function(win, context) + { + return "document"; + }, + + getTooltip: function(doc) + { + return doc.location.href; + } +}); + +// ************************************************************************************************ + +this.StyleSheet = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(styleSheet) + { + return getFileName(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(styleSheet) + { + copyToClipboard(styleSheet.href); + }, + + openInTab: function(styleSheet) + { + openNewTab(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof CSSStyleSheet; + return instanceOf(object, "CSSStyleSheet"); + }, + + browseObject: function(styleSheet, context) + { + openNewTab(styleSheet.href); + return true; + }, + + persistObject: function(styleSheet, context) + { + return bind(this.persistor, top, styleSheet.href); + }, + + getTooltip: function(styleSheet) + { + return styleSheet.href; + }, + + getContextMenuItems: function(styleSheet, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) } + ]; + }, + + persistor: function(context, href) + { + return getStyleSheetByHref(href, context); + } +}); + +// ************************************************************************************************ + +this.Window = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(win) + { + try + { + return (win && win.location && !win.closed) ? getFileName(win.location.href) : ""; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.Window window closed?"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + return instanceOf(object, "Window"); + }, + + browseObject: function(win, context) + { + openNewTab(win.location.href); + return true; + }, + + persistObject: function(win, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window; + }, + + getTitle: function(win, context) + { + return "window"; + }, + + getTooltip: function(win) + { + if (win && !win.closed) + return win.location.href; + } +}); + +// ************************************************************************************************ + +this.Event = domplate(Firebug.Rep, +{ + tag: TAG("$copyEventTag", {object: "$object|copyEvent"}), + + copyEventTag: + OBJECTLINK("$object|summarizeEvent"), + + summarizeEvent: function(event) + { + var info = [event.type, ' ']; + + var eventFamily = getEventFamily(event.type); + if (eventFamily == "mouse") + info.push("clientX=", event.clientX, ", clientY=", event.clientY); + else if (eventFamily == "key") + info.push("charCode=", event.charCode, ", keyCode=", event.keyCode); + + return info.join(""); + }, + + copyEvent: function(event) + { + return new EventCopy(event); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Event || object instanceof EventCopy; + return instanceOf(object, "Event") || instanceOf(object, "EventCopy"); + }, + + getTitle: function(event, context) + { + return "Event " + event.type; + } +}); + +// ************************************************************************************************ + +this.SourceLink = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + hideSourceLink: function(sourceLink) + { + return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true; + }, + + getSourceLinkTitle: function(sourceLink) + { + if (!sourceLink) + return ""; + + try + { + var fileName = getFileName(sourceLink.href); + fileName = decodeURIComponent(fileName); + fileName = cropString(fileName, 17); + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'"+fileName+"\': "+exc, exc); + } + + return typeof sourceLink.line == "number" ? + fileName + " (line " + sourceLink.line + ")" : + fileName; + + // TODO: xxxpedro + //return $STRF("Line", [fileName, sourceLink.line]); + }, + + copyLink: function(sourceLink) + { + copyToClipboard(sourceLink.href); + }, + + openInTab: function(sourceLink) + { + openNewTab(sourceLink.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceLink", + + supportsObject: function(object) + { + return object instanceof SourceLink; + }, + + getTooltip: function(sourceLink) + { + return decodeURI(sourceLink.href); + }, + + inspectObject: function(sourceLink, context) + { + if (sourceLink.type == "js") + { + var scriptFile = getSourceFileByHref(sourceLink.href, context); + if (scriptFile) + return Firebug.chrome.select(sourceLink); + } + else if (sourceLink.type == "css") + { + // If an object is defined, treat it as the highest priority for + // inspect actions + if (sourceLink.object) { + Firebug.chrome.select(sourceLink.object); + return; + } + + var stylesheet = getStyleSheetByHref(sourceLink.href, context); + if (stylesheet) + { + var ownerNode = stylesheet.ownerNode; + if (ownerNode) + { + Firebug.chrome.select(sourceLink, "html"); + return; + } + + var panel = context.getPanel("stylesheet"); + if (panel && panel.getRuleByLine(stylesheet, sourceLink.line)) + return Firebug.chrome.select(sourceLink); + } + } + + // Fallback is to just open the view-source window on the file + viewSource(sourceLink.href, sourceLink.line); + }, + + browseObject: function(sourceLink, context) + { + openNewTab(sourceLink.href); + return true; + }, + + getContextMenuItems: function(sourceLink, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceFile = domplate(this.SourceLink, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + persistor: function(context, href) + { + return getSourceFileByHref(href, context); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceFile", + + supportsObject: function(object) + { + return object instanceof SourceFile; + }, + + persistObject: function(sourceFile) + { + return bind(this.persistor, top, sourceFile.href); + }, + + browseObject: function(sourceLink, context) + { + }, + + getTooltip: function(sourceFile) + { + return sourceFile.href; + } +}); + +// ************************************************************************************************ + +this.StackFrame = domplate(Firebug.Rep, // XXXjjb Since the repObject is fn the stack does not have correct line numbers +{ + tag: + OBJECTBLOCK( + A({"class": "objectLink objectLink-function focusRow a11yFocus", _repObject: "$object.fn"}, "$object|getCallName"), + " ( ", + FOR("arg", "$object|argIterator", + TAG("$arg.tag", {object: "$arg.value"}), + SPAN({"class": "arrayComma"}, "$arg.delim") + ), + " )", + SPAN({"class": "objectLink-sourceLink objectLink"}, "$object|getSourceLinkTitle") + ), + + getCallName: function(frame) + { + //TODO: xxxpedro reps StackFrame + return frame.name || "anonymous"; + + //return getFunctionName(frame.script, frame.context); + }, + + getSourceLinkTitle: function(frame) + { + //TODO: xxxpedro reps StackFrame + var fileName = cropString(getFileName(frame.href), 20); + return fileName + (frame.lineNo ? " (line " + frame.lineNo + ")" : ""); + + var fileName = cropString(getFileName(frame.href), 17); + return $STRF("Line", [fileName, frame.lineNo]); + }, + + argIterator: function(frame) + { + if (!frame.args) + return []; + + var items = []; + + for (var i = 0; i < frame.args.length; ++i) + { + var arg = frame.args[i]; + + if (!arg) + break; + + var rep = Firebug.getRep(arg.value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var delim = (i == frame.args.length-1 ? "" : ", "); + + items.push({name: arg.name, value: arg.value, tag: tag, delim: delim}); + } + + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackFrame", + + supportsObject: function(object) + { + return object instanceof StackFrame; + }, + + inspectObject: function(stackFrame, context) + { + var sourceLink = new SourceLink(stackFrame.href, stackFrame.lineNo, "js"); + Firebug.chrome.select(sourceLink); + }, + + getTooltip: function(stackFrame, context) + { + return $STRF("Line", [stackFrame.href, stackFrame.lineNo]); + } + +}); + +// ************************************************************************************************ + +this.StackTrace = domplate(Firebug.Rep, +{ + tag: + FOR("frame", "$object.frames focusRow", + TAG(this.StackFrame.tag, {object: "$frame"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackTrace", + + supportsObject: function(object) + { + return object instanceof StackTrace; + } +}); + +// ************************************************************************************************ + +this.jsdStackFrame = domplate(Firebug.Rep, +{ + inspectable: false, + + supportsObject: function(object) + { + return (object instanceof jsdIStackFrame) && (object.isValid); + }, + + getTitle: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + return getFunctionName(frame.script, context); + }, + + getTooltip: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + var sourceInfo = FBL.getSourceFileAndLineByScript(context, frame.script, frame); + if (sourceInfo) + return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]); + else + return $STRF("Line", [frame.script.fileName, frame.line]); + }, + + getContextMenuItems: function(frame, target, context) + { + var fn = frame.script.functionObject.getWrappedValue(); + return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script); + } +}); + +// ************************************************************************************************ + +this.ErrorMessage = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({ + $hasTwisty: "$object|hasStackTrace", + $hasBreakSwitch: "$object|hasBreakSwitch", + $breakForError: "$object|hasErrorBreak", + _repObject: "$object", + _stackTrace: "$object|getLastErrorStackTrace", + onclick: "$onToggleError"}, + + DIV({"class": "errorTitle a11yFocus", role : 'checkbox', 'aria-checked' : 'false'}, + "$object.message|getMessage" + ), + DIV({"class": "errorTrace"}), + DIV({"class": "errorSourceBox errorSource-$object|getSourceType"}, + IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':'false', title: "Break on this error"}), + A({"class": "errorSource a11yFocus"}, "$object|getLine") + ), + TAG(this.SourceLink.tag, {object: "$object|getSourceLink"}) + ), + + getLastErrorStackTrace: function(error) + { + return error.trace; + }, + + hasStackTrace: function(error) + { + var url = error.href.toString(); + var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1); + return !fromCommandLine && error.trace; + }, + + hasBreakSwitch: function(error) + { + return error.href && error.lineNo > 0; + }, + + hasErrorBreak: function(error) + { + return fbs.hasErrorBreakpoint(error.href, error.lineNo); + }, + + getMessage: function(message) + { + var re = /\[Exception... "(.*?)" nsresult:/; + var m = re.exec(message); + return m ? m[1] : message; + }, + + getLine: function(error) + { + if (error.category == "js") + { + if (error.source) + return cropString(error.source, 80); + else if (error.href && error.href.indexOf("XPCSafeJSObjectWrapper") == -1) + return cropString(error.getSourceLine(), 80); + } + }, + + getSourceLink: function(error) + { + var ext = error.category == "css" ? "css" : "js"; + return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null; + }, + + getSourceType: function(error) + { + // Errors occurring inside of HTML event handlers look like "foo.html (line 1)" + // so let's try to skip those + if (error.source) + return "syntax"; + else if (error.lineNo == 1 && getFileExtension(error.href) != "js") + return "none"; + else if (error.category == "css") + return "none"; + else if (!error.href || !error.lineNo) + return "none"; + else + return "exec"; + }, + + onToggleError: function(event) + { + var target = event.currentTarget; + if (hasClass(event.target, "errorBreak")) + { + this.breakOnThisError(target.repObject); + } + else if (hasClass(event.target, "errorSource")) + { + var panel = Firebug.getElementPanel(event.target); + this.inspectObject(target.repObject, panel.context); + } + else if (hasClass(event.target, "errorTitle")) + { + var traceBox = target.childNodes[1]; + toggleClass(target, "opened"); + event.target.setAttribute('aria-checked', hasClass(target, "opened")); + if (hasClass(target, "opened")) + { + if (target.stackTrace) + var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox); + if (Firebug.A11yModel.enabled) + { + var panel = Firebug.getElementPanel(event.target); + dispatch([Firebug.A11yModel], "onLogRowContentCreated", [panel , traceBox]); + } + } + else + clearNode(traceBox); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyError: function(error) + { + var message = [ + this.getMessage(error.message), + error.href, + "Line " + error.lineNo + ]; + copyToClipboard(message.join("\n")); + }, + + breakOnThisError: function(error) + { + if (this.hasErrorBreak(error)) + Firebug.Debugger.clearErrorBreakpoint(error.href, error.lineNo); + else + Firebug.Debugger.setErrorBreakpoint(error.href, error.lineNo); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "errorMessage", + inspectable: false, + + supportsObject: function(object) + { + return object instanceof ErrorMessage; + }, + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + FirebugReps.SourceLink.inspectObject(sourceLink, context); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + var items = [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) } + ]; + + if (error.category == "css") + { + items.push( + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + + optionMenu("BreakOnAllErrors", "breakOnErrors") + ); + } + + return items; + } +}); + +// ************************************************************************************************ + +this.Assert = domplate(Firebug.Rep, +{ + tag: + DIV( + DIV({"class": "errorTitle"}), + DIV({"class": "assertDescription"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "assert", + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + Firebug.chrome.select(sourceLink); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + return [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) }, + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors, + command: bindFixed(this.breakOnAllErrors, this, error) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceText = domplate(Firebug.Rep, +{ + tag: + DIV( + FOR("line", "$object|lineIterator", + DIV({"class": "sourceRow", role : "presentation"}, + SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"), + SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text") + ) + ) + ), + + lineIterator: function(sourceText) + { + var maxLineNoChars = (sourceText.lines.length + "").length; + var list = []; + + for (var i = 0; i < sourceText.lines.length; ++i) + { + // Make sure all line numbers are the same width (with a fixed-width font) + var lineNo = (i+1) + ""; + while (lineNo.length < maxLineNoChars) + lineNo = " " + lineNo; + + list.push({lineNo: lineNo, text: sourceText.lines[i]}); + } + + return list; + }, + + getHTML: function(sourceText) + { + return getSourceLineRange(sourceText, 1, sourceText.lines.length); + } +}); + +//************************************************************************************************ +this.nsIDOMHistory = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showHistory"}, + OBJECTLINK("$object|summarizeHistory") + ), + + className: "nsIDOMHistory", + + summarizeHistory: function(history) + { + try + { + var items = history.length; + return items + " history entries"; + } + catch(exc) + { + return "object does not support history (nsIDOMHistory)"; + } + }, + + showHistory: function(history) + { + try + { + var items = history.length; // if this throws, then unsupported + Firebug.chrome.select(history); + } + catch (exc) + { + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object, type) + { + return (object instanceof Ci.nsIDOMHistory); + } +}); + +// ************************************************************************************************ +this.ApplicationCache = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showApplicationCache"}, + OBJECTLINK("$object|summarizeCache") + ), + + summarizeCache: function(applicationCache) + { + try + { + return applicationCache.length + " items in offline cache"; + } + catch(exc) + { + return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264"; + } + }, + + showApplicationCache: function(event) + { + openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "applicationCache", + + supportsObject: function(object, type) + { + if (Ci.nsIDOMOfflineResourceList) + return (object instanceof Ci.nsIDOMOfflineResourceList); + } + +}); + +this.Storage = domplate(Firebug.Rep, +{ + tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")), + + summarize: function(storage) + { + return storage.length +" items in Storage"; + }, + show: function(storage) + { + openNewTab("http://dev.w3.org/html5/webstorage/#storage-0"); + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "Storage", + + supportsObject: function(object, type) + { + return (object instanceof Storage); + } + +}); + +// ************************************************************************************************ +Firebug.registerRep( + //this.nsIDOMHistory, // make this early to avoid exceptions + this.Undefined, + this.Null, + this.Number, + this.String, + this.Window, + //this.ApplicationCache, // must come before Arr (array) else exceptions. + //this.ErrorMessage, + this.Element, + //this.TextNode, + this.Document, + this.StyleSheet, + this.Event, + //this.SourceLink, + //this.SourceFile, + //this.StackTrace, + //this.StackFrame, + //this.jsdStackFrame, + //this.jsdScript, + //this.NetFile, + this.Property, + this.Except, + this.Arr +); + +Firebug.setDefaultReps(this.Func, this.Obj); + +}}); + +// ************************************************************************************************ +/* + * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source" + * in only this file reps.js. John J. Barton June 2007. + * +Software License Agreement (BSD License) + +Copyright (c) 2006, Yahoo! Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Yahoo! Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Yahoo! Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * / + */ + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var saveTimeout = 400; +var pageAmount = 10; + +// ************************************************************************************************ +// Globals + +var currentTarget = null; +var currentGroup = null; +var currentPanel = null; +var currentEditor = null; + +var defaultEditor = null; + +var originalClassName = null; + +var originalValue = null; +var defaultValue = null; +var previousValue = null; + +var invalidEditor = false; +var ignoreNextInput = false; + +// ************************************************************************************************ + +Firebug.Editor = extend(Firebug.Module, +{ + supportsStopEvent: true, + + dispatchName: "editor", + tabCharacter: " ", + + startEditing: function(target, value, editor) + { + this.stopEditing(); + + if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter")) + return; + + var panel = Firebug.getElementPanel(target); + if (!panel.editable) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.startEditing " + value, target); + + defaultValue = target.getAttribute("defaultValue"); + if (value == undefined) + { + var textContent = isIE ? "innerText" : "textContent"; + value = target[textContent]; + if (value == defaultValue) + value = ""; + } + + originalValue = previousValue = value; + + invalidEditor = false; + currentTarget = target; + currentPanel = panel; + currentGroup = getAncestorByClass(target, "editGroup"); + + currentPanel.editing = true; + + var panelEditor = currentPanel.getEditor(target, value); + currentEditor = editor ? editor : panelEditor; + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + var inlineParent = getInlineParent(target); + var targetSize = getOffsetSize(inlineParent); + + setClass(panel.panelNode, "editing"); + setClass(target, "editing"); + if (currentGroup) + setClass(currentGroup, "editing"); + + currentEditor.show(target, currentPanel, value, targetSize); + //dispatch(this.fbListeners, "onBeginEditing", [currentPanel, currentEditor, target, value]); + currentEditor.beginEditing(target, value); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Editor start panel "+currentPanel.name); + this.attachListeners(currentEditor, panel.context); + }, + + stopEditing: function(cancel) + { + if (!currentTarget) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.stopEditing cancel:" + cancel+" saveTimeout: "+this.saveTimeout); + + clearTimeout(this.saveTimeout); + delete this.saveTimeout; + + this.detachListeners(currentEditor, currentPanel.context); + + removeClass(currentPanel.panelNode, "editing"); + removeClass(currentTarget, "editing"); + if (currentGroup) + removeClass(currentGroup, "editing"); + + var value = currentEditor.getValue(); + if (value == defaultValue) + value = ""; + + var removeGroup = currentEditor.endEditing(currentTarget, value, cancel); + + try + { + if (cancel) + { + //dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, removeGroup && !originalValue]); + if (value != originalValue) + this.saveEditAndNotifyListeners(currentTarget, originalValue, previousValue); + + if (removeGroup && !originalValue && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else if (!value) + { + this.saveEditAndNotifyListeners(currentTarget, null, previousValue); + + if (removeGroup && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else + this.save(value); + } + catch (exc) + { + //throw exc.message; + //ERROR(exc); + } + + currentEditor.hide(); + currentPanel.editing = false; + + //dispatch(this.fbListeners, "onStopEdit", [currentPanel, currentEditor, currentTarget]); + //if (FBTrace.DBG_EDITOR) + // FBTrace.sysout("Editor stop panel "+currentPanel.name); + + currentTarget = null; + currentGroup = null; + currentPanel = null; + currentEditor = null; + originalValue = null; + invalidEditor = false; + + return value; + }, + + cancelEditing: function() + { + return this.stopEditing(true); + }, + + update: function(saveNow) + { + if (this.saveTimeout) + clearTimeout(this.saveTimeout); + + invalidEditor = true; + + currentEditor.layout(); + + if (saveNow) + this.save(); + else + { + var context = currentPanel.context; + this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.update saveTimeout: "+this.saveTimeout); + } + }, + + save: function(value) + { + if (!invalidEditor) + return; + + if (value == undefined) + value = currentEditor.getValue(); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.save saveTimeout: "+this.saveTimeout+" currentPanel: "+(currentPanel?currentPanel.name:"null")); + try + { + this.saveEditAndNotifyListeners(currentTarget, value, previousValue); + + previousValue = value; + invalidEditor = false; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("editor.save FAILS "+exc, exc); + } + }, + + saveEditAndNotifyListeners: function(currentTarget, value, previousValue) + { + currentEditor.saveEdit(currentTarget, value, previousValue); + //dispatch(this.fbListeners, "onSaveEdit", [currentPanel, currentEditor, currentTarget, value, previousValue]); + }, + + setEditTarget: function(element) + { + if (!element) + { + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, true]); + this.stopEditing(); + } + else if (hasClass(element, "insertBefore")) + this.insertRow(element, "before"); + else if (hasClass(element, "insertAfter")) + this.insertRow(element, "after"); + else + this.startEditing(element); + }, + + tabNextEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var nextEditable = currentTarget; + do + { + nextEditable = !value && currentGroup + ? getNextOutsider(nextEditable, currentGroup) + : getNextByClass(nextEditable, "editable"); + } + while (nextEditable && !nextEditable.offsetHeight); + + this.setEditTarget(nextEditable); + }, + + tabPreviousEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var prevEditable = currentTarget; + do + { + prevEditable = !value && currentGroup + ? getPreviousOutsider(prevEditable, currentGroup) + : getPreviousByClass(prevEditable, "editable"); + } + while (prevEditable && !prevEditable.offsetHeight); + + this.setEditTarget(prevEditable); + }, + + insertRow: function(relative, insertWhere) + { + var group = + relative || getAncestorByClass(currentTarget, "editGroup") || currentTarget; + var value = this.stopEditing(); + + currentPanel = Firebug.getElementPanel(group); + + currentEditor = currentPanel.getEditor(group, value); + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + currentGroup = currentEditor.insertNewRow(group, insertWhere); + if (!currentGroup) + return; + + var editable = hasClass(currentGroup, "editable") + ? currentGroup + : getNextByClass(currentGroup, "editable"); + + if (editable) + this.setEditTarget(editable); + }, + + insertRowForObject: function(relative) + { + var container = getAncestorByClass(relative, "insertInto"); + if (container) + { + relative = getChildByClass(container, "insertBefore"); + if (relative) + this.insertRow(relative, "before"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + attachListeners: function(editor, context) + { + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + addEvent(win, "resize", this.onResize); + addEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + + this.listeners = [ + chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this)) + ]; + + if (editor.arrowCompletion) + { + this.listeners.push( + chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)), + chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)), + chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)), + chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount)) + ); + } + + if (currentEditor.tabNavigation) + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")), + chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this)) + ); + } + else if (currentEditor.multiLine) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, insertTab) + ); + } + else + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this)) + ); + + if (currentEditor.tabCompletion) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)), + chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1)) + ); + } + } + }, + + detachListeners: function(editor, context) + { + if (!this.listeners) + return; + + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + removeEvent(win, "resize", this.onResize); + removeEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + if (chrome) + { + for (var i = 0; i < this.listeners.length; ++i) + chrome.keyIgnore(this.listeners[i]); + } + + delete this.listeners; + }, + + onResize: function(event) + { + currentEditor.layout(true); + }, + + onBlur: function(event) + { + if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box)) + this.stopEditing(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + Firebug.Module.initialize.apply(this, arguments); + + this.onResize = bindFixed(this.onResize, this); + this.onBlur = bind(this.onBlur, this); + }, + + disable: function() + { + this.stopEditing(); + }, + + showContext: function(browser, context) + { + this.stopEditing(); + }, + + showPanel: function(browser, panel) + { + this.stopEditing(); + } +}); + +// ************************************************************************************************ +// BaseEditor + +Firebug.BaseEditor = extend(Firebug.MeasureBox, +{ + getValue: function() + { + }, + + setValue: function(value) + { + }, + + show: function(target, panel, value, textSize, targetSize) + { + }, + + hide: function() + { + }, + + layout: function(forceAll) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for context menus within inline editors. + + getContextMenuItems: function(target) + { + var items = []; + items.push({label: "Cut", commandID: "cmd_cut"}); + items.push({label: "Copy", commandID: "cmd_copy"}); + items.push({label: "Paste", commandID: "cmd_paste"}); + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Editor Module listeners will get "onBeginEditing" just before this call + + beginEditing: function(target, value) + { + }, + + // Editor Module listeners will get "onSaveEdit" just after this call + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + } +}); + +// ************************************************************************************************ +// InlineEditor + +// basic inline editor attributes +var inlineEditorAttributes = { + "class": "textEditorInner", + + type: "text", + spellcheck: "false", + + onkeypress: "$onKeyPress", + + onoverflow: "$onOverflow", + oncontextmenu: "$onContextMenu" +}; + +// IE does not support the oninput event, so we're using the onkeydown to signalize +// the relevant keyboard events, and the onpropertychange to actually handle the +// input event, which should happen after the onkeydown event is fired and after the +// value of the input is updated, but before the onkeyup and before the input (with the +// new value) is rendered +if (isIE) +{ + inlineEditorAttributes.onpropertychange = "$onInput"; + inlineEditorAttributes.onkeydown = "$onKeyDown"; +} +// for other browsers we use the oninput event +else +{ + inlineEditorAttributes.oninput = "$onInput"; +} + +Firebug.InlineEditor = function(doc) +{ + this.initializeInline(doc); +}; + +Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor, +{ + enterOnBlur: true, + outerMargin: 8, + shadowExpand: 7, + + tag: + DIV({"class": "inlineEditor"}, + DIV({"class": "textEditorTop1"}, + DIV({"class": "textEditorTop2"}) + ), + DIV({"class": "textEditorInner1"}, + DIV({"class": "textEditorInner2"}, + INPUT( + inlineEditorAttributes + ) + ) + ), + DIV({"class": "textEditorBottom1"}, + DIV({"class": "textEditorBottom2"}) + ) + ), + + inputTag : + INPUT({"class": "textEditorInner", type: "text", + /*oninput: "$onInput",*/ onkeypress: "$onKeyPress", onoverflow: "$onOverflow"} + ), + + expanderTag: + IMG({"class": "inlineExpander", src: "blank.gif"}), + + initialize: function() + { + this.fixedWidth = false; + this.completeAsYouType = true; + this.tabNavigation = true; + this.multiLine = false; + this.tabCompletion = false; + this.arrowCompletion = true; + this.noWrap = true; + this.numeric = false; + }, + + destroy: function() + { + this.destroyInput(); + }, + + initializeInline: function(doc) + { + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Firebug.InlineEditor initializeInline()"); + + //this.box = this.tag.replace({}, doc, this); + this.box = this.tag.append({}, doc.body, this); + + //this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required + this.input = this.box.getElementsByTagName("input")[0]; + + if (isIElt8) + { + this.input.style.top = "-8px"; + } + + this.expander = this.expanderTag.replace({}, doc, this); + this.initialize(); + }, + + destroyInput: function() + { + // XXXjoe Need to remove input/keypress handlers to avoid leaks + }, + + getValue: function() + { + return this.input.value; + }, + + setValue: function(value) + { + // It's only a one-line editor, so new lines shouldn't be allowed + return this.input.value = stripNewLines(value); + }, + + show: function(target, panel, value, targetSize) + { + //dispatch([Firebug.A11yModel], "onInlineEditorShow", [panel, this]); + this.target = target; + this.panel = panel; + + this.targetSize = targetSize; + + // TODO: xxxpedro editor + //this.targetOffset = getClientOffset(target); + + // Some browsers (IE, Google Chrome and Safari) will have problem trying to get the + // offset values of invisible elements, or empty elements. So, in order to get the + // correct values, we temporary inject a character in the innerHTML of the empty element, + // then we get the offset values, and next, we restore the original innerHTML value. + var innerHTML = target.innerHTML; + var isEmptyElement = !innerHTML; + if (isEmptyElement) + target.innerHTML = "."; + + // Get the position of the target element (that is about to be edited) + this.targetOffset = + { + x: target.offsetLeft, + y: target.offsetTop + }; + + // Restore the original innerHTML value of the empty element + if (isEmptyElement) + target.innerHTML = innerHTML; + + this.originalClassName = this.box.className; + + var classNames = target.className.split(" "); + for (var i = 0; i < classNames.length; ++i) + setClass(this.box, "editor-" + classNames[i]); + + // Make the editor match the target's font style + copyTextStyles(target, this.box); + + this.setValue(value); + + if (this.fixedWidth) + this.updateLayout(true); + else + { + this.startMeasuring(target); + this.textSize = this.measureInputText(value); + + // Correct the height of the box to make the funky CSS drop-shadow line up + var parent = this.input.parentNode; + if (hasClass(parent, "textEditorInner2")) + { + var yDiff = this.textSize.height - this.shadowExpand; + + // IE6 height offset + if (isIE6) + yDiff -= 2; + + parent.style.height = yDiff + "px"; + parent.parentNode.style.height = yDiff + "px"; + } + + this.updateLayout(true); + } + + this.getAutoCompleter().reset(); + + if (isIElt8) + panel.panelNode.appendChild(this.box); + else + target.offsetParent.appendChild(this.box); + + //console.log(target); + //this.input.select(); // it's called bellow, with setTimeout + + if (isIE) + { + // reset input style + this.input.style.fontFamily = "Monospace"; + this.input.style.fontSize = "11px"; + } + + // Insert the "expander" to cover the target element with white space + if (!this.fixedWidth) + { + copyBoxStyles(target, this.expander); + + target.parentNode.replaceChild(this.expander, target); + collapse(target, true); + this.expander.parentNode.insertBefore(target, this.expander); + } + + //TODO: xxxpedro + //scrollIntoCenterView(this.box, null, true); + + // Display the editor after change its size and position to avoid flickering + this.box.style.display = "block"; + + // we need to call input.focus() and input.select() with a timeout, + // otherwise it won't work on all browsers due to timing issues + var self = this; + setTimeout(function(){ + self.input.focus(); + self.input.select(); + },0); + }, + + hide: function() + { + this.box.className = this.originalClassName; + + if (!this.fixedWidth) + { + this.stopMeasuring(); + + collapse(this.target, false); + + if (this.expander.parentNode) + this.expander.parentNode.removeChild(this.expander); + } + + if (this.box.parentNode) + { + ///setSelectionRange(this.input, 0, 0); + this.input.blur(); + + this.box.parentNode.removeChild(this.box); + } + + delete this.target; + delete this.panel; + }, + + layout: function(forceAll) + { + if (!this.fixedWidth) + this.textSize = this.measureInputText(this.input.value); + + if (forceAll) + this.targetOffset = getClientOffset(this.expander); + + this.updateLayout(false, forceAll); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + beginEditing: function(target, value) + { + }, + + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + }, + + advanceToNext: function(target, charCode) + { + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleter: function() + { + if (!this.autoCompleter) + { + this.autoCompleter = new Firebug.AutoCompleter(null, + bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this), + true, false); + } + + return this.autoCompleter; + }, + + completeValue: function(amt) + { + //console.log("completeValue"); + + var selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0); + + if (selectRangeCallback) + { + Firebug.Editor.update(true); + + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + else + this.incrementValue(amt); + }, + + incrementValue: function(amt) + { + var value = this.input.value; + + // TODO: xxxpedro editor + if (isIE) + var start = getInputSelectionStart(this.input), end = start; + else + var start = this.input.selectionStart, end = this.input.selectionEnd; + + //debugger; + var range = this.getAutoCompleteRange(value, start); + if (!range || range.type != "int") + range = {start: 0, end: value.length-1}; + + var expr = value.substr(range.start, range.end-range.start+1); + preExpr = value.substr(0, range.start); + postExpr = value.substr(range.end+1); + + // See if the value is an integer, and if so increment it + var intValue = parseInt(expr); + if (!!intValue || intValue == 0) + { + var m = /\d+/.exec(expr); + var digitPost = expr.substr(m.index+m[0].length); + + var completion = intValue-amt; + this.input.value = preExpr + completion + digitPost + postExpr; + + setSelectionRange(this.input, start, end); + + Firebug.Editor.update(true); + + return true; + } + else + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onKeyPress: function(event) + { + //console.log("onKeyPress", event); + if (event.keyCode == 27 && !this.completeAsYouType) + { + var reverted = this.getAutoCompleter().revert(this.input); + if (reverted) + cancelEvent(event); + } + else if (event.charCode && this.advanceToNext(this.target, event.charCode)) + { + Firebug.Editor.tabNextEditor(); + cancelEvent(event); + } + else + { + if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57) + && event.charCode != 45 && event.charCode != 46) + FBL.cancelEvent(event); + else + { + // If the user backspaces, don't autocomplete after the upcoming input event + this.ignoreNextInput = event.keyCode == 8; + } + } + }, + + onOverflow: function() + { + this.updateLayout(false, false, 3); + }, + + onKeyDown: function(event) + { + //console.log("onKeyDown", event.keyCode); + if (event.keyCode > 46 || event.keyCode == 32 || event.keyCode == 8) + { + this.keyDownPressed = true; + } + }, + + onInput: function(event) + { + //debugger; + + // skip not relevant onpropertychange calls on IE + if (isIE) + { + if (event.propertyName != "value" || !isVisible(this.input) || !this.keyDownPressed) + return; + + this.keyDownPressed = false; + } + + //console.log("onInput", event); + //console.trace(); + + var selectRangeCallback; + + if (this.ignoreNextInput) + { + this.ignoreNextInput = false; + this.getAutoCompleter().reset(); + } + else if (this.completeAsYouType) + selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, false); + else + this.getAutoCompleter().reset(); + + Firebug.Editor.update(); + + if (selectRangeCallback) + { + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + }, + + onContextMenu: function(event) + { + cancelEvent(event); + + var popup = $("fbInlineEditorPopup"); + FBL.eraseNode(popup); + + var target = event.target || event.srcElement; + var menu = this.getContextMenuItems(target); + if (menu) + { + for (var i = 0; i < menu.length; ++i) + FBL.createMenuItem(popup, menu[i]); + } + + if (!popup.firstChild) + return false; + + popup.openPopupAtScreen(event.screenX, event.screenY, true); + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateLayout: function(initial, forceAll, extraWidth) + { + if (this.fixedWidth) + { + this.box.style.left = (this.targetOffset.x) + "px"; + this.box.style.top = (this.targetOffset.y) + "px"; + + var w = this.target.offsetWidth; + var h = this.target.offsetHeight; + this.input.style.width = w + "px"; + this.input.style.height = (h-3) + "px"; + } + else + { + if (initial || forceAll) + { + this.box.style.left = this.targetOffset.x + "px"; + this.box.style.top = this.targetOffset.y + "px"; + } + + var approxTextWidth = this.textSize.width; + var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x) + - this.outerMargin; + + var wrapped = initial + ? this.noWrap && this.targetSize.height > this.textSize.height+3 + : this.noWrap && approxTextWidth > maxWidth; + + if (wrapped) + { + var style = isIE ? + this.target.currentStyle : + this.target.ownerDocument.defaultView.getComputedStyle(this.target, ""); + + targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight); + + // Make the width fit the remaining x-space from the offset to the far right + approxTextWidth = maxWidth - targetMargin; + + this.input.style.width = "100%"; + this.box.style.width = approxTextWidth + "px"; + } + else + { + // Make the input one character wider than the text value so that + // typing does not ever cause the textbox to scroll + var charWidth = this.measureInputText('m').width; + + // Sometimes we need to make the editor a little wider, specifically when + // an overflow happens, otherwise it will scroll off some text on the left + if (extraWidth) + charWidth *= extraWidth; + + var inputWidth = approxTextWidth + charWidth; + + if (initial) + { + if (isIE) + { + // TODO: xxxpedro + var xDiff = 13; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + else + this.box.style.width = "auto"; + } + else + { + // TODO: xxxpedro + var xDiff = isIE ? 13: this.box.scrollWidth - this.input.offsetWidth; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + + this.input.style.width = inputWidth + "px"; + } + + this.expander.style.width = approxTextWidth + "px"; + this.expander.style.height = Math.max(this.textSize.height-3,0) + "px"; + } + + if (forceAll) + scrollIntoCenterView(this.box, null, true); + } +}); + +// ************************************************************************************************ +// Autocompletion + +Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive) +{ + var candidates = null; + var originalValue = null; + var originalOffset = -1; + var lastExpr = null; + var lastOffset = -1; + var exprOffset = 0; + var lastIndex = 0; + var preParsed = null; + var preExpr = null; + var postExpr = null; + + this.revert = function(textBox) + { + if (originalOffset != -1) + { + textBox.value = originalValue; + + setSelectionRange(textBox, originalOffset, originalOffset); + + this.reset(); + return true; + } + else + { + this.reset(); + return false; + } + }; + + this.reset = function() + { + candidates = null; + originalValue = null; + originalOffset = -1; + lastExpr = null; + lastOffset = 0; + exprOffset = 0; + }; + + this.complete = function(context, textBox, cycle, reverse) + { + //console.log("complete", context, textBox, cycle, reverse); + // TODO: xxxpedro important port to firebug (variable leak) + //var value = lastValue = textBox.value; + var value = textBox.value; + + //var offset = textBox.selectionStart; + var offset = getInputSelectionStart(textBox); + + // The result of selectionStart() in Safari/Chrome is 1 unit less than the result + // in Firefox. Therefore, we need to manually adjust the value here. + if (isSafari && !cycle && offset >= 0) offset++; + + if (!selectMode && originalOffset != -1) + offset = originalOffset; + + if (!candidates || !cycle || offset != lastOffset) + { + originalOffset = offset; + originalValue = value; + + // Find the part of the string that will be parsed + var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0; + preParsed = value.substr(0, parseStart); + var parsed = value.substr(parseStart); + + // Find the part of the string that is being completed + var range = getRange ? getRange(parsed, offset-parseStart, context) : null; + if (!range) + range = {start: 0, end: parsed.length-1 }; + + var expr = parsed.substr(range.start, range.end-range.start+1); + preExpr = parsed.substr(0, range.start); + postExpr = parsed.substr(range.end+1); + exprOffset = parseStart + range.start; + + if (!cycle) + { + if (!expr) + return; + else if (lastExpr && lastExpr.indexOf(expr) != 0) + { + candidates = null; + } + else if (lastExpr && lastExpr.length >= expr.length) + { + candidates = null; + lastExpr = expr; + return; + } + } + + lastExpr = expr; + lastOffset = offset; + + var searchExpr; + + // Check if the cursor is at the very right edge of the expression, or + // somewhere in the middle of it + if (expr && offset != parseStart+range.end+1) + { + if (cycle) + { + // We are in the middle of the expression, but we can + // complete by cycling to the next item in the values + // list after the expression + offset = range.start; + searchExpr = expr; + expr = ""; + } + else + { + // We can't complete unless we are at the ridge edge + return; + } + } + + var values = evaluator(preExpr, expr, postExpr, context); + if (!values) + return; + + if (expr) + { + // Filter the list of values to those which begin with expr. We + // will then go on to complete the first value in the resulting list + candidates = []; + + if (caseSensitive) + { + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.indexOf(expr) == 0) + candidates.push(name); + } + } + else + { + var lowerExpr = caseSensitive ? expr : expr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0) + candidates.push(name); + } + } + + lastIndex = reverse ? candidates.length-1 : 0; + } + else if (searchExpr) + { + var searchIndex = -1; + + // Find the first instance of searchExpr in the values list. We + // will then complete the string that is found + if (caseSensitive) + { + searchIndex = values.indexOf(expr); + } + else + { + var lowerExpr = searchExpr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name && name.toLowerCase().indexOf(lowerExpr) == 0) + { + searchIndex = i; + break; + } + } + } + + // Nothing found, so there's nothing to complete to + if (searchIndex == -1) + return this.reset(); + + expr = searchExpr; + candidates = cloneArray(values); + lastIndex = searchIndex; + } + else + { + expr = ""; + candidates = []; + for (var i = 0; i < values.length; ++i) + { + if (values[i].substr) + candidates.push(values[i]); + } + lastIndex = -1; + } + } + + if (cycle) + { + expr = lastExpr; + lastIndex += reverse ? -1 : 1; + } + + if (!candidates.length) + return; + + if (lastIndex >= candidates.length) + lastIndex = 0; + else if (lastIndex < 0) + lastIndex = candidates.length-1; + + var completion = candidates[lastIndex]; + var preCompletion = expr.substr(0, offset-exprOffset); + var postCompletion = completion.substr(offset-exprOffset); + + textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr; + var offsetEnd = preParsed.length + preExpr.length + completion.length; + + // TODO: xxxpedro remove the following commented code, if the lib.setSelectionRange() + // is working well. + /* + if (textBox.setSelectionRange) + { + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + setTimeout(function(){ + if (selectMode) + textBox.setSelectionRange(offset, offsetEnd); + else + textBox.setSelectionRange(offsetEnd, offsetEnd); + },0); + } + /**/ + + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + /* + setTimeout(function(){ + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + },0); + + return true; + /**/ + + // The editor text should be selected only after calling the editor.update() + // in Safari/Chrome, otherwise the text won't be selected. So, we're returning + // a function to be called later (in the proper time for all browsers). + // + // TODO: xxxpedro see if we can move the editor.update() calls to here, and avoid + // returning a closure. the complete() function seems to be called only twice in + // editor.js. See if this function is called anywhere else (like css.js for example). + return function(){ + //console.log("autocomplete ", textBox, offset, offsetEnd); + + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + }; + /**/ + }; +}; + +// ************************************************************************************************ +// Local Helpers + +var getDefaultEditor = function getDefaultEditor(panel) +{ + if (!defaultEditor) + { + var doc = panel.document; + defaultEditor = new Firebug.InlineEditor(doc); + } + + return defaultEditor; +} + +/** + * An outsider is the first element matching the stepper element that + * is not an child of group. Elements tagged with insertBefore or insertAfter + * classes are also excluded from these results unless they are the sibling + * of group, relative to group's parent editGroup. This allows for the proper insertion + * rows when groups are nested. + */ +var getOutsider = function getOutsider(element, group, stepper) +{ + var parentGroup = getAncestorByClass(group.parentNode, "editGroup"); + var next; + do + { + next = stepper(next || element); + } + while (isAncestor(next, group) || isGroupInsert(next, parentGroup)); + + return next; +} + +var isGroupInsert = function isGroupInsert(next, group) +{ + return (!group || isAncestor(next, group)) + && (hasClass(next, "insertBefore") || hasClass(next, "insertAfter")); +} + +var getNextOutsider = function getNextOutsider(element, group) +{ + return getOutsider(element, group, bind(getNextByClass, FBL, "editable")); +} + +var getPreviousOutsider = function getPreviousOutsider(element, group) +{ + return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable")); +} + +var getInlineParent = function getInlineParent(element) +{ + var lastInline = element; + for (; element; element = element.parentNode) + { + //var s = element.ownerDocument.defaultView.getComputedStyle(element, ""); + var s = isIE ? + element.currentStyle : + element.ownerDocument.defaultView.getComputedStyle(element, ""); + + if (s.display != "inline") + return lastInline; + else + lastInline = element; + } + return null; +} + +var insertTab = function insertTab() +{ + insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.Editor); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Inspector Module + +var ElementCache = Firebug.Lite.Cache.Element; + +var inspectorTS, inspectorTimer, isInspecting; + +Firebug.Inspector = +{ + create: function() + { + offlineFragment = Env.browser.document.createDocumentFragment(); + + createBoxModelInspector(); + createOutlineInspector(); + }, + + destroy: function() + { + destroyBoxModelInspector(); + destroyOutlineInspector(); + + offlineFragment = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inspect functions + + toggleInspect: function() + { + if (isInspecting) + { + this.stopInspecting(); + } + else + { + Firebug.chrome.inspectButton.changeState("pressed"); + this.startInspecting(); + } + }, + + startInspecting: function() + { + isInspecting = true; + + Firebug.chrome.selectPanel("HTML"); + + createInspectorFrame(); + + var size = Firebug.browser.getWindowScrollSize(); + + fbInspectFrame.style.width = size.width + "px"; + fbInspectFrame.style.height = size.height + "px"; + + //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody); + + addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + }, + + stopInspecting: function() + { + isInspecting = false; + + if (outlineVisible) this.hideOutline(); + removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + + destroyInspectorFrame(); + + Firebug.chrome.inspectButton.restore(); + + if (Firebug.chrome.type == "popup") + Firebug.chrome.node.focus(); + }, + + onInspectingClick: function(e) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + //Firebug.Console.log(targ); + Firebug.Inspector.stopInspecting(); + }, + + onInspecting: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache(targ)) + { + var target = ""+ElementCache.key(targ); + var lazySelect = function() + { + inspectorTS = new Date().getTime(); + + Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)) + }; + + if (inspectorTimer) + { + clearTimeout(inspectorTimer); + inspectorTimer = null; + } + + if (new Date().getTime() - inspectorTS > 200) + setTimeout(lazySelect, 0) + else + inspectorTimer = setTimeout(lazySelect, 300); + } + + lastInspecting = new Date().getTime(); + } + }, + + // TODO: xxxpedro remove this? + onInspectingBody: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + var targ = e.target; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache.has(targ)) + FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)); + + lastInspecting = new Date().getTime(); + } + }, + + /** + * + * llttttttrr + * llttttttrr + * ll rr + * ll rr + * llbbbbbbrr + * llbbbbbbrr + */ + drawOutline: function(el) + { + var border = 2; + var scrollbarSize = 17; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + var box = Firebug.browser.getElementBox(el); + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width - + (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible + scrollbarSize : 0); + + var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height - + (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible + scrollbarSize : 0); + + var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1; + + var o = outlineElements; + var style; + + style = o.fbOutlineT.style; + style.top = top-border + "px"; + style.left = left + "px"; + style.height = border + "px"; // TODO: on initialize() + style.width = width + "px"; + + style = o.fbOutlineL.style; + style.top = top-border + "px"; + style.left = left-border + "px"; + style.height = height+ numVerticalBorders*border + "px"; + style.width = border + "px"; // TODO: on initialize() + + style = o.fbOutlineB.style; + if (freeVerticalSpace > 0) + { + style.top = top+height + "px"; + style.left = left + "px"; + style.width = width + "px"; + //style.height = border + "px"; // TODO: on initialize() or worst case? + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.width = border + "px"; + //style.height = border + "px"; + } + + style = o.fbOutlineR.style; + if (freeHorizontalSpace > 0) + { + style.top = top-border + "px"; + style.left = left+width + "px"; + style.height = height + numVerticalBorders*border + "px"; + style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px"; + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.height = border + "px"; + style.width = border + "px"; + } + + if (!outlineVisible) this.showOutline(); + }, + + hideOutline: function() + { + if (!outlineVisible) return; + + for (var name in outline) + offlineFragment.appendChild(outlineElements[name]); + + outlineVisible = false; + }, + + showOutline: function() + { + if (outlineVisible) return; + + if (boxModelVisible) this.hideBoxModel(); + + for (var name in outline) + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]); + + outlineVisible = true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Box Model + + drawBoxModel: function(el) + { + // avoid error when the element is not attached a document + if (!el || !el.parentNode) + return; + + var box = Firebug.browser.getElementBox(el); + + var windowSize = Firebug.browser.getWindowSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + // element may be occluded by the chrome, when in frame mode + var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0; + + // if element box is not inside the viewport, don't draw the box model + if (box.top > scrollPosition.top + windowSize.height - offsetHeight || + box.left > scrollPosition.left + windowSize.width || + scrollPosition.top > box.top + box.height || + scrollPosition.left > box.left + box.width ) + return; + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var margin = Firebug.browser.getMeasurementBox(el, "margin"); + var padding = Firebug.browser.getMeasurementBox(el, "padding"); + var border = Firebug.browser.getMeasurementBox(el, "border"); + + boxModelStyle.top = top - margin.top + "px"; + boxModelStyle.left = left - margin.left + "px"; + boxModelStyle.height = height + margin.top + margin.bottom + "px"; + boxModelStyle.width = width + margin.left + margin.right + "px"; + + boxBorderStyle.top = margin.top + "px"; + boxBorderStyle.left = margin.left + "px"; + boxBorderStyle.height = height + "px"; + boxBorderStyle.width = width + "px"; + + boxPaddingStyle.top = margin.top + border.top + "px"; + boxPaddingStyle.left = margin.left + border.left + "px"; + boxPaddingStyle.height = height - border.top - border.bottom + "px"; + boxPaddingStyle.width = width - border.left - border.right + "px"; + + boxContentStyle.top = margin.top + border.top + padding.top + "px"; + boxContentStyle.left = margin.left + border.left + padding.left + "px"; + boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px"; + boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px"; + + if (!boxModelVisible) this.showBoxModel(); + }, + + hideBoxModel: function() + { + if (!boxModelVisible) return; + + offlineFragment.appendChild(boxModel); + boxModelVisible = false; + }, + + showBoxModel: function() + { + if (boxModelVisible) return; + + if (outlineVisible) this.hideOutline(); + + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel); + boxModelVisible = true; + } + +}; + +// ************************************************************************************************ +// Inspector Internals + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Shared variables + + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internal variables + +var offlineFragment = null; + +var boxModelVisible = false; + +var boxModel, boxModelStyle, + boxMargin, boxMarginStyle, + boxBorder, boxBorderStyle, + boxPadding, boxPaddingStyle, + boxContent, boxContentStyle; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; +var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;"; + +var inspectStyle = resetStyle + "z-index: 2147483500;"; +var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" + + Env.Location.skinDir + "pixel_transparent.gif);"; + +//if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);"; + +var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;"; +var inspectModelStyle = inspectStyle + inspectModelOpacity; +var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;"; +var inspectBorderStyle = inspectStyle + "background: #666;"; +var inspectPaddingStyle = inspectStyle + "background: SlateBlue;"; +var inspectContentStyle = inspectStyle + "background: SkyBlue;"; + + +var outlineStyle = { + fbHorizontalLine: "background: #3875D7;height: 2px;", + fbVerticalLine: "background: #3875D7;width: 2px;" +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var lastInspecting = 0; +var fbInspectFrame = null; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var outlineVisible = false; +var outlineElements = {}; +var outline = { + "fbOutlineT": "fbHorizontalLine", + "fbOutlineL": "fbVerticalLine", + "fbOutlineB": "fbHorizontalLine", + "fbOutlineR": "fbVerticalLine" +}; + + +var getInspectingTarget = function() +{ + +}; + +// ************************************************************************************************ +// Section + +var createInspectorFrame = function createInspectorFrame() +{ + fbInspectFrame = createGlobalElement("div"); + fbInspectFrame.id = "fbInspectFrame"; + fbInspectFrame.firebugIgnore = true; + fbInspectFrame.style.cssText = inspectFrameStyle; + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame); +}; + +var destroyInspectorFrame = function destroyInspectorFrame() +{ + if (fbInspectFrame) + { + Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame); + fbInspectFrame = null; + } +}; + +var createOutlineInspector = function createOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name] = createGlobalElement("div"); + el.id = name; + el.firebugIgnore = true; + el.style.cssText = inspectStyle + outlineStyle[outline[name]]; + offlineFragment.appendChild(el); + } +}; + +var destroyOutlineInspector = function destroyOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name]; + el.parentNode.removeChild(el); + } +}; + +var createBoxModelInspector = function createBoxModelInspector() +{ + boxModel = createGlobalElement("div"); + boxModel.id = "fbBoxModel"; + boxModel.firebugIgnore = true; + boxModelStyle = boxModel.style; + boxModelStyle.cssText = inspectModelStyle; + + boxMargin = createGlobalElement("div"); + boxMargin.id = "fbBoxMargin"; + boxMarginStyle = boxMargin.style; + boxMarginStyle.cssText = inspectMarginStyle; + boxModel.appendChild(boxMargin); + + boxBorder = createGlobalElement("div"); + boxBorder.id = "fbBoxBorder"; + boxBorderStyle = boxBorder.style; + boxBorderStyle.cssText = inspectBorderStyle; + boxModel.appendChild(boxBorder); + + boxPadding = createGlobalElement("div"); + boxPadding.id = "fbBoxPadding"; + boxPaddingStyle = boxPadding.style; + boxPaddingStyle.cssText = inspectPaddingStyle; + boxModel.appendChild(boxPadding); + + boxContent = createGlobalElement("div"); + boxContent.id = "fbBoxContent"; + boxContentStyle = boxContent.style; + boxContentStyle.cssText = inspectContentStyle; + boxModel.appendChild(boxContent); + + offlineFragment.appendChild(boxModel); +}; + +var destroyBoxModelInspector = function destroyBoxModelInspector() +{ + boxModel.parentNode.removeChild(boxModel); +}; + +// ************************************************************************************************ +// Section + + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +// next-generation Console Panel (will override consoje.js) +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Constants + +/* +const Cc = Components.classes; +const Ci = Components.interfaces; +const nsIPrefBranch2 = Ci.nsIPrefBranch2; +const PrefService = Cc["@mozilla.org/preferences-service;1"]; +const prefs = PrefService.getService(nsIPrefBranch2); +/**/ +/* + +// new offline message handler +o = {x:1,y:2}; + +r = Firebug.getRep(o); + +r.tag.tag.compile(); + +outputs = []; +html = r.tag.renderHTML({object:o}, outputs); + + +// finish rendering the template (the DOM part) +target = $("build"); +target.innerHTML = html; +root = target.firstChild; + +domArgs = [root, r.tag.context, 0]; +domArgs.push.apply(domArgs, r.tag.domArgs); +domArgs.push.apply(domArgs, outputs); +r.tag.tag.renderDOM.apply(self ? self : r.tag.subject, domArgs); + + + */ +var consoleQueue = []; +var lastHighlightedObject; +var FirebugContext = Env.browser; + +// ************************************************************************************************ + +var maxQueueRequests = 500; + +// ************************************************************************************************ + +Firebug.ConsoleBase = +{ + log: function(object, context, className, rep, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"log",[context, object, className, sourceLink]); + return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle); + }, + + logFormatted: function(objects, context, className, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]); + return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle); + }, + + openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush) + { + return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle); + }, + + closeGroup: function(context, noThrottle) + { + return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true); + }, + + logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow) + { + // TODO: xxxpedro console console2 + noThrottle = true; // xxxpedro forced because there is no TabContext yet + + if (!context) + context = FirebugContext; + + if (FBTrace.DBG_ERRORS && !context) + FBTrace.sysout("Console.logRow has no context, skipping objects", objects); + + if (!context) + return; + + if (noThrottle || !context) + { + var panel = this.getPanel(context); + if (panel) + { + var row = panel.append(appender, objects, className, rep, sourceLink, noRow); + var container = panel.panelNode; + + // TODO: xxxpedro what is this? console console2 + /* + var template = Firebug.NetMonitor.NetLimit; + + while (container.childNodes.length > maxQueueRequests + 1) + { + clearDomplate(container.firstChild.nextSibling); + container.removeChild(container.firstChild.nextSibling); + panel.limit.limitInfo.totalCount++; + template.updateCounter(panel.limit); + } + dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]); + /**/ + return row; + } + else + { + consoleQueue.push([appender, objects, context, className, rep, sourceLink, noThrottle, noRow]); + } + } + else + { + if (!context.throttle) + { + //FBTrace.sysout("console.logRow has not context.throttle! "); + return; + } + var args = [appender, objects, context, className, rep, sourceLink, true, noRow]; + context.throttle(this.logRow, this, args); + } + }, + + appendFormatted: function(args, row, context) + { + if (!context) + context = FirebugContext; + + var panel = this.getPanel(context); + panel.appendFormatted(args, row); + }, + + clear: function(context) + { + if (!context) + //context = FirebugContext; + context = Firebug.context; + + /* + if (context) + Firebug.Errors.clear(context); + /**/ + + var panel = this.getPanel(context, true); + if (panel) + { + panel.clear(); + } + }, + + // Override to direct output to your panel + getPanel: function(context, noCreate) + { + //return context.getPanel("console", noCreate); + // TODO: xxxpedro console console2 + return Firebug.chrome ? Firebug.chrome.getPanel("Console") : null; + } + +}; + +// ************************************************************************************************ + +//TODO: xxxpedro +//var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase); +var ActivableConsole = extend(Firebug.ConsoleBase, +{ + isAlwaysEnabled: function() + { + return true; + } +}); + +Firebug.Console = Firebug.Console = extend(ActivableConsole, +//Firebug.Console = extend(ActivableConsole, +{ + dispatchName: "console", + + error: function() + { + Firebug.Console.logFormatted(arguments, Firebug.browser, "error"); + }, + + flush: function() + { + dispatch(this.fbListeners,"flush",[]); + + for (var i=0, length=consoleQueue.length; i objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + if (typeof(object) != "undefined") + this.appendObject(object, row, part.rep); + else + this.appendObject(part.type, row, FirebugReps.Text); + } + else + FirebugReps.Text.tag.append({object: part}, row); + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + logText(" ", row); + var object = objects[i]; + if (typeof(object) == "string") + FirebugReps.Text.tag.append({object: object}, row); + else + this.appendObject(object, row); + } + }, + + appendOpenGroup: function(objects, row, rep) + { + if (!this.groups) + this.groups = []; + + setClass(row, "logGroup"); + setClass(row, "opened"); + + var innerRow = this.createRow("logRow"); + setClass(innerRow, "logGroupLabel"); + if (rep) + rep.tag.replace({"objects": objects}, innerRow); + else + this.appendFormatted(objects, innerRow, rep); + row.appendChild(innerRow); + //dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]); + var groupBody = this.createRow("logGroupBody"); + row.appendChild(groupBody); + groupBody.setAttribute('role', 'group'); + this.groups.push(groupBody); + + addEvent(innerRow, "mousedown", function(event) + { + if (isLeftClick(event)) + { + //console.log(event.currentTarget == event.target); + + var target = event.target || event.srcElement; + + target = getAncestorByClass(target, "logGroupLabel"); + + var groupRow = target.parentNode; + + if (hasClass(groupRow, "opened")) + { + removeClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'false'); + } + else + { + setClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'true'); + } + } + }); + }, + + appendCloseGroup: function(object, row, rep) + { + if (this.groups) + this.groups.pop(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // TODO: xxxpedro console2 + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + onMouseDown: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + var repObject = object ? object.repObject : null; + + if (!repObject) + { + return; + } + + if (hasClass(object, "objectLink-object")) + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(repObject, true); + } + else if (hasClass(object, "objectLink-element")) + { + Firebug.chrome.selectPanel("HTML"); + Firebug.chrome.getPanel("HTML").select(repObject, true); + } + + /* + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + /**/ + + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "Console", + title: "Console", + //searchable: true, + //breakable: true, + //editable: false, + + options: + { + hasCommandLine: true, + hasToolButtons: true, + isPreRendered: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.context = Firebug.browser.window; + this.document = Firebug.chrome.document; + this.onMouseMove = bind(this.onMouseMove, this); + this.onMouseDown = bind(this.onMouseDown, this); + + this.clearButton = new Button({ + element: $("fbConsole_btClear"), + owner: Firebug.Console, + onClick: Firebug.Console.clear + }); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); // loads persisted content + //Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content + + if (!this.persistedContent && Firebug.Console.isAlwaysEnabled()) + { + this.insertLogLimit(this.context); + + // Initialize log limit and listen for changes. + this.updateMaxLimit(); + + if (this.context.consoleReloadWarning) // we have not yet injected the console + this.insertReloadWarning(); + } + + //Firebug.Console.injector.install(Firebug.browser.window); + + addEvent(this.panelNode, "mouseover", this.onMouseMove); + addEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.clearButton.initialize(); + + //consolex.trace(); + //TODO: xxxpedro remove this + /* + Firebug.Console.openGroup(["asd"], null, "group", null, false); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + /**/ + + //TODO: xxxpedro preferences prefs + //prefs.addObserver(Firebug.prefDomain, this, false); + }, + + initializeNode : function() + { + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this]); + if (FBTrace.DBG_CONSOLE) + { + this.onScroller = bind(this.onScroll, this); + addEvent(this.panelNode, "scroll", this.onScroller); + } + + this.onResizer = bind(this.onResize, this); + this.resizeEventTarget = Firebug.chrome.$('fbContentBox'); + addEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + destroyNode : function() + { + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this]); + if (this.onScroller) + removeEvent(this.panelNode, "scroll", this.onScroller); + + //removeEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + shutdown: function() + { + //TODO: xxxpedro console console2 + this.clearButton.shutdown(); + + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + + //TODO: xxxpedro preferences prefs + //prefs.removeObserver(Firebug.prefDomain, this, false); + }, + + ishow: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel show; " + this.context.getName(), state); + + var enabled = Firebug.Console.isAlwaysEnabled(); + if (enabled) + { + Firebug.Console.disabledPanelPage.hide(this); + this.showCommandLine(true); + this.showToolbarButtons("fbConsoleButtons", true); + Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent); + + if (state && state.wasScrolledToBottom) + { + this.wasScrolledToBottom = state.wasScrolledToBottom; + delete state.wasScrolledToBottom; + } + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + } + else + { + this.hide(state); + Firebug.Console.disabledPanelPage.show(this); + } + }, + + ihide: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel hide; " + this.context.getName(), state); + + this.showToolbarButtons("fbConsoleButtons", false); + this.showCommandLine(false); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + destroy: function(state) + { + if (this.panelNode.offsetHeight) + this.wasScrolledToBottom = isScrolledToBottom(this.panelNode); + + if (state) + state.wasScrolledToBottom = this.wasScrolledToBottom; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + shouldBreakOnNext: function() + { + // xxxHonza: shouldn't the breakOnErrors be context related? + // xxxJJB, yes, but we can't support it because we can't yet tell + // which window the error is on. + return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors"); + }, + + getBreakOnNextTooltip: function(enabled) + { + return (enabled ? $STR("console.Disable Break On All Errors") : + $STR("console.Break On All Errors")); + }, + + enablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.enablePanel.apply(this, arguments); + + this.showCommandLine(true); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + }, + + disablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.disablePanel.apply(this, arguments); + + this.showCommandLine(false); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowJavaScriptErrors", "showJSErrors"), + optionMenu("ShowJavaScriptWarnings", "showJSWarnings"), + optionMenu("ShowCSSErrors", "showCSSErrors"), + optionMenu("ShowXMLErrors", "showXMLErrors"), + optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"), + optionMenu("ShowChromeErrors", "showChromeErrors"), + optionMenu("ShowChromeMessages", "showChromeMessages"), + optionMenu("ShowExternalErrors", "showExternalErrors"), + optionMenu("ShowNetworkErrors", "showNetworkErrors"), + this.getShowStackTraceMenuItem(), + this.getStrictOptionMenuItem(), + "-", + optionMenu("LargeCommandLine", "largeCommandLine") + ]; + }, + + getShowStackTraceMenuItem: function() + { + var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace"); + if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled()) + menuItem.disabled = true; + return menuItem; + }, + + getStrictOptionMenuItem: function() + { + var strictDomain = "javascript.options"; + var strictName = "strict"; + var strictValue = prefs.getBoolPref(strictDomain+"."+strictName); + return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue, + command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) }; + }, + + getBreakOnMenuItems: function() + { + //xxxHonza: no BON options for now. + /*return [ + optionMenu("console.option.Persist Break On Error", "persistBreakOnError") + ];*/ + return []; + }, + + search: function(text) + { + if (!text) + return; + + // Make previously visible nodes invisible again + if (this.matchSet) + { + for (var i in this.matchSet) + removeClass(this.matchSet[i], "matched"); + } + + this.matchSet = []; + + function findRow(node) { return getAncestorByClass(node, "logRow"); } + var search = new TextSearch(this.panelNode, findRow); + + var logRow = search.find(text); + if (!logRow) + { + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]); + return false; + } + for (; logRow; logRow = search.findNext()) + { + setClass(logRow, "matched"); + this.matchSet.push(logRow); + } + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]); + return true; + }, + + breakOnNext: function(breaking) + { + Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // private + + createRow: function(rowName, className) + { + var elt = this.document.createElement("div"); + elt.className = rowName + (className ? " " + rowName + "-" + className : ""); + return elt; + }, + + getTopContainer: function() + { + if (this.groups && this.groups.length) + return this.groups[this.groups.length-1]; + else + return this.panelNode; + }, + + filterLogRow: function(logRow, scrolledToBottom) + { + if (this.searchText) + { + setClass(logRow, "matching"); + setClass(logRow, "matched"); + + // Search after a delay because we must wait for a frame to be created for + // the new logRow so that the finder will be able to locate it + setTimeout(bindFixed(function() + { + if (this.searchFilter(this.searchText, logRow)) + this.matchSet.push(logRow); + else + removeClass(logRow, "matched"); + + removeClass(logRow, "matching"); + + if (scrolledToBottom) + scrollToBottom(this.panelNode); + }, this), 100); + } + }, + + searchFilter: function(text, logRow) + { + var count = this.panelNode.childNodes.length; + var searchRange = this.document.createRange(); + searchRange.setStart(this.panelNode, 0); + searchRange.setEnd(this.panelNode, count); + + var startPt = this.document.createRange(); + startPt.setStartBefore(logRow); + + var endPt = this.document.createRange(); + endPt.setStartAfter(logRow); + + return finder.Find(text, searchRange, startPt, endPt) != null; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + // xxxHonza check this out. + var prefDomain = "Firebug.extension."; + var prefName = data.substr(prefDomain.length); + if (prefName == "console.logLimit") + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = 1000; + //TODO: xxxpedro preferences log limit? + //var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + }, + + showCommandLine: function(shouldShow) + { + //TODO: xxxpedro show command line important + return; + + if (shouldShow) + { + collapse(Firebug.chrome.$("fbCommandBox"), false); + Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome); + } + else + { + // Make sure that entire content of the Console panel is hidden when + // the panel is disabled. + Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine); + collapse(Firebug.chrome.$("fbCommandBox"), true); + } + }, + + onScroll: function(event) + { + // Update the scroll position flag if the position changes. + this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", wasScrolledToBottom: " + + this.context.getName(), event); + }, + + onResize: function(event) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight + + ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " + + this.panelNode.scrollHeight + ", " + this.context.getName(), event); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + } +}); + +// ************************************************************************************************ + +function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +} + +// ************************************************************************************************ + +var appendObject = Firebug.ConsolePanel.prototype.appendObject; +var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted; +var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup; +var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup; + +// ************************************************************************************************ + +//Firebug.registerActivableModule(Firebug.Console); +Firebug.registerModule(Firebug.Console); +Firebug.registerPanel(Firebug.ConsolePanel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +var frameCounters = {}; +var traceRecursion = 0; + +Firebug.Console.injector = +{ + install: function(context) + { + var win = context.window; + + var consoleHandler = new FirebugConsoleHandler(context, win); + + var properties = + [ + "log", + "debug", + "info", + "warn", + "error", + "assert", + "dir", + "dirxml", + "group", + "groupCollapsed", + "groupEnd", + "time", + "timeEnd", + "count", + "trace", + "profile", + "profileEnd", + "clear", + "open", + "close" + ]; + + var Handler = function(name) + { + var c = consoleHandler; + var f = consoleHandler[name]; + return function(){return f.apply(c,arguments)}; + }; + + var installer = function(c) + { + for (var i=0, l=properties.length; i 1) + { + traceRecursion--; + return; + } + + var frames = []; + + for (var fn = arguments.callee.caller.caller; fn; fn = fn.caller) + { + if (wasVisited(fn)) break; + + var args = []; + + for (var i = 0, l = fn.arguments.length; i < l; ++i) + { + args.push({value: fn.arguments[i]}); + } + + frames.push({fn: fn, name: getFuncName(fn), args: args}); + } + + + // **************************************************************************************** + + try + { + (0)(); + } + catch(e) + { + var result = e; + + var stack = + result.stack || // Firefox / Google Chrome + result.stacktrace || // Opera + ""; + + stack = stack.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks + var items = stack.split(/[\n\r]/); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Google Chrome + if (FBL.isSafari) + { + //var reChromeStackItem = /^\s+at\s+([^\(]+)\s\((.*)\)$/; + //var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + + var reChromeStackItemName = /\s*\($/; + var reChromeStackItemValue = /^(.+)\:(\d+\:\d+)\)?$/; + + var framePos = 0; + for (var i=4, length=items.length; i 1) + { + objects = [errorObject]; + for (var i = 1; i < args.length; i++) + objects.push(args[i]); + } + + var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle + row.scrollIntoView(); + } + + function getComponentsStackDump() + { + // Starting with our stack, walk back to the user-level code + var frame = Components.stack; + var userURL = win.location.href.toString(); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame); + + // Drop frames until we get into user code. + while (frame && FBL.isSystemURL(frame.filename) ) + frame = frame.caller; + + // Drop two more frames, the injected console function and firebugAppendConsole() + if (frame) + frame = frame.caller; + if (frame) + frame = frame.caller; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame); + + return frame; + } + + function getStackLink() + { + // TODO: xxxpedro console2 + return; + //return FBL.getFrameSourceLink(getComponentsStackDump()); + } + + function getJSDUserStack() + { + var trace = FBL.getCurrentStackTrace(context); + + var frames = trace ? trace.frames : null; + if (frames && (frames.length > 0) ) + { + var oldest = frames.length - 1; // 6 - 1 = 5 + for (var i = 0; i < frames.length; i++) + { + if (frames[oldest - i].href.indexOf("chrome:") == 0) break; + var fn = frames[oldest - i].fn + ""; + if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line + } + FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace); + trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code + + return trace; + } + else + return "Firebug failed to get stack trace with any frames"; + } +} + +// ************************************************************************************************ +// Register console namespace + +FBL.registerConsole = function() +{ + //TODO: xxxpedro console options override + //if (Env.Options.overrideConsole) + var win = Env.browser.window; + Firebug.Console.injector.install(win); +}; + +registerConsole(); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +// ************************************************************************************************ +// Globals + +var commandPrefix = ">>>"; +var reOpenBracket = /[\[\(\{]/; +var reCloseBracket = /[\]\)\}]/; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var commandHistory = []; +var commandPointer = -1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var isAutoCompleting = null; +var autoCompletePrefix = null; +var autoCompleteExpr = null; +var autoCompleteBuffer = null; +var autoCompletePosition = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var fbCommandLine = null; +var fbLargeCommandLine = null; +var fbLargeCommandButtons = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _completion = +{ + window: + [ + "console" + ], + + document: + [ + "getElementById", + "getElementsByTagName" + ] +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _stack = function(command) +{ + commandHistory.push(command); + commandPointer = commandHistory.length; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +// ************************************************************************************************ +// CommandLine + +Firebug.CommandLine = extend(Firebug.Module, +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + element: null, + isMultiLine: false, + isActive: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + initialize: function(doc) + { + this.clear = bind(this.clear, this); + this.enter = bind(this.enter, this); + + this.onError = bind(this.onError, this); + this.onKeyDown = bind(this.onKeyDown, this); + this.onMultiLineKeyDown = bind(this.onMultiLineKeyDown, this); + + addEvent(Firebug.browser.window, "error", this.onError); + addEvent(Firebug.chrome.window, "error", this.onError); + }, + + shutdown: function(doc) + { + this.deactivate(); + + removeEvent(Firebug.browser.window, "error", this.onError); + removeEvent(Firebug.chrome.window, "error", this.onError); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + activate: function(multiLine, hideToggleIcon, onRun) + { + defineCommandLineAPI(); + + if (this.isActive) + { + if (this.isMultiLine == multiLine) return; + + this.deactivate(); + } + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + if (multiLine) + { + onRun = onRun || this.enter; + + this.isMultiLine = true; + + this.element = fbLargeCommandLine; + + addEvent(this.element, "keydown", this.onMultiLineKeyDown); + + addEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton = new Button({ + element: $("fbCommand_btRun"), + owner: Firebug.CommandLine, + onClick: onRun + }); + + this.runButton.initialize(); + + this.clearButton = new Button({ + element: $("fbCommand_btClear"), + owner: Firebug.CommandLine, + onClick: this.clear + }); + + this.clearButton.initialize(); + } + else + { + this.isMultiLine = false; + this.element = fbCommandLine; + + if (!fbCommandLine) + return; + + addEvent(this.element, "keydown", this.onKeyDown); + } + + //Firebug.Console.log("activate", this.element); + + if (isOpera) + fixOperaTabKey(this.element); + + if(this.lastValue) + this.element.value = this.lastValue; + + this.isActive = true; + }, + + deactivate: function() + { + if (!this.isActive) return; + + //Firebug.Console.log("deactivate", this.element); + + this.isActive = false; + + this.lastValue = this.element.value; + + if (this.isMultiLine) + { + removeEvent(this.element, "keydown", this.onMultiLineKeyDown); + + removeEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton.destroy(); + this.clearButton.destroy(); + } + else + { + removeEvent(this.element, "keydown", this.onKeyDown); + } + + this.element = null + delete this.element; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focus: function() + { + this.element.focus(); + }, + + blur: function() + { + this.element.blur(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + clear: function() + { + this.element.value = ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + evaluate: function(expr) + { + // TODO: need to register the API in console.firebug.commandLineAPI + var api = "Firebug.CommandLine.API" + + var result = Firebug.context.evaluate(expr, "window", api, Firebug.Console.error); + + return result; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + enter: function() + { + var command = this.element.value; + + if (!command) return; + + _stack(command); + + Firebug.Console.log(commandPrefix + " " + stripNewLines(command), Firebug.browser, "command", FirebugReps.Text); + + var result = this.evaluate(command); + + Firebug.Console.log(result); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + prevCommand: function() + { + if (commandPointer > 0 && commandHistory.length > 0) + this.element.value = commandHistory[--commandPointer]; + }, + + nextCommand: function() + { + var element = this.element; + + var limit = commandHistory.length -1; + var i = commandPointer; + + if (i < limit) + element.value = commandHistory[++commandPointer]; + + else if (i == limit) + { + ++commandPointer; + element.value = ""; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + autocomplete: function(reverse) + { + var element = this.element; + + var command = element.value; + var offset = getExpressionOffset(command); + + var valBegin = offset ? command.substr(0, offset) : ""; + var val = command.substr(offset); + + var buffer, obj, objName, commandBegin, result, prefix; + + // if it is the beginning of the completion + if(!isAutoCompleting) + { + + // group1 - command begin + // group2 - base object + // group3 - property prefix + var reObj = /(.*[^_$\w\d\.])?((?:[_$\w][_$\w\d]*\.)*)([_$\w][_$\w\d]*)?$/; + var r = reObj.exec(val); + + // parse command + if (r[1] || r[2] || r[3]) + { + commandBegin = r[1] || ""; + objName = r[2] || ""; + prefix = r[3] || ""; + } + else if (val == "") + { + commandBegin = objName = prefix = ""; + } else + return; + + isAutoCompleting = true; + + // find base object + if(objName == "") + obj = window; + + else + { + objName = objName.replace(/\.$/, ""); + + var n = objName.split("."); + var target = window, o; + + for (var i=0, ni; ni = n[i]; i++) + { + if (o = target[ni]) + target = o; + + else + { + target = null; + break; + } + } + obj = target; + } + + // map base object + if(obj) + { + autoCompletePrefix = prefix; + autoCompleteExpr = valBegin + commandBegin + (objName ? objName + "." : ""); + autoCompletePosition = -1; + + buffer = autoCompleteBuffer = isIE ? + _completion[objName || "window"] || [] : []; + + for(var p in obj) + buffer.push(p); + } + + // if it is the continuation of the last completion + } else + buffer = autoCompleteBuffer; + + if (buffer) + { + prefix = autoCompletePrefix; + + var diff = reverse ? -1 : 1; + + for(var i=autoCompletePosition+diff, l=buffer.length, bi; i>=0 && i', msg, '
      ', + '' + ]; + + // TODO: xxxpedro ajust to Console2 + //Firebug.Console.writeRow(html, "error"); + }, + + onKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + /*tab, shift, control, alt*/ + if (code != 9 && code != 16 && code != 17 && code != 18) + { + isAutoCompleting = false; + } + + if (code == 13 /* enter */) + { + this.enter(); + this.clear(); + } + else if (code == 27 /* ESC */) + { + setTimeout(this.clear, 0); + } + else if (code == 38 /* up */) + { + this.prevCommand(); + } + else if (code == 40 /* down */) + { + this.nextCommand(); + } + else if (code == 9 /* tab */) + { + this.autocomplete(e.shiftKey); + } + else + return; + + cancelEvent(e, true); + return false; + }, + + onMultiLineKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + if (code == 13 /* enter */ && e.ctrlKey) + { + this.enter(); + } + } +}); + +Firebug.registerModule(Firebug.CommandLine); + + +// ************************************************************************************************ +// + +function getExpressionOffset(command) +{ + // XXXjoe This is kind of a poor-man's JavaScript parser - trying + // to find the start of the expression that the cursor is inside. + // Not 100% fool proof, but hey... + + var bracketCount = 0; + + var start = command.length-1; + for (; start >= 0; --start) + { + var c = command[start]; + if ((c == "," || c == ";" || c == " ") && !bracketCount) + break; + if (reOpenBracket.test(c)) + { + if (bracketCount) + --bracketCount; + else + break; + } + else if (reCloseBracket.test(c)) + ++bracketCount; + } + + return start + 1; +} + +// ************************************************************************************************ +// CommandLine API + +var CommandLineAPI = +{ + $: function(id) + { + return Firebug.browser.document.getElementById(id) + }, + + $$: function(selector, context) + { + context = context || Firebug.browser.document; + return Firebug.Selector ? + Firebug.Selector(selector, context) : + Firebug.Console.error("Firebug.Selector module not loaded."); + }, + + $0: null, + + $1: null, + + dir: function(o) + { + Firebug.Console.log(o, Firebug.context, "dir", Firebug.DOMPanel.DirTable); + }, + + dirxml: function(o) + { + ///if (o instanceof Window) + if (instanceOf(o, "Window")) + o = o.document.documentElement; + ///else if (o instanceof Document) + else if (instanceOf(o, "Document")) + o = o.documentElement; + + // TODO: xxxpedro html3 + ///Firebug.Console.log(o, Firebug.context, "dirxml", Firebug.HTMLPanel.SoloElement); + var div = Firebug.Console.log(o, Firebug.context, "dirxml"); + var html = []; + Firebug.Reps.appendNode(o, html); + div.innerHTML = html.join(""); + + } +}; + +// ************************************************************************************************ + +var defineCommandLineAPI = function defineCommandLineAPI() +{ + Firebug.CommandLine.API = {}; + for (var m in CommandLineAPI) + if (!Env.browser.window[m]) + Firebug.CommandLine.API[m] = CommandLineAPI[m]; + + var stack = FirebugChrome.htmlSelectionStack; + if (stack) + { + Firebug.CommandLine.API.$0 = stack[0]; + Firebug.CommandLine.API.$1 = stack[1]; + } +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +if (Env.Options.disableXHRListener) + return; + +// ************************************************************************************************ +// XHRSpy + +var XHRSpy = function() +{ + this.requestHeaders = []; + this.responseHeaders = []; +}; + +XHRSpy.prototype = +{ + method: null, + url: null, + async: null, + + xhrRequest: null, + + href: null, + + loaded: false, + + logRow: null, + + responseText: null, + + requestHeaders: null, + responseHeaders: null, + + sourceLink: null, // {href:"file.html", line: 22} + + getURL: function() + { + return this.href; + } +}; + +// ************************************************************************************************ +// XMLHttpRequestWrapper + +var XMLHttpRequestWrapper = function(activeXObject) +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal variables + + var xhrRequest = typeof activeXObject != "undefined" ? + activeXObject : + new _XMLHttpRequest(), + + spy = new XHRSpy(), + + self = this, + + reqType, + reqUrl, + reqStartTS; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal methods + + var updateSelfPropertiesIgnore = { + abort: 1, + channel: 1, + getAllResponseHeaders: 1, + getInterface: 1, + getResponseHeader: 1, + mozBackgroundRequest: 1, + multipart: 1, + onreadystatechange: 1, + open: 1, + send: 1, + setRequestHeader: 1 + }; + + var updateSelfProperties = function() + { + if (supportsXHRIterator) + { + for (var propName in xhrRequest) + { + if (propName in updateSelfPropertiesIgnore) + continue; + + try + { + var propValue = xhrRequest[propName]; + + if (propValue && !isFunction(propValue)) + self[propName] = propValue; + } + catch(E) + { + //console.log(propName, E.message); + } + } + } + else + { + // will fail to read these xhrRequest properties if the request is not completed + if (xhrRequest.readyState == 4) + { + self.status = xhrRequest.status; + self.statusText = xhrRequest.statusText; + self.responseText = xhrRequest.responseText; + self.responseXML = xhrRequest.responseXML; + } + } + }; + + var updateXHRPropertiesIgnore = { + channel: 1, + onreadystatechange: 1, + readyState: 1, + responseBody: 1, + responseText: 1, + responseXML: 1, + status: 1, + statusText: 1, + upload: 1 + }; + + var updateXHRProperties = function() + { + for (var propName in self) + { + if (propName in updateXHRPropertiesIgnore) + continue; + + try + { + var propValue = self[propName]; + + if (propValue && !xhrRequest[propName]) + { + xhrRequest[propName] = propValue; + } + } + catch(E) + { + //console.log(propName, E.message); + } + } + }; + + var logXHR = function() + { + var row = Firebug.Console.log(spy, null, "spy", Firebug.Spy.XHR); + + if (row) + { + setClass(row, "loading"); + spy.logRow = row; + } + }; + + var finishXHR = function() + { + var duration = new Date().getTime() - reqStartTS; + var success = xhrRequest.status == 200; + + var responseHeadersText = xhrRequest.getAllResponseHeaders(); + var responses = responseHeadersText ? responseHeadersText.split(/[\n\r]/) : []; + var reHeader = /^(\S+):\s*(.*)/; + + for (var i=0, l=responses.length; i 0; + + /**/ + + return this; +}; + +// ************************************************************************************************ +// ActiveXObject Wrapper (IE6 only) + +var _ActiveXObject; +var isIE6 = /msie 6/i.test(navigator.appVersion); + +if (isIE6) +{ + _ActiveXObject = window.ActiveXObject; + + var xhrObjects = " MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP "; + + window.ActiveXObject = function(name) + { + var error = null; + + try + { + var activeXObject = new _ActiveXObject(name); + } + catch(e) + { + error = e; + } + finally + { + if (!error) + { + if (xhrObjects.indexOf(" " + name + " ") != -1) + return new XMLHttpRequestWrapper(activeXObject); + else + return activeXObject; + } + else + throw error.message; + } + }; +} + +// ************************************************************************************************ + +// Register the XMLHttpRequestWrapper for non-IE6 browsers +if (!isIE6) +{ + var _XMLHttpRequest = XMLHttpRequest; + window.XMLHttpRequest = function() + { + return new XMLHttpRequestWrapper(); + }; +} + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var reIgnore = /about:|javascript:|resource:|chrome:|jar:/; +var layoutInterval = 300; +var indentWidth = 18; + +var cacheSession = null; +var contexts = new Array(); +var panelName = "net"; +var maxQueueRequests = 500; +//var panelBar1 = $("fbPanelBar1"); // chrome not available at startup +var activeRequests = []; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var mimeExtensionMap = +{ + "txt": "text/plain", + "html": "text/html", + "htm": "text/html", + "xhtml": "text/html", + "xml": "text/xml", + "css": "text/css", + "js": "application/x-javascript", + "jss": "application/x-javascript", + "jpg": "image/jpg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "png": "image/png", + "bmp": "image/bmp", + "swf": "application/x-shockwave-flash", + "flv": "video/x-flv" +}; + +var fileCategories = +{ + "undefined": 1, + "html": 1, + "css": 1, + "js": 1, + "xhr": 1, + "image": 1, + "flash": 1, + "txt": 1, + "bin": 1 +}; + +var textFileCategories = +{ + "txt": 1, + "html": 1, + "xhr": 1, + "css": 1, + "js": 1 +}; + +var binaryFileCategories = +{ + "bin": 1, + "flash": 1 +}; + +var mimeCategoryMap = +{ + "text/plain": "txt", + "application/octet-stream": "bin", + "text/html": "html", + "text/xml": "html", + "text/css": "css", + "application/x-javascript": "js", + "text/javascript": "js", + "application/javascript" : "js", + "image/jpeg": "image", + "image/jpg": "image", + "image/gif": "image", + "image/png": "image", + "image/bmp": "image", + "application/x-shockwave-flash": "flash", + "video/x-flv": "flash" +}; + +var binaryCategoryMap = +{ + "image": 1, + "flash" : 1 +}; + +// ************************************************************************************************ + +/** + * @module Represents a module object for the Net panel. This object is derived + * from Firebug.ActivableModule in order to support activation (enable/disable). + * This allows to avoid (performance) expensive features if the functionality is not necessary + * for the user. + */ +Firebug.NetMonitor = extend(Firebug.ActivableModule, +{ + dispatchName: "netMonitor", + + clear: function(context) + { + // The user pressed a Clear button so, remove content of the panel... + var panel = context.getPanel(panelName, true); + if (panel) + panel.clear(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + return; + + this.panelName = panelName; + + Firebug.ActivableModule.initialize.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + // HTTP observer must be registered now (and not in monitorContext, since if a + // page is opened in a new tab the top document request would be missed otherwise. + NetHttpObserver.registerObserver(); + NetHttpActivityObserver.registerObserver(); + + Firebug.Debugger.addListener(this.DebuggerListener); + }, + + shutdown: function() + { + return; + + prefs.removeObserver(Firebug.prefDomain, this, false); + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + + NetHttpObserver.unregisterObserver(); + NetHttpActivityObserver.unregisterObserver(); + + Firebug.Debugger.removeListener(this.DebuggerListener); + } +}); + + +/** + * @domplate Represents a template that is used to reneder detailed info about a request. + * This template is rendered when a request is expanded. + */ +Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep, new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoBody", _repObject: "$file"}, + TAG("$infoTabs", {file: "$file"}), + TAG("$infoBodies", {file: "$file"}) + ), + + infoTabs: + DIV({"class": "netInfoTabs focusRow subFocusRow", "role": "tablist"}, + A({"class": "netInfoParamsTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Params", + $collapsed: "$file|hideParams"}, + $STR("URLParameters") + ), + A({"class": "netInfoHeadersTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Headers"}, + $STR("Headers") + ), + A({"class": "netInfoPostTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Post", + $collapsed: "$file|hidePost"}, + $STR("Post") + ), + A({"class": "netInfoPutTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Put", + $collapsed: "$file|hidePut"}, + $STR("Put") + ), + A({"class": "netInfoResponseTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Response", + $collapsed: "$file|hideResponse"}, + $STR("Response") + ), + A({"class": "netInfoCacheTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Cache", + $collapsed: "$file|hideCache"}, + $STR("Cache") + ), + A({"class": "netInfoHtmlTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Html", + $collapsed: "$file|hideHtml"}, + $STR("HTML") + ) + ), + + infoBodies: + DIV({"class": "netInfoBodies outerFocusRow"}, + TABLE({"class": "netInfoParamsText netInfoText netInfoParamsTable", "role": "tabpanel", + cellpadding: 0, cellspacing: 0}, TBODY()), + DIV({"class": "netInfoHeadersText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPostText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPutText netInfoText", "role": "tabpanel"}), + PRE({"class": "netInfoResponseText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoCacheText netInfoText", "role": "tabpanel"}, + TABLE({"class": "netInfoCacheTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("Cache")}) + ) + ), + DIV({"class": "netInfoHtmlText netInfoText", "role": "tabpanel"}, + IFRAME({"class": "netInfoHtmlPreview", "role": "document"}) + ) + ), + + headerDataTag: + FOR("param", "$headers", + TR({"role": "listitem"}, + TD({"class": "netInfoParamName", "role": "presentation"}, + TAG("$param|getNameTag", {param: "$param"}) + ), + TD({"class": "netInfoParamValue", "role": "list", "aria-label": "$param.name"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class": "focusRow subFocusRow", "role": "listitem"}, "$line") + ) + ) + ) + ), + + customTab: + A({"class": "netInfo$tabId\\Tab netInfoTab", onclick: "$onClickTab", view: "$tabId", "role": "tab"}, + "$tabTitle" + ), + + customBody: + DIV({"class": "netInfo$tabId\\Text netInfoText", "role": "tabpanel"}), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + nameTag: + SPAN("$param|getParamName"), + + nameWithTooltipTag: + SPAN({title: "$param.name"}, "$param|getParamName"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getNameTag: function(param) + { + return (this.getParamName(param) == param.name) ? this.nameTag : this.nameWithTooltipTag; + }, + + getParamName: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + name = name.substr(0, limit) + "..."; + return name; + }, + + getParamTitle: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + return name; + return ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + hideParams: function(file) + { + return !file.urlParams || !file.urlParams.length; + }, + + hidePost: function(file) + { + return file.method.toUpperCase() != "POST"; + }, + + hidePut: function(file) + { + return file.method.toUpperCase() != "PUT"; + }, + + hideResponse: function(file) + { + return false; + //return file.category in binaryFileCategories; + }, + + hideCache: function(file) + { + return true; + //xxxHonza: I don't see any reason why not to display the cache also info for images. + return !file.cacheEntry; // || file.category=="image"; + }, + + hideHtml: function(file) + { + return (file.mimeType != "text/html") && (file.mimeType != "application/xhtml+xml"); + }, + + onClickTab: function(event) + { + this.selectTab(event.currentTarget || event.srcElement); + }, + + getParamValueIterator: function(param) + { + // TODO: xxxpedro console2 + return param.value; + + // This value is inserted into CODE element and so, make sure the HTML isn't escaped (1210). + // This is why the second parameter is true. + // The CODE (with style white-space:pre) element preserves whitespaces so they are + // displayed the same, as they come from the server (1194). + // In case of a long header values of post parameters the value must be wrapped (2105). + return wrapText(param.value, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + appendTab: function(netInfoBox, tabId, tabTitle) + { + // Create new tab and body. + var args = {tabId: tabId, tabTitle: tabTitle}; + ///this.customTab.append(args, netInfoBox.getElementsByClassName("netInfoTabs").item(0)); + ///this.customBody.append(args, netInfoBox.getElementsByClassName("netInfoBodies").item(0)); + this.customTab.append(args, $$(".netInfoTabs", netInfoBox)[0]); + this.customBody.append(args, $$(".netInfoBodies", netInfoBox)[0]); + }, + + selectTabByName: function(netInfoBox, tabName) + { + var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab"); + if (tab) + this.selectTab(tab); + }, + + selectTab: function(tab) + { + var view = tab.getAttribute("view"); + + var netInfoBox = getAncestorByClass(tab, "netInfoBody"); + + var selectedTab = netInfoBox.selectedTab; + + if (selectedTab) + { + //netInfoBox.selectedText.removeAttribute("selected"); + removeClass(netInfoBox.selectedText, "netInfoTextSelected"); + + removeClass(selectedTab, "netInfoTabSelected"); + //selectedTab.removeAttribute("selected"); + selectedTab.setAttribute("aria-selected", "false"); + } + + var textBodyName = "netInfo" + view + "Text"; + + selectedTab = netInfoBox.selectedTab = tab; + + netInfoBox.selectedText = $$("."+textBodyName, netInfoBox)[0]; + //netInfoBox.selectedText = netInfoBox.getElementsByClassName(textBodyName).item(0); + + //netInfoBox.selectedText.setAttribute("selected", "true"); + setClass(netInfoBox.selectedText, "netInfoTextSelected"); + + setClass(selectedTab, "netInfoTabSelected"); + selectedTab.setAttribute("selected", "true"); + selectedTab.setAttribute("aria-selected", "true"); + + var file = Firebug.getRepObject(netInfoBox); + + //var context = Firebug.getElementPanel(netInfoBox).context; + var context = Firebug.chrome; + + this.updateInfo(netInfoBox, file, context); + }, + + updateInfo: function(netInfoBox, file, context) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.updateInfo; file", file); + + if (!netInfoBox) + { + if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS) + FBTrace.sysout("net.updateInfo; ERROR netInfo == null " + file.href, file); + return; + } + + var tab = netInfoBox.selectedTab; + + if (hasClass(tab, "netInfoParamsTab")) + { + if (file.urlParams && !netInfoBox.urlParamsPresented) + { + netInfoBox.urlParamsPresented = true; + this.insertHeaderRows(netInfoBox, file.urlParams, "Params"); + } + } + + else if (hasClass(tab, "netInfoHeadersTab")) + { + var headersText = $$(".netInfoHeadersText", netInfoBox)[0]; + //var headersText = netInfoBox.getElementsByClassName("netInfoHeadersText").item(0); + + if (file.responseHeaders && !netInfoBox.responseHeadersPresented) + { + netInfoBox.responseHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.responseHeaders, "ResponseHeaders"); + } + + if (file.requestHeaders && !netInfoBox.requestHeadersPresented) + { + netInfoBox.requestHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.requestHeaders, "RequestHeaders"); + } + } + + else if (hasClass(tab, "netInfoPostTab")) + { + if (!netInfoBox.postPresented) + { + netInfoBox.postPresented = true; + //var postText = netInfoBox.getElementsByClassName("netInfoPostText").item(0); + var postText = $$(".netInfoPostText", netInfoBox)[0]; + NetInfoPostData.render(context, postText, file); + } + } + + else if (hasClass(tab, "netInfoPutTab")) + { + if (!netInfoBox.putPresented) + { + netInfoBox.putPresented = true; + //var putText = netInfoBox.getElementsByClassName("netInfoPutText").item(0); + var putText = $$(".netInfoPutText", netInfoBox)[0]; + NetInfoPostData.render(context, putText, file); + } + } + + else if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented) + { + ///var responseTextBox = netInfoBox.getElementsByClassName("netInfoResponseText").item(0); + var responseTextBox = $$(".netInfoResponseText", netInfoBox)[0]; + if (file.category == "image") + { + netInfoBox.responsePresented = true; + + var responseImage = netInfoBox.ownerDocument.createElement("img"); + responseImage.src = file.href; + + clearNode(responseTextBox); + responseTextBox.appendChild(responseImage, responseTextBox); + } + else ///if (!(binaryCategoryMap.hasOwnProperty(file.category))) + { + this.setResponseText(file, netInfoBox, responseTextBox, context); + } + } + + else if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented) + { + var responseTextBox = netInfoBox.getElementsByClassName("netInfoCacheText").item(0); + if (file.cacheEntry) { + netInfoBox.cachePresented = true; + this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache"); + } + } + + else if (hasClass(tab, "netInfoHtmlTab") && file.loaded && !netInfoBox.htmlPresented) + { + netInfoBox.htmlPresented = true; + + var text = Utils.getResponseText(file, context); + + ///var iframe = netInfoBox.getElementsByClassName("netInfoHtmlPreview").item(0); + var iframe = $$(".netInfoHtmlPreview", netInfoBox)[0]; + + ///iframe.contentWindow.document.body.innerHTML = text; + + // TODO: xxxpedro net - remove scripts + var reScript = //gi; + + text = text.replace(reScript, ""); + + iframe.contentWindow.document.write(text); + iframe.contentWindow.document.close(); + } + + // Notify listeners about update so, content of custom tabs can be updated. + dispatch(NetInfoBody.fbListeners, "updateTabBody", [netInfoBox, file, context]); + }, + + setResponseText: function(file, netInfoBox, responseTextBox, context) + { + //********************************************** + //********************************************** + //********************************************** + netInfoBox.responsePresented = true; + // line breaks somehow are different in IE + // make this only once in the initialization? we don't have net panels and modules yet. + if (isIE) + responseTextBox.style.whiteSpace = "nowrap"; + + responseTextBox[ + typeof responseTextBox.textContent != "undefined" ? + "textContent" : + "innerText" + ] = file.responseText; + + return; + //********************************************** + //********************************************** + //********************************************** + + // Get response text and make sure it doesn't exceed the max limit. + var text = Utils.getResponseText(file, context); + var limit = Firebug.netDisplayedResponseLimit + 15; + var limitReached = text ? (text.length > limit) : false; + if (limitReached) + text = text.substr(0, limit) + "..."; + + // Insert the response into the UI. + if (text) + insertWrappedText(text, responseTextBox); + else + insertWrappedText("", responseTextBox); + + // Append a message informing the user that the response isn't fully displayed. + if (limitReached) + { + var object = { + text: $STR("net.responseSizeLimitMessage"), + onClickLink: function() { + var panel = context.getPanel("net", true); + panel.openResponseInTab(file); + } + }; + Firebug.NetMonitor.ResponseSizeLimit.append(object, responseTextBox); + } + + netInfoBox.responsePresented = true; + + if (FBTrace.DBG_NET) + FBTrace.sysout("net.setResponseText; response text updated"); + }, + + insertHeaderRows: function(netInfoBox, headers, tableName, rowName) + { + if (!headers.length) + return; + + var headersTable = $$(".netInfo"+tableName+"Table", netInfoBox)[0]; + //var headersTable = netInfoBox.getElementsByClassName("netInfo"+tableName+"Table").item(0); + var tbody = getChildByClass(headersTable, "netInfo" + rowName + "Body"); + if (!tbody) + tbody = headersTable.firstChild; + var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title"); + + this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody); + removeClass(titleRow, "collapsed"); + } +}); + +var NetInfoBody = Firebug.NetMonitor.NetInfoBody; + +// ************************************************************************************************ + +/** + * @domplate Used within the Net panel to display raw source of request and response headers + * as well as pretty-formatted summary of these headers. + */ +Firebug.NetMonitor.NetInfoHeaders = domplate(Firebug.Rep, //new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoHeadersTable", "role": "tabpanel"}, + DIV({"class": "netInfoHeadersGroup netInfoResponseHeadersTitle"}, + SPAN($STR("ResponseHeaders")), + SPAN({"class": "netHeadersViewSource response collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "ResponseHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoResponseHeadersBody", "role": "list", + "aria-label": $STR("ResponseHeaders")}) + ), + DIV({"class": "netInfoHeadersGroup netInfoRequestHeadersTitle"}, + SPAN($STR("RequestHeaders")), + SPAN({"class": "netHeadersViewSource request collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "RequestHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoRequestHeadersBody", "role": "list", + "aria-label": $STR("RequestHeaders")}) + ) + ), + + sourceTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + PRE({"class": "source"}) + ) + ), + + onViewSource: function(event) + { + var target = event.target; + var requestHeaders = (target.rowName == "RequestHeaders"); + + var netInfoBox = getAncestorByClass(target, "netInfoBody"); + var file = netInfoBox.repObject; + + if (target.sourceDisplayed) + { + var headers = requestHeaders ? file.requestHeaders : file.responseHeaders; + this.insertHeaderRows(netInfoBox, headers, target.rowName); + target.innerHTML = $STR("net.headers.view source"); + } + else + { + var source = requestHeaders ? file.requestHeadersText : file.responseHeadersText; + this.insertSource(netInfoBox, source, target.rowName); + target.innerHTML = $STR("net.headers.pretty print"); + } + + target.sourceDisplayed = !target.sourceDisplayed; + + cancelEvent(event); + }, + + insertSource: function(netInfoBox, source, rowName) + { + // This breaks copy to clipboard. + //if (source) + // source = source.replace(/\r\n/gm, "\\r\\n\r\n"); + + ///var tbody = netInfoBox.getElementsByClassName("netInfo" + rowName + "Body").item(0); + var tbody = $$(".netInfo" + rowName + "Body", netInfoBox)[0]; + var node = this.sourceTag.replace({}, tbody); + ///var sourceNode = node.getElementsByClassName("source").item(0); + var sourceNode = $$(".source", node)[0]; + sourceNode.innerHTML = source; + }, + + insertHeaderRows: function(netInfoBox, headers, rowName) + { + var headersTable = $$(".netInfoHeadersTable", netInfoBox)[0]; + var tbody = $$(".netInfo" + rowName + "Body", headersTable)[0]; + + //var headersTable = netInfoBox.getElementsByClassName("netInfoHeadersTable").item(0); + //var tbody = headersTable.getElementsByClassName("netInfo" + rowName + "Body").item(0); + + clearNode(tbody); + + if (!headers.length) + return; + + NetInfoBody.headerDataTag.insertRows({headers: headers}, tbody); + + var titleRow = getChildByClass(headersTable, "netInfo" + rowName + "Title"); + removeClass(titleRow, "collapsed"); + }, + + init: function(parent) + { + var rootNode = this.tag.append({}, parent); + + var netInfoBox = getAncestorByClass(parent, "netInfoBody"); + var file = netInfoBox.repObject; + + var viewSource; + + viewSource = $$(".request", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource request").item(0); + if (file.requestHeadersText) + removeClass(viewSource, "collapsed"); + + viewSource = $$(".response", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource response").item(0); + if (file.responseHeadersText) + removeClass(viewSource, "collapsed"); + }, + + renderHeaders: function(parent, headers, rowName) + { + if (!parent.firstChild) + this.init(parent); + + this.insertHeaderRows(parent, headers, rowName); + } +}); + +var NetInfoHeaders = Firebug.NetMonitor.NetInfoHeaders; + +// ************************************************************************************************ + +/** + * @domplate Represents posted data within request info (the info, which is visible when + * a request entry is expanded. This template renders content of the Post tab. + */ +Firebug.NetMonitor.NetInfoPostData = domplate(Firebug.Rep, /*new Firebug.Listener(),*/ +{ + // application/x-www-form-urlencoded + paramsTable: + TABLE({"class": "netInfoPostParamsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parameters")}, + TR({"class": "netInfoPostParamsTitle", "role": "presentation"}, + TD({colspan: 3, "role": "presentation"}, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parameters"), + SPAN({"class": "netInfoPostContentType"}, + "application/x-www-form-urlencoded" + ) + ) + ) + ) + ) + ), + + // multipart/form-data + partsTable: + TABLE({"class": "netInfoPostPartsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parts")}, + TR({"class": "netInfoPostPartsTitle", "role": "presentation"}, + TD({colspan: 2, "role":"presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parts"), + SPAN({"class": "netInfoPostContentType"}, + "multipart/form-data" + ) + ) + ) + ) + ) + ), + + // application/json + jsonTable: + TABLE({"class": "netInfoPostJSONTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + ///TBODY({"role": "list", "aria-label": $STR("jsonviewer.tab.JSON")}, + TBODY({"role": "list", "aria-label": $STR("JSON")}, + TR({"class": "netInfoPostJSONTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + ///$STR("jsonviewer.tab.JSON") + $STR("JSON") + ) + ) + ), + TR( + TD({"class": "netInfoPostJSONBody"}) + ) + ) + ), + + // application/xml + xmlTable: + TABLE({"class": "netInfoPostXMLTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("xmlviewer.tab.XML")}, + TR({"class": "netInfoPostXMLTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("xmlviewer.tab.XML") + ) + ) + ), + TR( + TD({"class": "netInfoPostXMLBody"}) + ) + ) + ), + + sourceTable: + TABLE({"class": "netInfoPostSourceTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Source")}, + TR({"class": "netInfoPostSourceTitle", "role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + DIV({"class": "netInfoPostSource"}, + $STR("net.label.Source") + ) + ) + ) + ) + ), + + sourceBodyTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class":"focusRow subFocusRow" , "role": "listitem"},"$line") + ) + ) + ), + + getParamValueIterator: function(param) + { + return NetInfoBody.getParamValueIterator(param); + }, + + render: function(context, parentNode, file) + { + //debugger; + var spy = getAncestorByClass(parentNode, "spyHead"); + var spyObject = spy.repObject; + var data = spyObject.data; + + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + var contentType = file.mimeType; + + ///var text = Utils.getPostText(file, context, true); + ///if (text == undefined) + /// return; + + ///if (Utils.isURLEncodedRequest(file, context)) + // fake Utils.isURLEncodedRequest identification + if (contentType && contentType == "application/x-www-form-urlencoded" || + data && data.indexOf("=") != -1) + { + ///var lines = text.split("\n"); + ///var params = parseURLEncodedText(lines[lines.length-1]); + var params = parseURLEncodedTextArray(data); + if (params) + this.insertParameters(parentNode, params); + } + + ///if (Utils.isMultiPartRequest(file, context)) + ///{ + /// var data = this.parseMultiPartText(file, context); + /// if (data) + /// this.insertParts(parentNode, data); + ///} + + // moved to the top + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + + ///if (Firebug.JSONViewerModel.isJSON(contentType)) + var jsonData = { + responseText: data + }; + + if (Firebug.JSONViewerModel.isJSON(contentType, data)) + ///this.insertJSON(parentNode, file, context); + this.insertJSON(parentNode, jsonData, context); + + ///if (Firebug.XMLViewerModel.isXML(contentType)) + /// this.insertXML(parentNode, file, context); + + ///var postText = Utils.getPostText(file, context); + ///postText = Utils.formatPostText(postText); + var postText = data; + if (postText) + this.insertSource(parentNode, postText); + }, + + insertParameters: function(parentNode, params) + { + if (!params || !params.length) + return; + + var paramTable = this.paramsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostParamsTitle", paramTable)[0]; + //var paramTable = this.paramsTable.append(null, parentNode); + //var row = paramTable.getElementsByClassName("netInfoPostParamsTitle").item(0); + + var tbody = paramTable.getElementsByTagName("tbody")[0]; + + NetInfoBody.headerDataTag.insertRows({headers: params}, row); + }, + + insertParts: function(parentNode, data) + { + if (!data.params || !data.params.length) + return; + + var partsTable = this.partsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostPartsTitle", paramTable)[0]; + //var partsTable = this.partsTable.append(null, parentNode); + //var row = partsTable.getElementsByClassName("netInfoPostPartsTitle").item(0); + + NetInfoBody.headerDataTag.insertRows({headers: data.params}, row); + }, + + insertJSON: function(parentNode, file, context) + { + ///var text = Utils.getPostText(file, context); + var text = file.responseText; + ///var data = parseJSONString(text, "http://" + file.request.originalURI.host); + var data = parseJSONString(text); + if (!data) + return; + + ///var jsonTable = this.jsonTable.append(null, parentNode); + var jsonTable = this.jsonTable.append({}, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostJSONBody").item(0); + var jsonBody = $$(".netInfoPostJSONBody", jsonTable)[0]; + + if (!this.toggles) + this.toggles = {}; + + Firebug.DOMPanel.DirTable.tag.replace( + {object: data, toggles: this.toggles}, jsonBody); + }, + + insertXML: function(parentNode, file, context) + { + var text = Utils.getPostText(file, context); + + var jsonTable = this.xmlTable.append(null, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostXMLBody").item(0); + var jsonBody = $$(".netInfoPostXMLBody", jsonTable)[0]; + + Firebug.XMLViewerModel.insertXML(jsonBody, text); + }, + + insertSource: function(parentNode, text) + { + var sourceTable = this.sourceTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostSourceTitle", sourceTable)[0]; + //var sourceTable = this.sourceTable.append(null, parentNode); + //var row = sourceTable.getElementsByClassName("netInfoPostSourceTitle").item(0); + + var param = {value: [text]}; + this.sourceBodyTag.insertRows({param: param}, row); + }, + + parseMultiPartText: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text == undefined) + return null; + + FBTrace.sysout("net.parseMultiPartText; boundary: ", text); + + var boundary = text.match(/\s*boundary=\s*(.*)/)[1]; + + var divider = "\r\n\r\n"; + var bodyStart = text.indexOf(divider); + var body = text.substr(bodyStart + divider.length); + + var postData = {}; + postData.mimeType = "multipart/form-data"; + postData.params = []; + + var parts = body.split("--" + boundary); + for (var i=0; i 1) ? m[1] : "", + value: trim(part[1]) + }); + } + + return postData; + } +}); + +var NetInfoPostData = Firebug.NetMonitor.NetInfoPostData; + +// ************************************************************************************************ + + +// TODO: xxxpedro net i18n +var $STRP = function(a){return a;}; + +Firebug.NetMonitor.NetLimit = domplate(Firebug.Rep, +{ + collapsed: true, + + tableTag: + DIV( + TABLE({width: "100%", cellpadding: 0, cellspacing: 0}, + TBODY() + ) + ), + + limitTag: + TR({"class": "netRow netLimitRow", $collapsed: "$isCollapsed"}, + TD({"class": "netCol netLimitCol", colspan: 6}, + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY( + TR( + TD( + SPAN({"class": "netLimitLabel"}, + $STRP("plural.Limit_Exceeded", [0]) + ) + ), + TD({style: "width:100%"}), + TD( + BUTTON({"class": "netLimitButton", title: "$limitPrefsTitle", + onclick: "$onPreferences"}, + $STR("LimitPrefs") + ) + ), + TD(" ") + ) + ) + ) + ) + ), + + isCollapsed: function() + { + return this.collapsed; + }, + + onPreferences: function(event) + { + openNewTab("about:config"); + }, + + updateCounter: function(row) + { + removeClass(row, "collapsed"); + + // Update info within the limit row. + var limitLabel = row.getElementsByClassName("netLimitLabel").item(0); + limitLabel.firstChild.nodeValue = $STRP("plural.Limit_Exceeded", [row.limitInfo.totalCount]); + }, + + createTable: function(parent, limitInfo) + { + var table = this.tableTag.replace({}, parent); + var row = this.createRow(table.firstChild.firstChild, limitInfo); + return [table, row]; + }, + + createRow: function(parent, limitInfo) + { + var row = this.limitTag.insertRows(limitInfo, parent, this)[0]; + row.limitInfo = limitInfo; + return row; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + if (data.indexOf("net.logLimit") != -1) + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = Firebug.getPref(Firebug.prefDomain, "net.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + } +}); + +var NetLimit = Firebug.NetMonitor.NetLimit; + +// ************************************************************************************************ + +Firebug.NetMonitor.ResponseSizeLimit = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "netInfoResponseSizeLimit"}, + SPAN("$object.beforeLink"), + A({"class": "objectLink", onclick: "$onClickLink"}, + "$object.linkText" + ), + SPAN("$object.afterLink") + ), + + reLink: /^(.*)(.*)<\/a>(.*$)/, + append: function(obj, parent) + { + var m = obj.text.match(this.reLink); + return this.tag.append({onClickLink: obj.onClickLink, + object: { + beforeLink: m[1], + linkText: m[2], + afterLink: m[3] + }}, parent, this); + } +}); + +// ************************************************************************************************ +// ************************************************************************************************ + +Firebug.NetMonitor.Utils = +{ + findHeader: function(headers, name) + { + if (!headers) + return null; + + name = name.toLowerCase(); + for (var i = 0; i < headers.length; ++i) + { + var headerName = headers[i].name.toLowerCase(); + if (headerName == name) + return headers[i].value; + } + }, + + formatPostText: function(text) + { + if (text instanceof XMLDocument) + return getElementXML(text.documentElement); + else + return text; + }, + + getPostText: function(file, context, noLimit) + { + if (!file.postText) + { + file.postText = readPostTextFromRequest(file.request, context); + + if (!file.postText && context) + file.postText = readPostTextFromPage(file.href, context); + } + + if (!file.postText) + return file.postText; + + var limit = Firebug.netDisplayedPostBodyLimit; + if (file.postText.length > limit && !noLimit) + { + return cropString(file.postText, limit, + "\n\n... " + $STR("net.postDataSizeLimitMessage") + " ...\n\n"); + } + + return file.postText; + }, + + getResponseText: function(file, context) + { + // The response can be also empty string so, check agains "undefined". + return (typeof(file.responseText) != "undefined")? file.responseText : + context.sourceCache.loadText(file.href, file.method, file); + }, + + isURLEncodedRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded") == 0) + return true; + + // The header value doesn't have to be always exactly "application/x-www-form-urlencoded", + // there can be even charset specified. So, use indexOf rather than just "==". + var headerValue = Utils.findHeader(file.requestHeaders, "content-type"); + if (headerValue && headerValue.indexOf("application/x-www-form-urlencoded") == 0) + return true; + + return false; + }, + + isMultiPartRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: multipart/form-data") == 0) + return true; + return false; + }, + + getMimeType: function(mimeType, uri) + { + if (!mimeType || !(mimeCategoryMap.hasOwnProperty(mimeType))) + { + var ext = getFileExtension(uri); + if (!ext) + return mimeType; + else + { + var extMimeType = mimeExtensionMap[ext.toLowerCase()]; + return extMimeType ? extMimeType : mimeType; + } + } + else + return mimeType; + }, + + getDateFromSeconds: function(s) + { + var d = new Date(); + d.setTime(s*1000); + return d; + }, + + getHttpHeaders: function(request, file) + { + try + { + var http = QI(request, Ci.nsIHttpChannel); + file.status = request.responseStatus; + + // xxxHonza: is there any problem to do this in requestedFile method? + file.method = http.requestMethod; + file.urlParams = parseURLParams(file.href); + file.mimeType = Utils.getMimeType(request.contentType, request.name); + + if (!file.responseHeaders && Firebug.collectHttpHeaders) + { + var requestHeaders = [], responseHeaders = []; + + http.visitRequestHeaders({ + visitHeader: function(name, value) + { + requestHeaders.push({name: name, value: value}); + } + }); + http.visitResponseHeaders({ + visitHeader: function(name, value) + { + responseHeaders.push({name: name, value: value}); + } + }); + + file.requestHeaders = requestHeaders; + file.responseHeaders = responseHeaders; + } + } + catch (exc) + { + // An exception can be throwed e.g. when the request is aborted and + // request.responseStatus is accessed. + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("net.getHttpHeaders FAILS " + file.href, exc); + } + }, + + isXHR: function(request) + { + try + { + var callbacks = request.notificationCallbacks; + var xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null; + if (FBTrace.DBG_NET) + FBTrace.sysout("net.isXHR; " + (xhrRequest != null) + ", " + safeGetName(request)); + + return (xhrRequest != null); + } + catch (exc) + { + } + + return false; + }, + + getFileCategory: function(file) + { + if (file.category) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; current: " + file.category + " for: " + file.href, file); + return file.category; + } + + if (file.isXHR) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; XHR for: " + file.href, file); + return file.category = "xhr"; + } + + if (!file.mimeType) + { + var ext = getFileExtension(file.href); + if (ext) + file.mimeType = mimeExtensionMap[ext.toLowerCase()]; + } + + /*if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; " + mimeCategoryMap[file.mimeType] + + ", mimeType: " + file.mimeType + " for: " + file.href, file);*/ + + if (!file.mimeType) + return ""; + + // Solve cases when charset is also specified, eg "text/html; charset=UTF-8". + var mimeType = file.mimeType; + if (mimeType) + mimeType = mimeType.split(";")[0]; + + return (file.category = mimeCategoryMap[mimeType]); + } +}; + +var Utils = Firebug.NetMonitor.Utils; + +// ************************************************************************************************ + +//Firebug.registerRep(Firebug.NetMonitor.NetRequestTable); +//Firebug.registerActivableModule(Firebug.NetMonitor); +//Firebug.registerPanel(NetPanel); + +Firebug.registerModule(Firebug.NetMonitor); +//Firebug.registerRep(Firebug.NetMonitor.BreakpointRep); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +// List of contexts with XHR spy attached. +var contexts = []; + +// ************************************************************************************************ +// Spy Module + +/** + * @module Represents a XHR Spy module. The main purpose of the XHR Spy feature is to monitor + * XHR activity of the current page and create appropriate log into the Console panel. + * This feature can be controlled by an option Show XMLHttpRequests (from within the + * console panel). + * + * The module is responsible for attaching/detaching a HTTP Observers when Firebug is + * activated/deactivated for a site. + */ +Firebug.Spy = extend(Firebug.Module, +/** @lends Firebug.Spy */ +{ + dispatchName: "spy", + + initialize: function() + { + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + Firebug.Module.initialize.apply(this, arguments); + }, + + shutdown: function() + { + Firebug.Module.shutdown.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + }, + + initContext: function(context) + { + context.spies = []; + + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, context.window); + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.initContext " + contexts.length + " ", context.getName()); + }, + + destroyContext: function(context) + { + // For any spies that are in progress, remove our listeners so that they don't leak + this.detachObserver(context, null); + + if (FBTrace.DBG_SPY && context.spies.length) + FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies (" + + context.spies.length + ") " + context.getName()); + + delete context.spies; + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.destroyContext " + contexts.length + " ", context.getName()); + }, + + watchWindow: function(context, win) + { + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, win); + }, + + unwatchWindow: function(context, win) + { + try + { + // This make sure that the existing context is properly removed from "contexts" array. + this.detachObserver(context, win); + } + catch (ex) + { + // Get exceptions here sometimes, so let's just ignore them + // since the window is going away anyhow + ERROR(ex); + } + }, + + updateOption: function(name, value) + { + // XXXjjb Honza, if Console.isEnabled(context) false, then this can't be called, + // but somehow seems not correct + if (name == "showXMLHttpRequests") + { + var tach = value ? this.attachObserver : this.detachObserver; + for (var i = 0; i < TabWatcher.contexts.length; ++i) + { + var context = TabWatcher.contexts[i]; + iterateWindows(context.window, function(win) + { + tach.apply(this, [context, win]); + }); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Attaching Spy to XHR requests. + + /** + * Returns false if Spy should not be attached to XHRs executed by the specified window. + */ + skipSpy: function(win) + { + if (!win) + return true; + + // Don't attach spy to chrome. + var uri = safeGetWindowLocation(win); + if (uri && (uri.indexOf("about:") == 0 || uri.indexOf("chrome:") == 0)) + return true; + }, + + attachObserver: function(context, win) + { + if (Firebug.Spy.skipSpy(win)) + return; + + for (var i=0; insIHttpChannel. + * Returns null if the request doesn't represent XHR. + */ + getXHR: function(request) + { + // Does also query-interface for nsIHttpChannel. + if (!(request instanceof Ci.nsIHttpChannel)) + return null; + + try + { + var callbacks = request.notificationCallbacks; + return (callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null); + } + catch (exc) + { + if (exc.name == "NS_NOINTERFACE") + { + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.getXHR; Request is not nsIXMLHttpRequest: " + + safeGetRequestName(request)); + } + } + + return null; + } +}); + + + + + +// ************************************************************************************************ + +/* +function getSpyForXHR(request, xhrRequest, context, noCreate) +{ + var spy = null; + + // Iterate all existing spy objects in this context and look for one that is + // already created for this request. + var length = context.spies.length; + for (var i=0; i= 3) + { + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (netInfoBox) + { + netInfoBox.htmlPresented = false; + netInfoBox.responsePresented = false; + } + } + + // If the request is loading update the end time. + if (spy.xhrRequest.readyState == 3) + { + spy.responseTime = spy.endTime - spy.sendTime; + updateTime(spy); + } + + // Request loaded. Get all the info from the request now, just in case the + // XHR would be aborted in the original onReadyStateChange handler. + if (spy.xhrRequest.readyState == 4) + { + // Cumulate response so, multipart response content is properly displayed. + if (SpyHttpActivityObserver.getActivityDistributor()) + spy.responseText += spy.xhrRequest.responseText; + else + { + // xxxHonza: remove from FB 1.6 + if (!spy.responseText) + spy.responseText = spy.xhrRequest.responseText; + } + + // The XHR is loaded now (used also by the activity observer). + spy.loaded = true; + + // Update UI. + updateHttpSpyInfo(spy); + + // Notify Net pane about a request beeing loaded. + // xxxHonza: I don't think this is necessary. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.stopFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); + + // Notify registered listeners about finish of the XHR. + dispatch(Firebug.Spy.fbListeners, "onLoad", [spy.context, spy]); + } + + // Pass the event to the original page handler. + callPageHandler(spy, event, originalHandler); +} + +function onHTTPSpyLoad(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyLoad: " + spy.href, spy); + + // Detach must be done in onLoad (not in onreadystatechange) otherwise + // onAbort would not be handled. + spy.detach(); + + // xxxHonza: Still needed for Fx 3.5 (#502959) + if (!SpyHttpActivityObserver.getActivityDistributor()) + onHTTPSpyReadyStateChange(spy, null); +} + +function onHTTPSpyError(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyError; " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } +} + +function onHTTPSpyAbort(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyAbort: " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } + + spy.statusText = "Aborted"; + updateLogRow(spy); + + // Notify Net pane about a request beeing aborted. + // xxxHonza: the net panel shoud find out this itself. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.abortFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); +} +/**/ + +// ************************************************************************************************ + +/** + * @domplate Represents a template for XHRs logged in the Console panel. The body of the + * log (displayed when expanded) is rendered using {@link Firebug.NetMonitor.NetInfoBody}. + */ + +Firebug.Spy.XHR = domplate(Firebug.Rep, +/** @lends Firebug.Spy.XHR */ + +{ + tag: + DIV({"class": "spyHead", _repObject: "$object"}, + TABLE({"class": "spyHeadTable focusRow outerFocusRow", cellpadding: 0, cellspacing: 0, + "role": "listitem", "aria-expanded": "false"}, + TBODY({"role": "presentation"}, + TR({"class": "spyRow"}, + TD({"class": "spyTitleCol spyCol", onclick: "$onToggleBody"}, + DIV({"class": "spyTitle"}, + "$object|getCaption" + ), + DIV({"class": "spyFullTitle spyTitle"}, + "$object|getFullUri" + ) + ), + TD({"class": "spyCol"}, + DIV({"class": "spyStatus"}, "$object|getStatus") + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyIcon"}) + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyTime"}) + ), + TD({"class": "spyCol"}, + TAG(FirebugReps.SourceLink.tag, {object: "$object.sourceLink"}) + ) + ) + ) + ) + ), + + getCaption: function(spy) + { + return spy.method.toUpperCase() + " " + cropString(spy.getURL(), 100); + }, + + getFullUri: function(spy) + { + return spy.method.toUpperCase() + " " + spy.getURL(); + }, + + getStatus: function(spy) + { + var text = ""; + if (spy.statusCode) + text += spy.statusCode + " "; + + if (spy.statusText) + return text += spy.statusText; + + return text; + }, + + onToggleBody: function(event) + { + var target = event.currentTarget || event.srcElement; + var logRow = getAncestorByClass(target, "logRow-spy"); + + if (isLeftClick(event)) + { + toggleClass(logRow, "opened"); + + var spy = getChildByClass(logRow, "spyHead").repObject; + var spyHeadTable = getAncestorByClass(target, "spyHeadTable"); + + if (hasClass(logRow, "opened")) + { + updateHttpSpyInfo(spy, logRow); + if (spyHeadTable) + spyHeadTable.setAttribute('aria-expanded', 'true'); + } + else + { + //var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + //dispatch(Firebug.NetMonitor.NetInfoBody.fbListeners, "destroyTabBody", [netInfoBox, spy]); + //if (spyHeadTable) + // spyHeadTable.setAttribute('aria-expanded', 'false'); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(spy) + { + copyToClipboard(spy.getURL()); + }, + + copyParams: function(spy) + { + var text = spy.postText; + if (!text) + return; + + var url = reEncodeURL(spy, text, true); + copyToClipboard(url); + }, + + copyResponse: function(spy) + { + copyToClipboard(spy.responseText); + }, + + openInTab: function(spy) + { + openNewTab(spy.getURL(), spy.postText); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object) + { + // TODO: xxxpedro spy xhr + return false; + + return object instanceof Firebug.Spy.XMLHttpRequestSpy; + }, + + browseObject: function(spy, context) + { + var url = spy.getURL(); + openNewTab(url); + return true; + }, + + getRealObject: function(spy, context) + { + return spy.xhrRequest; + }, + + getContextMenuItems: function(spy) + { + var items = [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, spy) } + ]; + + if (spy.postText) + { + items.push( + {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, spy) } + ); + } + + items.push( + {label: "CopyResponse", command: bindFixed(this.copyResponse, this, spy) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, spy) } + ); + + return items; + } +}); + +// ************************************************************************************************ + +function updateTime(spy) +{ + var timeBox = spy.logRow.getElementsByClassName("spyTime").item(0); + if (spy.responseTime) + timeBox.textContent = " " + formatTime(spy.responseTime); +} + +function updateLogRow(spy) +{ + updateTime(spy); + + var statusBox = spy.logRow.getElementsByClassName("spyStatus").item(0); + statusBox.textContent = Firebug.Spy.XHR.getStatus(spy); + + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "loaded"); + + try + { + var errorRange = Math.floor(spy.xhrRequest.status/100); + if (errorRange == 4 || errorRange == 5) + setClass(spy.logRow, "error"); + } + catch (exc) + { + } +} + +var updateHttpSpyInfo = function updateHttpSpyInfo(spy, logRow) +{ + if (!spy.logRow && logRow) + spy.logRow = logRow; + + if (!spy.logRow || !hasClass(spy.logRow, "opened")) + return; + + if (!spy.params) + //spy.params = parseURLParams(spy.href+""); + spy.params = parseURLParams(spy.href+""); + + if (!spy.requestHeaders) + spy.requestHeaders = getRequestHeaders(spy); + + if (!spy.responseHeaders && spy.loaded) + spy.responseHeaders = getResponseHeaders(spy); + + var template = Firebug.NetMonitor.NetInfoBody; + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (!netInfoBox) + { + var head = getChildByClass(spy.logRow, "spyHead"); + netInfoBox = template.tag.append({"file": spy}, head); + dispatch(template.fbListeners, "initTabBody", [netInfoBox, spy]); + template.selectTabByName(netInfoBox, "Response"); + } + else + { + template.updateInfo(netInfoBox, spy, spy.context); + } +}; + + + +// ************************************************************************************************ + +function getRequestHeaders(spy) +{ + var headers = []; + + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitRequestHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + + return headers; +} + +function getResponseHeaders(spy) +{ + var headers = []; + + try + { + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitResponseHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + } + catch (exc) + { + if (FBTrace.DBG_SPY || FBTrace.DBG_ERRORS) + FBTrace.sysout("spy.getResponseHeaders; EXCEPTION " + + safeGetRequestName(spy.request), exc); + } + + return headers; +} + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.Spy); +//Firebug.registerRep(Firebug.Spy.XHR); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ + +// List of JSON content types. +var contentTypes = +{ + "text/plain": 1, + "text/javascript": 1, + "text/x-javascript": 1, + "text/json": 1, + "text/x-json": 1, + "application/json": 1, + "application/x-json": 1, + "application/javascript": 1, + "application/x-javascript": 1, + "application/json-rpc": 1 +}; + +// ************************************************************************************************ +// Model implementation + +Firebug.JSONViewerModel = extend(Firebug.Module, +{ + dispatchName: "jsonViewer", + initialize: function() + { + Firebug.NetMonitor.NetInfoBody.addListener(this); + + // Used by Firebug.DOMPanel.DirTable domplate. + this.toggles = {}; + }, + + shutdown: function() + { + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody", infoBox); + + // Let listeners to parse the JSON. + dispatch(this.fbListeners, "onParseJSON", [file]); + + // The JSON is still no there, try to parse most common cases. + if (!file.jsonObject) + { + ///if (this.isJSON(safeGetContentType(file.request), file.responseText)) + if (this.isJSON(file.mimeType, file.responseText)) + file.jsonObject = this.parseJSON(file); + } + + // The jsonObject is created so, the JSON tab can be displayed. + if (file.jsonObject && hasProperties(file.jsonObject)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "JSON", + ///$STR("jsonviewer.tab.JSON")); + $STR("JSON")); + + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody; JSON object available " + + (typeof(file.jsonObject) != "undefined"), file.jsonObject); + } + }, + + isJSON: function(contentType, data) + { + // Workaround for JSON responses without proper content type + // Let's consider all responses starting with "{" as JSON. In the worst + // case there will be an exception when parsing. This means that no-JSON + // responses (and post data) (with "{") can be parsed unnecessarily, + // which represents a little overhead, but this happens only if the request + // is actually expanded by the user in the UI (Net & Console panels). + + ///var responseText = data ? trimLeft(data) : null; + ///if (responseText && responseText.indexOf("{") == 0) + /// return true; + var responseText = data ? trim(data) : null; + if (responseText && responseText.indexOf("{") == 0) + return true; + + if (!contentType) + return false; + + contentType = contentType.split(";")[0]; + contentType = trim(contentType); + return contentTypes[contentType]; + }, + + // Update listener for TabView + updateTabBody: function(infoBox, file, context) + { + var tab = infoBox.selectedTab; + ///var tabBody = infoBox.getElementsByClassName("netInfoJSONText").item(0); + var tabBody = $$(".netInfoJSONText", infoBox)[0]; + if (!hasClass(tab, "netInfoJSONTab") || tabBody.updated) + return; + + tabBody.updated = true; + + if (file.jsonObject) { + Firebug.DOMPanel.DirTable.tag.replace( + {object: file.jsonObject, toggles: this.toggles}, tabBody); + } + }, + + parseJSON: function(file) + { + var jsonString = new String(file.responseText); + ///return parseJSONString(jsonString, "http://" + file.request.originalURI.host); + return parseJSONString(jsonString); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.JSONViewerModel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +// List of XML related content types. +var xmlContentTypes = +[ + "text/xml", + "application/xml", + "application/xhtml+xml", + "application/rss+xml", + "application/atom+xml",, + "application/vnd.mozilla.maybe.feed", + "application/rdf+xml", + "application/vnd.mozilla.xul+xml" +]; + +// ************************************************************************************************ +// Model implementation + +/** + * @module Implements viewer for XML based network responses. In order to create a new + * tab wihin network request detail, a listener is registered into + * Firebug.NetMonitor.NetInfoBody object. + */ +Firebug.XMLViewerModel = extend(Firebug.Module, +{ + dispatchName: "xmlViewer", + + initialize: function() + { + ///Firebug.ActivableModule.initialize.apply(this, arguments); + Firebug.Module.initialize.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.addListener(this); + }, + + shutdown: function() + { + ///Firebug.ActivableModule.shutdown.apply(this, arguments); + Firebug.Module.shutdown.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + /** + * Check response's content-type and if it's a XML, create a new tab with XML preview. + */ + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody", infoBox); + + // If the response is XML let's display a pretty preview. + ///if (this.isXML(safeGetContentType(file.request))) + if (this.isXML(file.mimeType, file.responseText)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML", + ///$STR("xmlviewer.tab.XML")); + $STR("XML")); + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody; XML response available"); + } + }, + + isXML: function(contentType) + { + if (!contentType) + return false; + + // Look if the response is XML based. + for (var i=0; i\s*/, ""); + + var div = parentNode.ownerDocument.createElement("div"); + div.innerHTML = xmlText; + + var root = div.getElementsByTagName("*")[0]; + + /*** + var parser = CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser"); + var doc = parser.parseFromString(text, "text/xml"); + var root = doc.documentElement; + + // Error handling + var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml"; + if (root.namespaceURI == nsURI && root.nodeName == "parsererror") + { + this.ParseError.tag.replace({error: { + message: root.firstChild.nodeValue, + source: root.lastChild.textContent + }}, parentNode); + return; + } + /**/ + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc); + + // Override getHidden in these templates. The parsed XML documen is + // hidden, but we want to display it using 'visible' styling. + /* + var templates = [ + Firebug.HTMLPanel.CompleteElement, + Firebug.HTMLPanel.Element, + Firebug.HTMLPanel.TextElement, + Firebug.HTMLPanel.EmptyElement, + Firebug.HTMLPanel.XEmptyElement, + ]; + + var originals = []; + for (var i=0; iFirebug.XMLViewerModel. + */ +Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "xmlInfoError"}, + DIV({"class": "xmlInfoErrorMsg"}, "$error.message"), + PRE({"class": "xmlInfoErrorSource"}, "$error|getSource") + ), + + getSource: function(error) + { + var parts = error.source.split("\n"); + if (parts.length != 2) + return error.source; + + var limit = 50; + var column = parts[1].length; + if (column >= limit) { + parts[0] = "..." + parts[0].substr(column - limit); + parts[1] = "..." + parts[1].substr(column - limit); + } + + if (parts[0].length > 80) + parts[0] = parts[0].substr(0, 80) + "..."; + + return parts.join("\n"); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.XMLViewerModel); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var ElementCache = Firebug.Lite.Cache.Element; +var cacheID = Firebug.Lite.Cache.ID; + +var ignoreHTMLProps = +{ + // ignores the attributes injected by Sizzle, otherwise it will + // be visible on IE (when enumerating element.attributes) + sizcache: 1, + sizset: 1 +}; + +// ignores also the cache property injected by firebug +ignoreHTMLProps[cacheID] = 1; + + +// ************************************************************************************************ +// HTML Module + +Firebug.HTML = extend(Firebug.Module, +{ + appendTreeNode: function(nodeArray, html) + { + var reTrim = /^\s+|\s+$/g; + + if (!nodeArray.length) nodeArray = [nodeArray]; + + for (var n=0, node; node=nodeArray[n]; n++) + { + if (node.nodeType == 1) + { + if (Firebug.ignoreFirebugElements && node.firebugIgnore) continue; + + var uid = ElementCache(node); + var child = node.childNodes; + var childLength = child.length; + + var nodeName = node.nodeName.toLowerCase(); + + var nodeVisible = isVisible(node); + + var hasSingleTextChild = childLength == 1 && node.firstChild.nodeType == 3 && + nodeName != "script" && nodeName != "style"; + + var nodeControl = !hasSingleTextChild && childLength > 0 ? + ('
      ') : ''; + + var isIE = false; + + if(isIE && nodeControl) + html.push(nodeControl); + + if (typeof uid != 'undefined') + html.push( + '
      ', + !isIE && nodeControl ? nodeControl: "", + '<', nodeName, '' + ); + else + html.push( + '
      <', + nodeName, '' + ); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || Firebug.ignoreFirebugElements && + ignoreHTMLProps.hasOwnProperty(attr.nodeName)) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? formatStyles(node.style.cssText) : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + /* + // source code nodes + if (nodeName == 'script' || nodeName == 'style') + { + + if(document.all){ + var src = node.innerHTML+'\n'; + + }else { + var src = '\n'+node.innerHTML+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + '
      '; + } + + html.push('>
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ', + '
      </', + nodeName, + '>
      ', + '
      ' + ); + + + }/**/ + + // Just a single text node child + if (hasSingleTextChild) + { + var value = child[0].nodeValue.replace(reTrim, ''); + if(value) + { + html.push( + '>', + escapeHTML(value), + '</', + nodeName, + '>
      ' + ); + } + else + html.push('/>
      '); // blank text, print as childless node + + } + else if (childLength > 0) + { + html.push('>'); + } + else + html.push('/>'); + + } + else if (node.nodeType == 3) + { + if ( node.parentNode && ( node.parentNode.nodeName.toLowerCase() == "script" || + node.parentNode.nodeName.toLowerCase() == "style" ) ) + { + var value = node.nodeValue.replace(reTrim, ''); + + if(isIE){ + var src = value+'\n'; + + }else { + var src = '\n'+value+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + ''; + } + + html.push('
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ' + ); + + } + else + { + var value = node.nodeValue.replace(reTrim, ''); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + } + } + }, + + appendTreeChildren: function(treeNode) + { + var doc = Firebug.chrome.document; + var uid = treeNode.id; + var parentNode = ElementCache.get(uid); + + if (parentNode.childNodes.length == 0) return; + + var treeNext = treeNode.nextSibling; + var treeParent = treeNode.parentNode; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl nodeMaximized'; + + var html = []; + var children = doc.createElement("div"); + children.className = "nodeChildren"; + this.appendTreeNode(parentNode.childNodes, html); + children.innerHTML = html.join(""); + + treeParent.insertBefore(children, treeNext); + + var closeElement = doc.createElement("div"); + closeElement.className = "objectBox-element"; + closeElement.innerHTML = '</' + + parentNode.nodeName.toLowerCase() + '>' + + treeParent.insertBefore(closeElement, treeNext); + + }, + + removeTreeChildren: function(treeNode) + { + var children = treeNode.nextSibling; + var closeTag = children.nextSibling; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl'; + + children.parentNode.removeChild(children); + closeTag.parentNode.removeChild(closeTag); + }, + + isTreeNodeVisible: function(id) + { + return $(id); + }, + + select: function(el) + { + var id = el && ElementCache(el); + if (id) + this.selectTreeNode(id); + }, + + selectTreeNode: function(id) + { + id = ""+id; + var node, stack = []; + while(id && !this.isTreeNodeVisible(id)) + { + stack.push(id); + + var node = ElementCache.get(id).parentNode; + + if (node) + id = ElementCache(node); + else + break; + } + + stack.push(id); + + while(stack.length > 0) + { + id = stack.pop(); + node = $(id); + + if (stack.length > 0 && ElementCache.get(id).childNodes.length > 0) + this.appendTreeChildren(node); + } + + selectElement(node); + + // TODO: xxxpedro + if (fbPanel1) + fbPanel1.scrollTop = Math.round(node.offsetTop - fbPanel1.clientHeight/2); + } + +}); + +Firebug.registerModule(Firebug.HTML); + +// ************************************************************************************************ +// HTML Panel + +function HTMLPanel(){}; + +HTMLPanel.prototype = extend(Firebug.Panel, +{ + name: "HTML", + title: "HTML", + + options: { + hasSidePanel: true, + //hasToolButtons: true, + isPreRendered: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "4px 3px 1px 15px"; + this.panelNode.style.minWidth = "500px"; + + if (Env.Options.enablePersistent || Firebug.chrome.type != "popup") + this.createUI(); + + if(!this.sidePanelBar.selectedPanel) + { + this.sidePanelBar.selectPanel("css"); + } + }, + + destroy: function() + { + selectedElement = null + fbPanel1 = null; + + selectedSidePanelTS = null; + selectedSidePanelTimer = null; + + Firebug.Panel.destroy.apply(this, arguments); + }, + + createUI: function() + { + var rootNode = Firebug.browser.document.documentElement; + var html = []; + Firebug.HTML.appendTreeNode(rootNode, html); + + this.panelNode.innerHTML = html.join(""); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + addEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = $("fbPanel1"); + + if(!selectedElement) + { + Firebug.HTML.selectTreeNode(ElementCache(Firebug.browser.document.body)); + } + + // TODO: xxxpedro + addEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + addEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + addEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + }, + + shutdown: function() + { + // TODO: xxxpedro + removeEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + removeEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + removeEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + + removeEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = null; + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + reattach: function() + { + // TODO: panel reattach + if(FirebugChrome.selectedHTMLElementId) + Firebug.HTML.selectTreeNode(FirebugChrome.selectedHTMLElementId); + }, + + updateSelection: function(object) + { + var id = ElementCache(object); + + if (id) + { + Firebug.HTML.selectTreeNode(id); + } + } +}); + +Firebug.registerPanel(HTMLPanel); + +// ************************************************************************************************ + +var formatStyles = function(styles) +{ + return isIE ? + // IE return CSS property names in upper case, so we need to convert them + styles.replace(/([^\s]+)\s*:/g, function(m,g){return g.toLowerCase()+":"}) : + // other browsers are just fine + styles; +}; + +// ************************************************************************************************ + +var selectedElement = null +var fbPanel1 = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +var selectedSidePanelTS, selectedSidePanelTimer; + +var selectElement= function selectElement(e) +{ + if (e != selectedElement) + { + if (selectedElement) + selectedElement.className = "objectBox-element"; + + e.className = e.className + " selectedElement"; + + if (FBL.isFirefox) + e.style.MozBorderRadius = "2px"; + + else if (FBL.isSafari) + e.style.WebkitBorderRadius = "2px"; + + selectedElement = e; + + FirebugChrome.selectedHTMLElementId = e.id; + + var target = ElementCache.get(e.id); + var selectedSidePanel = Firebug.chrome.getPanel("HTML").sidePanelBar.selectedPanel; + + var stack = FirebugChrome.htmlSelectionStack; + + stack.unshift(target); + + if (stack.length > 2) + stack.pop(); + + var lazySelect = function() + { + selectedSidePanelTS = new Date().getTime(); + + selectedSidePanel.select(target, true); + }; + + if (selectedSidePanelTimer) + { + clearTimeout(selectedSidePanelTimer); + selectedSidePanelTimer = null; + } + + if (new Date().getTime() - selectedSidePanelTS > 100) + setTimeout(lazySelect, 0) + else + selectedSidePanelTimer = setTimeout(lazySelect, 150); + } +} + + +// ************************************************************************************************ +// *** TODO: REFACTOR ************************************************************************** +// ************************************************************************************************ +Firebug.HTML.onTreeClick = function (e) +{ + e = e || event; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + + if (targ.className.indexOf('nodeControl') != -1 || targ.className == 'nodeTag') + { + var isIE = false; + + if(targ.className == 'nodeTag') + { + var control = isIE ? (targ.parentNode.previousSibling || targ) : + (targ.parentNode.previousSibling || targ); + + selectElement(targ.parentNode.parentNode); + + if (control.className.indexOf('nodeControl') == -1) + return; + + } else + control = targ; + + FBL.cancelEvent(e); + + var treeNode = isIE ? control.nextSibling : control.parentNode; + + //FBL.Firebug.Console.log(treeNode); + + if (control.className.indexOf(' nodeMaximized') != -1) { + FBL.Firebug.HTML.removeTreeChildren(treeNode); + } else { + FBL.Firebug.HTML.appendTreeChildren(treeNode); + } + } + else if (targ.className == 'nodeValue' || targ.className == 'nodeName') + { + /* + var input = FBL.Firebug.chrome.document.getElementById('treeInput'); + + input.style.display = "block"; + input.style.left = targ.offsetLeft + 'px'; + input.style.top = FBL.topHeight + targ.offsetTop - FBL.fbPanel1.scrollTop + 'px'; + input.style.width = targ.offsetWidth + 6 + 'px'; + input.value = targ.textContent || targ.innerText; + input.focus(); + /**/ + } +} + +function onListMouseOut(e) +{ + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + if (hasClass(targ, "fbPanel")) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + } +}; + +var hoverElement = null; +var hoverElementTS = 0; + +Firebug.HTML.onListMouseMove = function onListMouseMove(e) +{ + try + { + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + var found = false; + while (targ && !found) { + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) + targ = targ.parentNode; + else + found = true; + } + + if (!targ) + { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + /* + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + /**/ + + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + + var el = ElementCache.get(uid.value); + + var nodeName = el.nodeName.toLowerCase(); + + if (FBL.isIE && " meta title script link ".indexOf(" "+nodeName+" ") != -1) + return; + + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) return; + + if (el.id == "FirebugUI" || " html head body br script link iframe ".indexOf(" "+nodeName+" ") != -1) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + if ((new Date().getTime() - hoverElementTS > 40) && hoverElement != el) { + hoverElementTS = new Date().getTime(); + hoverElement = el; + FBL.Firebug.Inspector.drawBoxModel(el); + } + } + catch(E) + { + } +} + + +// ************************************************************************************************ + +Firebug.Reps = { + + appendText: function(object, html) + { + html.push(escapeHTML(objectToString(object))); + }, + + appendNull: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendString: function(object, html) + { + html.push('"', escapeHTML(objectToString(object)), + '"'); + }, + + appendInteger: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFloat: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFunction: function(object, html) + { + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m && m[1] ? m[1] : "function"; + html.push('', escapeHTML(name), '()'); + }, + + appendObject: function(object, html) + { + /* + var rep = Firebug.getRep(object); + var outputs = []; + + rep.tag.tag.compile(); + + var str = rep.tag.renderHTML({object: object}, outputs); + html.push(str); + /**/ + + try + { + if (object == undefined) + this.appendNull("undefined", html); + else if (object == null) + this.appendNull("null", html); + else if (typeof object == "string") + this.appendString(object, html); + else if (typeof object == "number") + this.appendInteger(object, html); + else if (typeof object == "boolean") + this.appendInteger(object, html); + else if (typeof object == "function") + this.appendFunction(object, html); + else if (object.nodeType == 1) + this.appendSelector(object, html); + else if (typeof object == "object") + { + if (typeof object.length != "undefined") + this.appendArray(object, html); + else + this.appendObjectFormatted(object, html); + } + else + this.appendText(object, html); + } + catch (exc) + { + } + /**/ + }, + + appendObjectFormatted: function(object, html) + { + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push('', m ? m[1] : text, '') + }, + + appendSelector: function(object, html) + { + var uid = ElementCache(object); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push(''); + + html.push('', escapeHTML(object.nodeName.toLowerCase()), ''); + if (object.id) + html.push('#', escapeHTML(object.id), ''); + if (object.className) + html.push('.', escapeHTML(object.className), ''); + + html.push(''); + }, + + appendNode: function(node, html) + { + if (node.nodeType == 1) + { + var uid = ElementCache(node); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push( + '
      ', + '', + '<', node.nodeName.toLowerCase(), ''); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || attr.nodeName == cacheID) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? node.style.cssText : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + if (node.firstChild) + { + html.push('>
      '); + + for (var child = node.firstChild; child; child = child.nextSibling) + this.appendNode(child, html); + + html.push('
      </', + node.nodeName.toLowerCase(), '>
      '); + } + else + html.push('/>'); + } + else if (node.nodeType == 3) + { + var value = trim(node.nodeValue); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + }, + + appendArray: function(object, html) + { + html.push('[ '); + + for (var i = 0, l = object.length, obj; i < l; ++i) + { + this.appendObject(object[i], html); + + if (i < l-1) + html.push(', '); + } + + html.push(' ]'); + } + +}; + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +/* + +Hack: +Firebug.chrome.currentPanel = Firebug.chrome.selectedPanel; +Firebug.showInfoTips = true; +Firebug.InfoTip.initializeBrowser(Firebug.chrome); + +/**/ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var maxWidth = 100, maxHeight = 80; +var infoTipMargin = 10; +var infoTipWindowPadding = 25; + +// ************************************************************************************************ + +Firebug.InfoTip = extend(Firebug.Module, +{ + dispatchName: "infoTip", + tags: domplate( + { + infoTipTag: DIV({"class": "infoTip"}), + + colorTag: + DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, " "), + + imgTag: + DIV({"class": "infoTipImageBox infoTipLoading"}, + IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat", + onload: "$onLoadImage"}), + IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}), + DIV({"class": "infoTipCaption"}) + ), + + onLoadImage: function(event) + { + var img = event.currentTarget || event.srcElement; + ///var bgImg = img.nextSibling; + ///if (!bgImg) + /// return; // Sometimes gets called after element is dead + + ///var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + /// TODO: xxxpedro infoTip hack + var caption = getElementByClass(innerBox, "infoTipCaption"); + var bgImg = getElementByClass(innerBox, "infoTipBgImage"); + if (!bgImg) + return; // Sometimes gets called after element is dead + + // TODO: xxxpedro infoTip IE and timing issue + // TODO: use offline document to avoid flickering + if (isIE) + removeClass(innerBox, "infoTipLoading"); + + var updateInfoTip = function(){ + + var w = img.naturalWidth || img.width || 10, + h = img.naturalHeight || img.height || 10; + + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + //caption.innerHTML = $STRF("Dimensions", [w, h]); + caption.innerHTML = $STRF(w + " x " + h); + + + }; + + if (isIE) + setTimeout(updateInfoTip, 0); + else + { + updateInfoTip(); + removeClass(innerBox, "infoTipLoading"); + } + + /// + } + + /* + /// onLoadImage original + onLoadImage: function(event) + { + var img = event.currentTarget; + var bgImg = img.nextSibling; + if (!bgImg) + return; // Sometimes gets called after element is dead + + var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + var w = img.naturalWidth, h = img.naturalHeight; + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + caption.innerHTML = $STRF("Dimensions", [w, h]); + + removeClass(innerBox, "infoTipLoading"); + } + /**/ + + }), + + initializeBrowser: function(browser) + { + browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser); + browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser); + + ///var doc = browser.contentDocument; + var doc = browser.document; + if (!doc) + return; + + ///doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true); + addEvent(doc, "mouseover", browser.onInfoTipMouseMove); + addEvent(doc, "mouseout", browser.onInfoTipMouseOut); + addEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc)); + }, + + uninitializeBrowser: function(browser) + { + if (browser.infoTip) + { + ///var doc = browser.contentDocument; + var doc = browser.document; + ///doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true); + removeEvent(doc, "mouseover", browser.onInfoTipMouseMove); + removeEvent(doc, "mouseout", browser.onInfoTipMouseOut); + removeEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + browser.infoTip.parentNode.removeChild(browser.infoTip); + delete browser.infoTip; + delete browser.onInfoTipMouseMove; + } + }, + + showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset) + { + if (!Firebug.showInfoTips) + return; + + var scrollParent = getOverflowParent(target); + var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0); + + if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset)) + { + var htmlElt = infoTip.ownerDocument.documentElement; + var panelWidth = htmlElt.clientWidth; + var panelHeight = htmlElt.clientHeight; + + if (x+infoTip.offsetWidth+infoTipMargin > panelWidth) + { + infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px"; + infoTip.style.right = "auto"; + } + else + { + infoTip.style.left = (x+infoTipMargin) + "px"; + infoTip.style.right = "auto"; + } + + if (y+infoTip.offsetHeight+infoTipMargin > panelHeight) + { + infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px"; + infoTip.style.bottom = "auto"; + } + else + { + infoTip.style.top = (y+infoTipMargin) + "px"; + infoTip.style.bottom = "auto"; + } + + if (FBTrace.DBG_INFOTIP) + FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top + + ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom + + ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight + + ", offsetWidth: " + infoTip.offsetWidth + + ", x: " + x + ", panelWidth: " + panelWidth + + ", y: " + y + ", panelHeight: " + panelHeight); + + infoTip.setAttribute("active", "true"); + } + else + this.hideInfoTip(infoTip); + }, + + hideInfoTip: function(infoTip) + { + if (infoTip) + infoTip.removeAttribute("active"); + }, + + onMouseOut: function(event, browser) + { + if (!event.relatedTarget) + this.hideInfoTip(browser.infoTip); + }, + + onMouseMove: function(event, browser) + { + // Ignore if the mouse is moving over the existing info tip. + if (getAncestorByClass(event.target, "infoTip")) + return; + + if (browser.currentPanel) + { + var x = event.clientX, y = event.clientY, target = event.target || event.srcElement; + this.showInfoTip(browser.infoTip, browser.currentPanel, target, x, y, event.rangeParent, event.rangeOffset); + } + else + this.hideInfoTip(browser.infoTip); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + populateColorInfoTip: function(infoTip, color) + { + this.tags.colorTag.replace({rgbValue: color}, infoTip); + return true; + }, + + populateImageInfoTip: function(infoTip, url, repeat) + { + if (!repeat) + repeat = "no-repeat"; + + this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip); + + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + disable: function() + { + // XXXjoe For each browser, call uninitializeBrowser + }, + + showPanel: function(browser, panel) + { + if (panel) + { + var infoTip = panel.panelBrowser.infoTip; + if (!infoTip) + infoTip = this.initializeBrowser(panel.panelBrowser); + this.hideInfoTip(infoTip); + } + + }, + + showSidePanel: function(browser, panel) + { + this.showPanel(browser, panel); + } +}); + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.InfoTip); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +// move to FBL +(function() { + +// ************************************************************************************************ +// XPath + +/** + * Gets an XPath for an element which describes its hierarchical location. + */ +this.getElementXPath = function(element) +{ + if (element && element.id) + return '//*[@id="' + element.id + '"]'; + else + return this.getElementTreeXPath(element); +}; + +this.getElementTreeXPath = function(element) +{ + var paths = []; + + for (; element && element.nodeType == 1; element = element.parentNode) + { + var index = 0; + for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) + { + if (sibling.nodeName == element.nodeName) + ++index; + } + + var tagName = element.nodeName.toLowerCase(); + var pathIndex = (index ? "[" + (index+1) + "]" : ""); + paths.splice(0, 0, tagName + pathIndex); + } + + return paths.length ? "/" + paths.join("/") : null; +}; + +this.getElementsByXPath = function(doc, xpath) +{ + var nodes = []; + + try { + var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + for (var item = result.iterateNext(); item; item = result.iterateNext()) + nodes.push(item); + } + catch (exc) + { + // Invalid xpath expressions make their way here sometimes. If that happens, + // we still want to return an empty set without an exception. + } + + return nodes; +}; + +this.getRuleMatchingElements = function(rule, doc) +{ + var css = rule.selectorText; + var xpath = this.cssToXPath(css); + return this.getElementsByXPath(doc, xpath); +}; + + +}).call(FBL); + + + + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + +var toCamelCase = function toCamelCase(s) +{ + return s.replace(reSelectorCase, toCamelCaseReplaceFn); +}; + +var toSelectorCase = function toSelectorCase(s) +{ + return s.replace(reCamelCase, "-$1").toLowerCase(); + +}; + +var reCamelCase = /([A-Z])/g; +var reSelectorCase = /\-(.)/g; +var toCamelCaseReplaceFn = function toCamelCaseReplaceFn(m,g) +{ + return g.toUpperCase(); +}; + + + + + +// ************************************************************************************************ + +var ElementCache = Firebug.Lite.Cache.Element; +var StyleSheetCache = Firebug.Lite.Cache.StyleSheet; + +var globalCSSRuleIndex; + +var externalStyleSheetURLs = []; +var externalStyleSheetWarning = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "warning focusRow", style: "font-weight:normal;", role: 'listitem'}, + SPAN("$object|STR"), + A({"href": "$href", target:"_blank"}, "$link|STR") + ) +}); + + +var processAllStyleSheetsTimeout = null; +var loadExternalStylesheet = function(doc, styleSheetIterator, styleSheet) +{ + var url = styleSheet.href; + styleSheet.firebugIgnore = true; + + var source = Firebug.Lite.Proxy.load(url); + + // TODO: check for null and error responses + + + // remove comments + //var reMultiComment = /(\/\*([^\*]|\*(?!\/))*\*\/)/g; + //source = source.replace(reMultiComment, ""); + + // convert relative addresses to absolute ones + source = source.replace(/url\(([^\)]+)\)/g, function(a,name){ + + var hasDomain = /\w+:\/\/./.test(name); + + if (!hasDomain) + { + name = name.replace(/^(["'])(.+)\1$/, "$2"); + var first = name.charAt(0); + + // relative path, based on root + if (first == "/") + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLRoot + var m = /^([^:]+:\/{1,3}[^\/]+)/.exec(url); + + return m ? + "url(" + m[1] + name + ")" : + "url(" + name + ")"; + } + // relative path, based on current location + else + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLPath + var path = url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g, ""); + + path = path + name; + + var reBack = /[^\/]+\/\.\.\//; + while(reBack.test(path)) + { + path = path.replace(reBack, ""); + } + + //console.log("url(" + path + ")"); + + return "url(" + path + ")"; + } + } + + // if it is an absolute path, there is nothing to do + return a; + }); + + var oldStyle = styleSheet.ownerNode; + + if (!oldStyle) return; + + if (!oldStyle.parentNode) return; + + var style = createGlobalElement("style"); + style.setAttribute("charset","utf-8"); + style.setAttribute("type", "text/css"); + style.innerHTML = source; + + //debugger; + oldStyle.parentNode.insertBefore(style, oldStyle.nextSibling); + oldStyle.parentNode.removeChild(oldStyle); + + + //doc.getElementsByTagName("head")[0].appendChild(style); + + doc.styleSheets[doc.styleSheets.length-1].externalURL = url; + + console.log(url, "call " + externalStyleSheetURLs.length, source); + + externalStyleSheetURLs.pop(); + + if (processAllStyleSheetsTimeout) + { + clearTimeout(processAllStyleSheetsTimeout); + } + + processAllStyleSheetsTimeout = setTimeout(function(){ + console.log("processing"); + FBL.processAllStyleSheets(doc, styleSheetIterator); + processAllStyleSheetsTimeout = null; + },200); + +}; + + +FBL.processAllStyleSheets = function(doc, styleSheetIterator) +{ + styleSheetIterator = styleSheetIterator || processStyleSheet; + + globalCSSRuleIndex = -1; + + var styleSheets = doc.styleSheets; + var importedStyleSheets = []; + + if (FBTrace.DBG_CSS) + var start = new Date().getTime(); + + for(var i=0, length=styleSheets.length; i maxSpecificity) + { + maxSpecificity = spec; + mostSpecificSelector = sel; + } + } + } + + rule.specificity = maxSpecificity; + } + } + + rules.sort(sortElementRules); + //rules.sort(solveRulesTied); + + return rules; +}; + +var sortElementRules = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + var specificityA = ruleA.specificity; + var specificityB = ruleB.specificity; + + if (specificityA > specificityB) + return 1; + + else if (specificityA < specificityB) + return -1; + + else + return ruleA.order > ruleB.order ? 1 : -1; +}; + +var solveRulesTied = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + if (ruleA.specificity == ruleB.specificity) + return ruleA.order > ruleB.order ? 1 : -1; + + return null; +}; + +var reSelectorTag = /(^|\s)(?:\w+)/g; +var reSelectorClass = /\.[\w\d_-]+/g; +var reSelectorId = /#[\w\d_-]+/g; + +var getCSSRuleSpecificity = function(selector) +{ + var match = selector.match(reSelectorTag); + var tagCount = match ? match.length : 0; + + match = selector.match(reSelectorClass); + var classCount = match ? match.length : 0; + + match = selector.match(reSelectorId); + var idCount = match ? match.length : 0; + + return tagCount + 10*classCount + 100*idCount; +}; + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; +//const nsIDOMCSSStyleRule = Ci.nsIDOMCSSStyleRule; +//const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor; +//const nsISelectionDisplay = Ci.nsISelectionDisplay; +//const nsISelectionController = Ci.nsISelectionController; + +// See: http://mxr.mozilla.org/mozilla1.9.2/source/content/events/public/nsIEventStateManager.h#153 +//const STATE_ACTIVE = 0x01; +//const STATE_FOCUS = 0x02; +//const STATE_HOVER = 0x04; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +Firebug.SourceBoxPanel = Firebug.Panel; + +var domUtils = null; + +var textContent = isIE ? "innerText" : "textContent"; +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var CSSDomplateBase = { + isEditable: function(rule) + { + return !rule.isSystemSheet; + }, + isSelectorEditable: function(rule) + { + return rule.isSelectorEditable && this.isEditable(rule); + } +}; + +var CSSPropTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssProp focusRow", $disabledStyle: "$prop.disabled", + $editGroup: "$rule|isEditable", + $cssOverridden: "$prop.overridden", role : "option"}, + A({"class": "cssPropDisable"}, "  "), + SPAN({"class": "cssPropName", $editable: "$rule|isEditable"}, "$prop.name"), + SPAN({"class": "cssColon"}, ":"), + SPAN({"class": "cssPropValue", $editable: "$rule|isEditable"}, "$prop.value$prop.important"), + SPAN({"class": "cssSemi"}, ";") + ) +}); + +var CSSRuleTag = + TAG("$rule.tag", {rule: "$rule"}); + +var CSSImportRuleTag = domplate({ + tag: DIV({"class": "cssRule insertInto focusRow importRule", _repObject: "$rule.rule"}, + "@import "", + A({"class": "objectLink", _repObject: "$rule.rule.styleSheet"}, "$rule.rule.href"), + "";" + ) +}); + +var CSSStyleRuleTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssRule insertInto", + $cssEditableRule: "$rule|isEditable", + $editGroup: "$rule|isSelectorEditable", + _repObject: "$rule.rule", + "ruleId": "$rule.id", role : 'presentation'}, + DIV({"class": "cssHead focusRow", role : 'listitem'}, + SPAN({"class": "cssSelector", $editable: "$rule|isSelectorEditable"}, "$rule.selector"), " {" + ), + DIV({role : 'group'}, + DIV({"class": "cssPropertyListBox", role : 'listbox'}, + FOR("prop", "$rule.props", + TAG(CSSPropTag.tag, {rule: "$rule", prop: "$prop"}) + ) + ) + ), + DIV({"class": "editable insertBefore", role:"presentation"}, "}") + ) +}); + +var reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/; + +var reURL = /url\("?([^"\)]+)?"?\)/; + +var reRepeat = /no-repeat|repeat-x|repeat-y|repeat/; + +//const sothinkInstalled = !!$("swfcatcherKey_sidebar"); +var sothinkInstalled = false; +var styleGroups = +{ + text: [ + "font-family", + "font-size", + "font-weight", + "font-style", + "color", + "text-transform", + "text-decoration", + "letter-spacing", + "word-spacing", + "line-height", + "text-align", + "vertical-align", + "direction", + "column-count", + "column-gap", + "column-width" + ], + + background: [ + "background-color", + "background-image", + "background-repeat", + "background-position", + "background-attachment", + "opacity" + ], + + box: [ + "width", + "height", + "top", + "right", + "bottom", + "left", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + "-moz-border-top-radius", + "-moz-border-right-radius", + "-moz-border-bottom-radius", + "-moz-border-left-radius", + "outline-top-width", + "outline-right-width", + "outline-bottom-width", + "outline-left-width", + "outline-top-color", + "outline-right-color", + "outline-bottom-color", + "outline-left-color", + "outline-top-style", + "outline-right-style", + "outline-bottom-style", + "outline-left-style" + ], + + layout: [ + "position", + "display", + "visibility", + "z-index", + "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow + "overflow-y", + "overflow-clip", + "white-space", + "clip", + "float", + "clear", + "-moz-box-sizing" + ], + + other: [ + "cursor", + "list-style-image", + "list-style-position", + "list-style-type", + "marker-offset", + "user-focus", + "user-select", + "user-modify", + "user-input" + ] +}; + +var styleGroupTitles = +{ + text: "Text", + background: "Background", + box: "Box Model", + layout: "Layout", + other: "Other" +}; + +Firebug.CSSModule = extend(Firebug.Module, +{ + freeEdit: function(styleSheet, value) + { + if (!styleSheet.editStyleSheet) + { + var ownerNode = getStyleSheetOwnerNode(styleSheet); + styleSheet.disabled = true; + + var url = CCSV("@mozilla.org/network/standard-url;1", Components.interfaces.nsIURL); + url.spec = styleSheet.href; + + var editStyleSheet = ownerNode.ownerDocument.createElementNS( + "http://www.w3.org/1999/xhtml", + "style"); + unwrapObject(editStyleSheet).firebugIgnore = true; + editStyleSheet.setAttribute("type", "text/css"); + editStyleSheet.setAttributeNS( + "http://www.w3.org/XML/1998/namespace", + "base", + url.directory); + if (ownerNode.hasAttribute("media")) + { + editStyleSheet.setAttribute("media", ownerNode.getAttribute("media")); + } + + // Insert the edited stylesheet directly after the old one to ensure the styles + // cascade properly. + ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling); + + styleSheet.editStyleSheet = editStyleSheet; + } + + styleSheet.editStyleSheet.innerHTML = value; + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n"); + + dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]); + }, + + insertRule: function(styleSheet, cssText, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("Insert: " + ruleIndex + " " + cssText); + var insertIndex = styleSheet.insertRule(cssText, ruleIndex); + + dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]); + + return insertIndex; + }, + + deleteRule: function(styleSheet, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("deleteRule: " + ruleIndex + " " + styleSheet.cssRules.length, styleSheet.cssRules); + dispatch(this.fbListeners, "onCSSDeleteRule", [styleSheet, ruleIndex]); + + styleSheet.deleteRule(ruleIndex); + }, + + setProperty: function(rule, propName, propValue, propPriority) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + // good browsers + if (style.getPropertyValue) + { + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect + // unless we remove the property first + style.removeProperty(propName); + + style.setProperty(propName, propValue, propPriority); + } + // sad browsers + else + { + // TODO: xxxpedro parse CSS rule to find property priority in IE? + //console.log(propName, propValue); + style[toCamelCase(propName)] = propValue; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue, propPriority, prevValue, prevPriority, rule, baseText]); + } + }, + + removeProperty: function(rule, propName, parent) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + if (style.getPropertyValue) + { + + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + style.removeProperty(propName); + } + else + { + style[toCamelCase(propName)] = ""; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue, prevPriority, rule, baseText]); + } + }/*, + + cleanupSheets: function(doc, context) + { + // Due to the manner in which the layout engine handles multiple + // references to the same sheet we need to kick it a little bit. + // The injecting a simple stylesheet then removing it will force + // Firefox to regenerate it's CSS hierarchy. + // + // WARN: This behavior was determined anecdotally. + // See http://code.google.com/p/fbug/issues/detail?id=2440 + var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + style.setAttribute("charset","utf-8"); + unwrapObject(style).firebugIgnore = true; + style.setAttribute("type", "text/css"); + style.innerHTML = "#fbIgnoreStyleDO_NOT_USE {}"; + addStyleSheet(doc, style); + style.parentNode.removeChild(style); + + // https://bugzilla.mozilla.org/show_bug.cgi?id=500365 + // This voodoo touches each style sheet to force some Firefox internal change to allow edits. + var styleSheets = getAllStyleSheets(context); + for(var i = 0; i < styleSheets.length; i++) + { + try + { + var rules = styleSheets[i].cssRules; + if (rules.length > 0) + var touch = rules[0]; + if (FBTrace.DBG_CSS && touch) + FBTrace.sysout("css.show() touch "+typeof(touch)+" in "+(styleSheets[i].href?styleSheets[i].href:context.getName())); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.show: sheet.cssRules FAILS for "+(styleSheets[i]?styleSheets[i].href:"null sheet")+e, e); + } + } + }, + cleanupSheetHandler: function(event, context) + { + var target = event.target || event.srcElement, + tagName = (target.tagName || "").toLowerCase(); + if (tagName == "link") + { + this.cleanupSheets(target.ownerDocument, context); + } + }, + watchWindow: function(context, win) + { + var cleanupSheets = bind(this.cleanupSheets, this), + cleanupSheetHandler = bind(this.cleanupSheetHandler, this, context), + doc = win.document; + + //doc.addEventListener("DOMAttrModified", cleanupSheetHandler, false); + //doc.addEventListener("DOMNodeInserted", cleanupSheetHandler, false); + }, + loadedContext: function(context) + { + var self = this; + iterateWindows(context.browser.contentWindow, function(subwin) + { + self.cleanupSheets(subwin.document, context); + }); + } + /**/ +}); + +// ************************************************************************************************ + +Firebug.CSSStyleSheetPanel = function() {}; + +Firebug.CSSStyleSheetPanel.prototype = extend(Firebug.SourceBoxPanel, +{ + template: domplate( + { + tag: + DIV({"class": "cssSheet insertInto a11yCSSView"}, + FOR("rule", "$rules", + CSSRuleTag + ), + DIV({"class": "cssSheet editable insertBefore"}, "") + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + refresh: function() + { + if (this.location) + this.updateLocation(this.location); + else if (this.selection) + this.updateSelection(this.selection); + }, + + toggleEditing: function() + { + if (!this.stylesheetEditor) + this.stylesheetEditor = new StyleSheetEditor(this.document); + + if (this.editing) + Firebug.Editor.stopEditing(); + else + { + if (!this.location) + return; + + var styleSheet = this.location.editStyleSheet + ? this.location.editStyleSheet.sheet + : this.location; + + var css = getStyleSheetCSS(styleSheet, this.context); + //var topmost = getTopmostRuleLine(this.panelNode); + + this.stylesheetEditor.styleSheet = this.location; + Firebug.Editor.startEditing(this.panelNode, css, this.stylesheetEditor); + //this.stylesheetEditor.scrollToLine(topmost.line, topmost.offset); + } + }, + + getStylesheetURL: function(rule) + { + if (this.location.href) + return this.location.href; + else + return this.context.window.location.href; + }, + + getRuleByLine: function(styleSheet, line) + { + if (!domUtils) + return null; + + var cssRules = styleSheet.cssRules; + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + if (rule instanceof CSSStyleRule) + { + var ruleLine = domUtils.getRuleLine(rule); + if (ruleLine >= line) + return rule; + } + } + }, + + highlightRule: function(rule) + { + var ruleElement = Firebug.getElementByRepObject(this.panelNode.firstChild, rule); + if (ruleElement) + { + scrollIntoCenterView(ruleElement, this.panelNode); + setClassTimed(ruleElement, "jumpHighlight", this.context); + } + }, + + getStyleSheetRules: function(context, styleSheet) + { + var isSystemSheet = isSystemStyleSheet(styleSheet); + + function appendRules(cssRules) + { + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + + // TODO: xxxpedro opera instanceof stylesheet remove the following comments when + // the issue with opera and style sheet Classes has been solved. + + //if (rule instanceof CSSStyleRule) + if (instanceOf(rule, "CSSStyleRule")) + { + var props = this.getRuleProperties(context, rule); + //var line = domUtils.getRuleLine(rule); + var line = null; + + var selector = rule.selectorText; + + if (isIE) + { + selector = selector.replace(reSelectorTag, + function(s){return s.toLowerCase();}); + } + + var ruleId = rule.selectorText+"/"+line; + rules.push({tag: CSSStyleRuleTag.tag, rule: rule, id: ruleId, + selector: selector, props: props, + isSystemSheet: isSystemSheet, + isSelectorEditable: true}); + } + //else if (rule instanceof CSSImportRule) + else if (instanceOf(rule, "CSSImportRule")) + rules.push({tag: CSSImportRuleTag.tag, rule: rule}); + //else if (rule instanceof CSSMediaRule) + else if (instanceOf(rule, "CSSMediaRule")) + appendRules.apply(this, [rule.cssRules]); + else + { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_CSS) + FBTrace.sysout("css getStyleSheetRules failed to classify a rule ", rule); + } + } + } + + var rules = []; + appendRules.apply(this, [styleSheet.cssRules || styleSheet.rules]); + return rules; + }, + + parseCSSProps: function(style, inheritMode) + { + var props = []; + + if (Firebug.expandShorthandProps) + { + var count = style.length-1, + index = style.length; + while (index--) + { + var propName = style.item(count - index); + this.addProperty(propName, style.getPropertyValue(propName), !!style.getPropertyPriority(propName), false, inheritMode, props); + } + } + else + { + var lines = style.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g); + var propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/; + var line,i=0; + // TODO: xxxpedro port to firebug: variable leaked into global namespace + var m; + + while(line=lines[i++]){ + m = propRE.exec(line); + if(!m) + continue; + //var name = m[1], value = m[2], important = !!m[3]; + if (m[2]) + this.addProperty(m[1], m[2], !!m[3], false, inheritMode, props); + }; + } + + return props; + }, + + getRuleProperties: function(context, rule, inheritMode) + { + var props = this.parseCSSProps(rule.style, inheritMode); + + // TODO: xxxpedro port to firebug: variable leaked into global namespace + //var line = domUtils.getRuleLine(rule); + var line; + var ruleId = rule.selectorText+"/"+line; + this.addOldProperties(context, ruleId, inheritMode, props); + sortProperties(props); + + return props; + }, + + addOldProperties: function(context, ruleId, inheritMode, props) + { + if (context.selectorMap && context.selectorMap.hasOwnProperty(ruleId) ) + { + var moreProps = context.selectorMap[ruleId]; + for (var i = 0; i < moreProps.length; ++i) + { + var prop = moreProps[i]; + this.addProperty(prop.name, prop.value, prop.important, true, inheritMode, props); + } + } + }, + + addProperty: function(name, value, important, disabled, inheritMode, props) + { + name = name.toLowerCase(); + + if (inheritMode && !inheritedStyleNames[name]) + return; + + name = this.translateName(name, value); + if (name) + { + value = stripUnits(rgbToHex(value)); + important = important ? " !important" : ""; + + var prop = {name: name, value: value, important: important, disabled: disabled}; + props.push(prop); + } + }, + + translateName: function(name, value) + { + // Don't show these proprietary Mozilla properties + if ((value == "-moz-initial" + && (name == "-moz-background-clip" || name == "-moz-background-origin" + || name == "-moz-background-inline-policy")) + || (value == "physical" + && (name == "margin-left-ltr-source" || name == "margin-left-rtl-source" + || name == "margin-right-ltr-source" || name == "margin-right-rtl-source")) + || (value == "physical" + && (name == "padding-left-ltr-source" || name == "padding-left-rtl-source" + || name == "padding-right-ltr-source" || name == "padding-right-rtl-source"))) + return null; + + // Translate these back to the form the user probably expects + if (name == "margin-left-value") + return "margin-left"; + else if (name == "margin-right-value") + return "margin-right"; + else if (name == "margin-top-value") + return "margin-top"; + else if (name == "margin-bottom-value") + return "margin-bottom"; + else if (name == "padding-left-value") + return "padding-left"; + else if (name == "padding-right-value") + return "padding-right"; + else if (name == "padding-top-value") + return "padding-top"; + else if (name == "padding-bottom-value") + return "padding-bottom"; + // XXXjoe What about border! + else + return name; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + editElementStyle: function() + { + ///var rulesBox = this.panelNode.getElementsByClassName("cssElementRuleContainer")[0]; + var rulesBox = $$(".cssElementRuleContainer", this.panelNode)[0]; + var styleRuleBox = rulesBox && Firebug.getElementByRepObject(rulesBox, this.selection); + if (!styleRuleBox) + { + var rule = {rule: this.selection, inherited: false, selector: "element.style", props: []}; + if (!rulesBox) + { + // The element did not have any displayed styles. We need to create the whole tree and remove + // the no styles message + styleRuleBox = this.template.cascadedTag.replace({ + rules: [rule], inherited: [], inheritLabel: "Inherited from" // $STR("InheritedFrom") + }, this.panelNode); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("cssElementRuleContainer")[0]; + styleRuleBox = $$(".cssElementRuleContainer", styleRuleBox)[0]; + } + else + styleRuleBox = this.template.ruleTag.insertBefore({rule: rule}, rulesBox); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("insertInto")[0]; + styleRuleBox = $$(".insertInto", styleRuleBox)[0]; + } + + Firebug.Editor.insertRowForObject(styleRuleBox); + }, + + insertPropertyRow: function(row) + { + Firebug.Editor.insertRowForObject(row); + }, + + insertRule: function(row) + { + var location = getAncestorByClass(row, "cssRule"); + if (!location) + { + location = getChildByClass(this.panelNode, "cssSheet"); + Firebug.Editor.insertRowForObject(location); + } + else + { + Firebug.Editor.insertRow(location, "before"); + } + }, + + editPropertyRow: function(row) + { + var propValueBox = getChildByClass(row, "cssPropValue"); + Firebug.Editor.startEditing(propValueBox); + }, + + deletePropertyRow: function(row) + { + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + Firebug.CSSModule.removeProperty(rule, propName); + + // Remove the property from the selector map, if it was disabled + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if ( this.context.selectorMap && this.context.selectorMap.hasOwnProperty(ruleId) ) + { + var map = this.context.selectorMap[ruleId]; + for (var i = 0; i < map.length; ++i) + { + if (map[i].name == propName) + { + map.splice(i, 1); + break; + } + } + } + if (this.name == "stylesheet") + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [this, row.firstChild, true]); + row.parentNode.removeChild(row); + + this.markChange(this.name == "stylesheet"); + }, + + disablePropertyRow: function(row) + { + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + + if (!this.context.selectorMap) + this.context.selectorMap = {}; + + // XXXjoe Generate unique key for elements too + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if (!(this.context.selectorMap.hasOwnProperty(ruleId))) + this.context.selectorMap[ruleId] = []; + + var map = this.context.selectorMap[ruleId]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + if (hasClass(row, "disabledStyle")) + { + Firebug.CSSModule.removeProperty(rule, propName); + + map.push({"name": propName, "value": parsedValue.value, + "important": parsedValue.priority}); + } + else + { + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + + var index = findPropByName(map, propName); + map.splice(index, 1); + } + + this.markChange(this.name == "stylesheet"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onMouseDown: function(event) + { + //console.log("onMouseDown", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + // XXjoe Hack to only allow clicking on the checkbox + if (!isLeftClick(event) || offset > 20) + return; + + var target = event.target || event.srcElement; + if (hasClass(target, "textEditor")) + return; + + var row = getAncestorByClass(target, "cssProp"); + if (row && hasClass(row, "editGroup")) + { + this.disablePropertyRow(row); + cancelEvent(event); + } + }, + + onDoubleClick: function(event) + { + //console.log("onDoubleClick", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + if (!isLeftClick(event) || offset <= 20) + return; + + var target = event.target || event.srcElement; + + //console.log("ok", target, hasClass(target, "textEditorInner"), !isLeftClick(event), offset <= 20); + + // if the inline editor was clicked, don't insert a new rule + if (hasClass(target, "textEditorInner")) + return; + + var row = getAncestorByClass(target, "cssRule"); + if (row && !getAncestorByClass(target, "cssPropName") + && !getAncestorByClass(target, "cssPropValue")) + { + this.insertPropertyRow(row); + cancelEvent(event); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "stylesheet", + title: "CSS", + parentPanel: null, + searchable: true, + dependents: ["css", "stylesheet", "dom", "domSide", "layout"], + + options: + { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onMouseDown = bind(this.onMouseDown, this); + this.onDoubleClick = bind(this.onDoubleClick, this); + + if (this.name == "stylesheet") + { + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var selectNode = this.selectNode = createElement("select"); + + processAllStyleSheets(doc, function(doc, styleSheet) + { + var key = StyleSheetCache.key(styleSheet); + var fileName = getFileName(styleSheet.href) || getFileName(doc.location.href); + var option = createElement("option", {value: key}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }); + + this.toolButtonsNode.appendChild(selectNode); + } + /**/ + }, + + onChangeSelect: function(event) + { + event = event || window.event; + var target = event.srcElement || event.currentTarget; + var key = target.value; + var styleSheet = StyleSheetCache.get(key); + + this.updateLocation(styleSheet); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + + //if (!domUtils) + //{ + // try { + // domUtils = CCSV("@mozilla.org/inspector/dom-utils;1", "inIDOMUtils"); + // } catch (exc) { + // if (FBTrace.DBG_ERRORS) + // FBTrace.sysout("@mozilla.org/inspector/dom-utils;1 FAILED to load: "+exc, exc); + // } + //} + + //TODO: xxxpedro + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + this.initializeNode(); + + if (this.name == "stylesheet") + { + var styleSheets = Firebug.browser.document.styleSheets; + + if (styleSheets.length > 0) + { + addEvent(this.selectNode, "change", this.onChangeSelect); + + this.updateLocation(styleSheets[0]); + } + } + + //Firebug.SourceBoxPanel.initialize.apply(this, arguments); + }, + + shutdown: function() + { + // must destroy the editor when we leave the panel to avoid problems (Issue 2981) + Firebug.Editor.stopEditing(); + + if (this.name == "stylesheet") + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + } + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + destroy: function(state) + { + //state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop; + + //persistObjects(this, state); + + // xxxpedro we are stopping the editor in the shutdown method already + //Firebug.Editor.stopEditing(); + Firebug.Panel.destroy.apply(this, arguments); + }, + + initializeNode: function(oldPanelNode) + { + addEvent(this.panelNode, "mousedown", this.onMouseDown); + addEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.initializeNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'css']); + }, + + destroyNode: function() + { + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + removeEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.destroyNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'css']); + }, + + ishow: function(state) + { + Firebug.Inspector.stopInspecting(true); + + this.showToolbarButtons("fbCSSButtons", true); + + if (this.context.loaded && !this.location) // wait for loadedContext to restore the panel + { + restoreObjects(this, state); + + if (!this.location) + this.location = this.getDefaultLocation(); + + if (state && state.scrollTop) + this.panelNode.scrollTop = state.scrollTop; + } + }, + + ihide: function() + { + this.showToolbarButtons("fbCSSButtons", false); + + this.lastScrollTop = this.panelNode.scrollTop; + }, + + supportsObject: function(object) + { + if (object instanceof CSSStyleSheet) + return 1; + else if (object instanceof CSSStyleRule) + return 2; + else if (object instanceof CSSStyleDeclaration) + return 2; + else if (object instanceof SourceLink && object.type == "css" && reCSS.test(object.href)) + return 2; + else + return 0; + }, + + updateLocation: function(styleSheet) + { + if (!styleSheet) + return; + if (styleSheet.editStyleSheet) + styleSheet = styleSheet.editStyleSheet.sheet; + + // if it is a restricted stylesheet, show the warning message and abort the update process + if (styleSheet.restricted) + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, this.panelNode); + + // TODO: xxxpedro remove when there the external resource problem is fixed + externalStyleSheetWarning.tag.append({ + object: "The stylesheet could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22" + }, this.panelNode); + + return; + } + + var rules = this.getStyleSheetRules(this.context, styleSheet); + + var result; + if (rules.length) + result = this.template.tag.replace({rules: rules}, this.panelNode); + else + result = FirebugReps.Warning.tag.replace({object: "EmptyStyleSheet"}, this.panelNode); + + // TODO: xxxpedro need to fix showToolbarButtons function + //this.showToolbarButtons("fbCSSButtons", !isSystemStyleSheet(this.location)); + + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, this.panelNode]); + }, + + updateSelection: function(object) + { + this.selection = null; + + if (object instanceof CSSStyleDeclaration) { + object = object.parentRule; + } + + if (object instanceof CSSStyleRule) + { + this.navigate(object.parentStyleSheet); + this.highlightRule(object); + } + else if (object instanceof CSSStyleSheet) + { + this.navigate(object); + } + else if (object instanceof SourceLink) + { + try + { + var sourceLink = object; + + var sourceFile = getSourceFileByHref(sourceLink.href, this.context); + if (sourceFile) + { + clearNode(this.panelNode); // replace rendered stylesheets + this.showSourceFile(sourceFile); + + var lineNo = object.line; + if (lineNo) + this.scrollToLine(lineNo, this.jumpHighlightFactory(lineNo, this.context)); + } + else // XXXjjb we should not be taking this path + { + var stylesheet = getStyleSheetByHref(sourceLink.href, this.context); + if (stylesheet) + this.navigate(stylesheet); + else + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href, sourceLink); + } + } + } + catch(exc) { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.upDateSelection FAILS "+exc, exc); + } + } + }, + + updateOption: function(name, value) + { + if (name == "expandShorthandProps") + this.refresh(); + }, + + getLocationList: function() + { + var styleSheets = getAllStyleSheets(this.context); + return styleSheets; + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") }, + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ]; + }, + + getContextMenuItems: function(style, target) + { + var items = []; + + if (this.infoTipType == "color") + { + items.push( + {label: "CopyColor", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) } + ); + } + else if (this.infoTipType == "image") + { + items.push( + {label: "CopyImageLocation", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) }, + {label: "OpenImageInNewTab", + command: bindFixed(openNewTab, FBL, this.infoTipObject) } + ); + } + + ///if (this.selection instanceof Element) + if (isElement(this.selection)) + { + items.push( + //"-", + {label: "EditStyle", + command: bindFixed(this.editElementStyle, this) } + ); + } + else if (!isSystemStyleSheet(this.selection)) + { + items.push( + //"-", + {label: "NewRule", + command: bindFixed(this.insertRule, this, target) } + ); + } + + var cssRule = getAncestorByClass(target, "cssRule"); + if (cssRule && hasClass(cssRule, "cssEditableRule")) + { + items.push( + "-", + {label: "NewProp", + command: bindFixed(this.insertPropertyRow, this, target) } + ); + + var propRow = getAncestorByClass(target, "cssProp"); + if (propRow) + { + var propName = getChildByClass(propRow, "cssPropName")[textContent]; + var isDisabled = hasClass(propRow, "disabledStyle"); + + items.push( + {label: $STRF("EditProp", [propName]), nol10n: true, + command: bindFixed(this.editPropertyRow, this, propRow) }, + {label: $STRF("DeleteProp", [propName]), nol10n: true, + command: bindFixed(this.deletePropertyRow, this, propRow) }, + {label: $STRF("DisableProp", [propName]), nol10n: true, + type: "checkbox", checked: isDisabled, + command: bindFixed(this.disablePropertyRow, this, propRow) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ); + + return items; + }, + + browseObject: function(object) + { + if (this.infoTipType == "image") + { + openNewTab(this.infoTipObject); + return true; + } + }, + + showInfoTip: function(infoTip, target, x, y) + { + var propValue = getAncestorByClass(target, "cssPropValue"); + if (propValue) + { + var offset = getClientOffset(propValue); + var offsetX = x-offset.x; + + var text = propValue[textContent]; + var charWidth = propValue.offsetWidth/text.length; + var charOffset = Math.floor(offsetX/charWidth); + + var cssValue = parseCSSValue(text, charOffset); + if (cssValue) + { + if (cssValue.value == this.infoTipValue) + return true; + + this.infoTipValue = cssValue.value; + + if (cssValue.type == "rgb" || (!cssValue.type && isColorKeyword(cssValue.value))) + { + this.infoTipType = "color"; + this.infoTipObject = cssValue.value; + + return Firebug.InfoTip.populateColorInfoTip(infoTip, cssValue.value); + } + else if (cssValue.type == "url") + { + ///var propNameNode = target.parentNode.getElementsByClassName("cssPropName").item(0); + var propNameNode = getElementByClass(target.parentNode, "cssPropName"); + if (propNameNode && isImageRule(propNameNode[textContent])) + { + var rule = Firebug.getRepObject(target); + var baseURL = this.getStylesheetURL(rule); + var relURL = parseURLValue(cssValue.value); + var absURL = isDataURL(relURL) ? relURL:absoluteURL(relURL, baseURL); + var repeat = parseRepeatValue(text); + + this.infoTipType = "image"; + this.infoTipObject = absURL; + + return Firebug.InfoTip.populateImageInfoTip(infoTip, absURL, repeat); + } + } + } + } + + delete this.infoTipType; + delete this.infoTipValue; + delete this.infoTipObject; + }, + + getEditor: function(target, value) + { + if (target == this.panelNode + || hasClass(target, "cssSelector") || hasClass(target, "cssRule") + || hasClass(target, "cssSheet")) + { + if (!this.ruleEditor) + this.ruleEditor = new CSSRuleEditor(this.document); + + return this.ruleEditor; + } + else + { + if (!this.editor) + this.editor = new CSSEditor(this.document); + + return this.editor; + } + }, + + getDefaultLocation: function() + { + try + { + var styleSheets = this.context.window.document.styleSheets; + if (styleSheets.length) + { + var sheet = styleSheets[0]; + return (Firebug.filterSystemURLs && isSystemURL(getURLForStyleSheet(sheet))) ? null : sheet; + } + } + catch (exc) + { + if (FBTrace.DBG_LOCATIONS) + FBTrace.sysout("css.getDefaultLocation FAILS "+exc, exc); + } + }, + + getObjectDescription: function(styleSheet) + { + var url = getURLForStyleSheet(styleSheet); + var instance = getInstanceForStyleSheet(styleSheet); + + var baseDescription = splitURLBase(url); + if (instance) { + baseDescription.name = baseDescription.name + " #" + (instance + 1); + } + return baseDescription; + }, + + search: function(text, reverse) + { + var curDoc = this.searchCurrentDoc(!Firebug.searchGlobal, text, reverse); + if (!curDoc && Firebug.searchGlobal) + { + return this.searchOtherDocs(text, reverse); + } + return curDoc; + }, + + searchOtherDocs: function(text, reverse) + { + var scanRE = Firebug.Search.getTestingRegex(text); + function scanDoc(styleSheet) { + // we don't care about reverse here as we are just looking for existence, + // if we do have a result we will handle the reverse logic on display + for (var i = 0; i < styleSheet.cssRules.length; i++) + { + if (scanRE.test(styleSheet.cssRules[i].cssText)) + { + return true; + } + } + } + + if (this.navigateToNextDocument(scanDoc, reverse)) + { + return this.searchCurrentDoc(true, text, reverse); + } + }, + + searchCurrentDoc: function(wrapSearch, text, reverse) + { + if (!text) + { + delete this.currentSearch; + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + { + row = this.currentSearch.findNext(wrapSearch, false, reverse, Firebug.Search.isCaseSensitive(text)); + } + else + { + if (this.editing) + { + this.currentSearch = new TextSearch(this.stylesheetEditor.box); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + scrollSelectionIntoView(this); + return true; + } + else + return false; + } + else + { + function findRow(node) { return node.nodeType == 1 ? node : node.parentNode; } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + } + } + + if (row) + { + this.document.defaultView.getSelection().selectAllChildren(row); + scrollIntoCenterView(row, this.panelNode); + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, null]); + return false; + } + }, + + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive"), + Firebug.Search.searchOptionMenu("search.Multiple_Files", "searchGlobal") + ]; + } +}); +/**/ +// ************************************************************************************************ + +function CSSElementPanel() {} + +CSSElementPanel.prototype = extend(Firebug.CSSStyleSheetPanel.prototype, +{ + template: domplate( + { + cascadedTag: + DIV({"class": "a11yCSSView", role : 'presentation'}, + DIV({role : 'list', 'aria-label' : $STR('aria.labels.style rules') }, + FOR("rule", "$rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ), + DIV({role : "list", 'aria-label' :$STR('aria.labels.inherited style rules')}, + FOR("section", "$inherited", + H1({"class": "cssInheritHeader groupHeader focusRow", role : 'listitem' }, + SPAN({"class": "cssInheritLabel"}, "$inheritLabel"), + TAG(FirebugReps.Element.shortTag, {object: "$section.element"}) + ), + DIV({role : 'group'}, + FOR("rule", "$section.rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ) + ) + ) + ), + + ruleTag: + isIE ? + // IE needs the sourceLink first, otherwise it will be rendered outside the panel + DIV({"class": "cssElementRuleContainer"}, + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}), + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}) + ) + : + // other browsers need the sourceLink last, otherwise it will cause an extra space + // before the rule representation + DIV({"class": "cssElementRuleContainer"}, + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}), + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateCascadeView: function(element) + { + //dispatch([Firebug.A11yModel], 'onBeforeCSSRulesAdded', [this]); + var rules = [], sections = [], usedProps = {}; + this.getInheritedRules(element, sections, usedProps); + this.getElementRules(element, rules, usedProps); + + if (rules.length || sections.length) + { + var inheritLabel = "Inherited from"; // $STR("InheritedFrom"); + var result = this.template.cascadedTag.replace({rules: rules, inherited: sections, + inheritLabel: inheritLabel}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + else + { + var result = FirebugReps.Warning.tag.replace({object: "EmptyElementCSS"}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + + // TODO: xxxpedro remove when there the external resource problem is fixed + if (externalStyleSheetURLs.length > 0) + externalStyleSheetWarning.tag.append({ + object: "The results here may be inaccurate because some " + + "stylesheets could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22" + }, this.panelNode); + }, + + getStylesheetURL: function(rule) + { + // if the parentStyleSheet.href is null, CSS std says its inline style. + // TODO: xxxpedro IE doesn't have rule.parentStyleSheet so we must fall back to the doc.location + if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href) + return rule.parentStyleSheet.href; + else + return this.selection.ownerDocument.location.href; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getInheritedRules: function(element, sections, usedProps) + { + var parent = element.parentNode; + if (parent && parent.nodeType == 1) + { + this.getInheritedRules(parent, sections, usedProps); + + var rules = []; + this.getElementRules(parent, rules, usedProps, true); + + if (rules.length) + sections.splice(0, 0, {element: parent, rules: rules}); + } + }, + + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + + // TODO: xxxpedro remove document specificity issue + //var eid = ElementCache(element); + //inspectedRules = ElementCSSRulesMap[eid]; + + inspectedRules = getElementCSSRules(element); + + if (inspectedRules) + { + for (var i = 0, length=inspectedRules.length; i < length; ++i) + { + var ruleId = inspectedRules[i]; + var ruleData = CSSRuleMap[ruleId]; + var rule = ruleData.rule; + + var ssid = ruleData.styleSheetId; + var parentStyleSheet = StyleSheetCache.get(ssid); + + var href = parentStyleSheet.externalURL ? parentStyleSheet.externalURL : parentStyleSheet.href; // Null means inline + + var instance = null; + //var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = false; + //var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + // + //var line = domUtils.getRuleLine(rule); + var line; + + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: ruleData.selector, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /* + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + try + { + inspectedRules = domUtils ? domUtils.getCSSStyleRules(element) : null; + } catch (exc) {} + + if (inspectedRules) + { + for (var i = 0; i < inspectedRules.Count(); ++i) + { + var rule = QI(inspectedRules.GetElementAt(i), nsIDOMCSSStyleRule); + + var href = rule.parentStyleSheet.href; // Null means inline + + var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + var line = domUtils.getRuleLine(rule); + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: rule.selectorText, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /**/ + markOverridenProps: function(props, usedProps, inheritMode) + { + for (var i = 0; i < props.length; ++i) + { + var prop = props[i]; + if ( usedProps.hasOwnProperty(prop.name) ) + { + var deadProps = usedProps[prop.name]; // all previous occurrences of this property + for (var j = 0; j < deadProps.length; ++j) + { + var deadProp = deadProps[j]; + if (!deadProp.disabled && !deadProp.wasInherited && deadProp.important && !prop.important) + prop.overridden = true; // new occurrence overridden + else if (!prop.disabled) + deadProp.overridden = true; // previous occurrences overridden + } + } + else + usedProps[prop.name] = []; + + prop.wasInherited = inheritMode ? true : false; + usedProps[prop.name].push(prop); // all occurrences of a property seen so far, by name + } + }, + + getStyleProperties: function(element, rules, usedProps, inheritMode) + { + var props = this.parseCSSProps(element.style, inheritMode); + this.addOldProperties(this.context, getElementXPath(element), inheritMode, props); + + sortProperties(props); + this.markOverridenProps(props, usedProps, inheritMode); + + if (props.length) + rules.splice(0, 0, + {rule: element, id: getElementXPath(element), + selector: "element.style", props: props, inherited: inheritMode}); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "css", + title: "Style", + parentPanel: "HTML", + order: 0, + + initialize: function() + { + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + Firebug.CSSStyleSheetPanel.prototype.initialize.apply(this, arguments); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + + //this.updateCascadeView(document.getElementsByTagName("h1")[0]); + //this.updateCascadeView(document.getElementById("build")); + + /* + this.onStateChange = bindFixed(this.contentStateCheck, this); + this.onHoverChange = bindFixed(this.contentStateCheck, this, STATE_HOVER); + this.onActiveChange = bindFixed(this.contentStateCheck, this, STATE_ACTIVE); + /**/ + }, + + ishow: function(state) + { + }, + + watchWindow: function(win) + { + if (domUtils) + { + // Normally these would not be required, but in order to update after the state is set + // using the options menu we need to monitor these global events as well + var doc = win.document; + ///addEvent(doc, "mouseover", this.onHoverChange); + ///addEvent(doc, "mousedown", this.onActiveChange); + } + }, + unwatchWindow: function(win) + { + var doc = win.document; + ///removeEvent(doc, "mouseover", this.onHoverChange); + ///removeEvent(doc, "mousedown", this.onActiveChange); + + if (isAncestor(this.stateChangeEl, doc)) + { + this.removeStateChangeHandlers(); + } + }, + + supportsObject: function(object) + { + return object instanceof Element ? 1 : 0; + }, + + updateView: function(element) + { + this.updateCascadeView(element); + if (domUtils) + { + this.contentState = safeGetContentState(element); + this.addStateChangeHandlers(element); + } + }, + + updateSelection: function(element) + { + if ( !instanceOf(element , "Element") ) // html supports SourceLink + return; + + if (sothinkInstalled) + { + FirebugReps.Warning.tag.replace({object: "SothinkWarning"}, this.panelNode); + return; + } + + /* + if (!domUtils) + { + FirebugReps.Warning.tag.replace({object: "DOMInspectorWarning"}, this.panelNode); + return; + } + /**/ + + if (!element) + return; + + this.updateView(element); + }, + + updateOption: function(name, value) + { + if (name == "showUserAgentCSS" || name == "expandShorthandProps") + this.refresh(); + }, + + getOptionsMenuItems: function() + { + var ret = [ + {label: "Show User Agent CSS", type: "checkbox", checked: Firebug.showUserAgentCSS, + command: bindFixed(Firebug.togglePref, Firebug, "showUserAgentCSS") }, + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") } + ]; + if (domUtils && this.selection) + { + var state = safeGetContentState(this.selection); + + ret.push("-"); + ret.push({label: ":active", type: "checkbox", checked: state & STATE_ACTIVE, + command: bindFixed(this.updateContentState, this, STATE_ACTIVE, state & STATE_ACTIVE)}); + ret.push({label: ":hover", type: "checkbox", checked: state & STATE_HOVER, + command: bindFixed(this.updateContentState, this, STATE_HOVER, state & STATE_HOVER)}); + } + return ret; + }, + + updateContentState: function(state, remove) + { + domUtils.setContentState(remove ? this.selection.ownerDocument.documentElement : this.selection, state); + this.refresh(); + }, + + addStateChangeHandlers: function(el) + { + this.removeStateChangeHandlers(); + + /* + addEvent(el, "focus", this.onStateChange); + addEvent(el, "blur", this.onStateChange); + addEvent(el, "mouseup", this.onStateChange); + addEvent(el, "mousedown", this.onStateChange); + addEvent(el, "mouseover", this.onStateChange); + addEvent(el, "mouseout", this.onStateChange); + /**/ + + this.stateChangeEl = el; + }, + + removeStateChangeHandlers: function() + { + var sel = this.stateChangeEl; + if (sel) + { + /* + removeEvent(sel, "focus", this.onStateChange); + removeEvent(sel, "blur", this.onStateChange); + removeEvent(sel, "mouseup", this.onStateChange); + removeEvent(sel, "mousedown", this.onStateChange); + removeEvent(sel, "mouseover", this.onStateChange); + removeEvent(sel, "mouseout", this.onStateChange); + /**/ + } + }, + + contentStateCheck: function(state) + { + if (!state || this.contentState & state) + { + var timeoutRunner = bindFixed(function() + { + var newState = safeGetContentState(this.selection); + if (newState != this.contentState) + { + this.context.invalidatePanels(this.name); + } + }, this); + + // Delay exec until after the event has processed and the state has been updated + setTimeout(timeoutRunner, 0); + } + } +}); + +function safeGetContentState(selection) +{ + try + { + return domUtils.getContentState(selection); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.safeGetContentState; EXCEPTION", e); + } +} + +// ************************************************************************************************ + +function CSSComputedElementPanel() {} + +CSSComputedElementPanel.prototype = extend(CSSElementPanel.prototype, +{ + template: domplate( + { + computedTag: + DIV({"class": "a11yCSSView", role : "list", "aria-label" : $STR('aria.labels.computed styles')}, + FOR("group", "$groups", + H1({"class": "cssInheritHeader groupHeader focusRow", role : "listitem"}, + SPAN({"class": "cssInheritLabel"}, "$group.title") + ), + TABLE({width: "100%", role : 'group'}, + TBODY({role : 'presentation'}, + FOR("prop", "$group.props", + TR({"class": 'focusRow computedStyleRow', role : 'listitem'}, + TD({"class": "stylePropName", role : 'presentation'}, "$prop.name"), + TD({"class": "stylePropValue", role : 'presentation'}, "$prop.value") + ) + ) + ) + ) + ) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateComputedView: function(element) + { + var win = isIE ? + element.ownerDocument.parentWindow : + element.ownerDocument.defaultView; + + var style = isIE ? + element.currentStyle : + win.getComputedStyle(element, ""); + + var groups = []; + + for (var groupName in styleGroups) + { + // TODO: xxxpedro i18n $STR + //var title = $STR("StyleGroup-" + groupName); + var title = styleGroupTitles[groupName]; + var group = {title: title, props: []}; + groups.push(group); + + var props = styleGroups[groupName]; + for (var i = 0; i < props.length; ++i) + { + var propName = props[i]; + var propValue = style.getPropertyValue ? + style.getPropertyValue(propName) : + ""+style[toCamelCase(propName)]; + + if (propValue === undefined || propValue === null) + continue; + + propValue = stripUnits(rgbToHex(propValue)); + if (propValue) + group.props.push({name: propName, value: propValue}); + } + } + + var result = this.template.computedTag.replace({groups: groups}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "computed", + title: "Computed", + parentPanel: "HTML", + order: 1, + + updateView: function(element) + { + this.updateComputedView(element); + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Refresh", command: bind(this.refresh, this) } + ]; + } +}); + +// ************************************************************************************************ +// CSSEditor + +function CSSEditor(doc) +{ + this.initializeInline(doc); +} + +CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var rule = Firebug.getRepObject(target); + var emptyProp = + { + // TODO: xxxpedro - uses charCode(255) to force the element being rendered, + // allowing webkit to get the correct position of the property name "span", + // when inserting a new CSS rule? + name: "", + value: "", + important: "" + }; + + if (insertWhere == "before") + return CSSPropTag.tag.insertBefore({prop: emptyProp, rule: rule}, target); + else + return CSSPropTag.tag.insertAfter({prop: emptyProp, rule: rule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + // We need to check the value first in order to avoid a problem in IE8 + // See Issue 3038: Empty (null) styles when adding CSS styles in Firebug Lite + if (!value) return; + + target.innerHTML = escapeForCss(value); + + var row = getAncestorByClass(target, "cssProp"); + if (hasClass(row, "disabledStyle")) + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(target); + + if (hasClass(target, "cssPropName")) + { + if (value && previousValue != value) // name of property has changed. + { + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + + if (propValue && propValue != "undefined") { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSEditor.saveEdit : "+previousValue+"->"+value+" = "+propValue+"\n"); + if (previousValue) + Firebug.CSSModule.removeProperty(rule, previousValue); + Firebug.CSSModule.setProperty(rule, value, parsedValue.value, parsedValue.priority); + } + } + else if (!value) // name of the property has been deleted, so remove the property. + Firebug.CSSModule.removeProperty(rule, previousValue); + } + else if (getAncestorByClass(target, "cssPropValue")) + { + var propName = getChildByClass(row, "cssPropName")[textContent]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + + if (FBTrace.DBG_CSS) + { + FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName +" = "+propValue+"\n"); + // FBTrace.sysout("CSSEditor.saveEdit BEFORE style:",style); + } + + if (value && value != "null") + { + var parsedValue = parsePriority(value); + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + } + else if (previousValue && previousValue != "null") + Firebug.CSSModule.removeProperty(rule, propName); + } + + this.panel.markChange(this.panel.name == "stylesheet"); + }, + + advanceToNext: function(target, charCode) + { + if (charCode == 58 /*":"*/ && hasClass(target, "cssPropName")) + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + if (hasClass(this.target, "cssPropName")) + return {start: 0, end: value.length-1}; + else + return parseCSSValue(value, offset); + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + if (hasClass(this.target, "cssPropName")) + { + return getCSSPropertyNames(); + } + else + { + var row = getAncestorByClass(this.target, "cssProp"); + var propName = getChildByClass(row, "cssPropName")[textContent]; + return getCSSKeywordsByProperty(propName); + } + } +}); + +//************************************************************************************************ +//CSSRuleEditor + +function CSSRuleEditor(doc) +{ + this.initializeInline(doc); + this.completeAsYouType = false; +} +CSSRuleEditor.uniquifier = 0; +CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var emptyRule = { + selector: "", + id: "", + props: [], + isSelectorEditable: true + }; + + if (insertWhere == "before") + return CSSStyleRuleTag.tag.insertBefore({rule: emptyRule}, target); + else + return CSSStyleRuleTag.tag.insertAfter({rule: emptyRule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSRuleEditor.saveEdit: '" + value + "' '" + previousValue + "'", target); + + target.innerHTML = escapeForCss(value); + + if (value === previousValue) return; + + var row = getAncestorByClass(target, "cssRule"); + var styleSheet = this.panel.location; + styleSheet = styleSheet.editStyleSheet ? styleSheet.editStyleSheet.sheet : styleSheet; + + var cssRules = styleSheet.cssRules; + var rule = Firebug.getRepObject(target), oldRule = rule; + var ruleIndex = cssRules.length; + if (rule || Firebug.getRepObject(row.nextSibling)) + { + var searchRule = rule || Firebug.getRepObject(row.nextSibling); + for (ruleIndex=0; ruleIndex b.name ? 1 : -1; + }); +} + +function getTopmostRuleLine(panelNode) +{ + for (var child = panelNode.firstChild; child; child = child.nextSibling) + { + if (child.offsetTop+child.offsetHeight > panelNode.scrollTop) + { + var rule = child.repObject; + if (rule) + return { + line: domUtils.getRuleLine(rule), + offset: panelNode.scrollTop-child.offsetTop + }; + } + } + return 0; +} + +function getStyleSheetCSS(sheet, context) +{ + if (sheet.ownerNode instanceof HTMLStyleElement) + return sheet.ownerNode.innerHTML; + else + return context.sourceCache.load(sheet.href).join(""); +} + +function getStyleSheetOwnerNode(sheet) { + for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet); + + return sheet.ownerNode; +} + +function scrollSelectionIntoView(panel) +{ + var selCon = getSelectionController(panel); + selCon.scrollSelectionIntoView( + nsISelectionController.SELECTION_NORMAL, + nsISelectionController.SELECTION_FOCUS_REGION, true); +} + +function getSelectionController(panel) +{ + var browser = Firebug.chrome.getPanelBrowser(panel); + return browser.docShell.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsISelectionDisplay) + .QueryInterface(nsISelectionController); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.CSSModule); +Firebug.registerPanel(Firebug.CSSStyleSheetPanel); +Firebug.registerPanel(CSSElementPanel); +Firebug.registerPanel(CSSComputedElementPanel); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Script Module + +Firebug.Script = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Script") : null; + }, + + selectSourceCode: function(index) + { + this.getPanel().selectSourceCode(index); + } +}); + +Firebug.registerModule(Firebug.Script); + + +// ************************************************************************************************ +// Script Panel + +function ScriptPanel(){}; + +ScriptPanel.prototype = extend(Firebug.Panel, +{ + name: "Script", + title: "Script", + + selectIndex: 0, // index of the current selectNode's option + sourceIndex: -1, // index of the script node, based in doc.getElementsByTagName("script") + + options: { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var scripts = doc.getElementsByTagName("script"); + var selectNode = this.selectNode = createElement("select"); + + for(var i=0, script; script=scripts[i]; i++) + { + // Don't show Firebug Lite source code in the list of options + if (Firebug.ignoreFirebugElements && script.getAttribute("firebugIgnore")) + continue; + + var fileName = getFileName(script.src) || getFileName(doc.location.href); + var option = createElement("option", {value:i}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }; + + this.toolButtonsNode.appendChild(selectNode); + }, + + initialize: function() + { + // we must render the code first, so the persistent state can be restore + this.selectSourceCode(this.selectIndex); + + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.selectNode, "change", this.onChangeSelect); + }, + + shutdown: function() + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + detach: function(oldChrome, newChrome) + { + Firebug.Panel.detach.apply(this, arguments); + + var oldPanel = oldChrome.getPanel("Script"); + var index = oldPanel.selectIndex; + + this.selectNode.selectedIndex = index; + this.selectIndex = index; + this.sourceIndex = -1; + }, + + onChangeSelect: function(event) + { + var select = this.selectNode; + + this.selectIndex = select.selectedIndex; + + var option = select.options[select.selectedIndex]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + selectSourceCode: function(index) + { + var select = this.selectNode; + select.selectedIndex = index; + + var option = select.options[index]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + renderSourceCode: function(index) + { + if (this.sourceIndex != index) + { + var renderProcess = function renderProcess(src) + { + var html = [], + hl = 0; + + src = isIE && !isExternal ? + src+'\n' : // IE put an extra line when reading source of local resources + '\n'+src; + + // find the number of lines of code + src = src.replace(/\n\r|\r\n/g, "\n"); + var match = src.match(/[\n]/g); + var lines=match ? match.length : 0; + + // render the full source code + line numbers html + html[hl++] = '
      ';
      +                html[hl++] = escapeHTML(src);
      +                html[hl++] = '
      '; + + // render the line number divs + for(var l=1, lines; l<=lines; l++) + { + html[hl++] = '
      '; + html[hl++] = l; + html[hl++] = '
      '; + } + + html[hl++] = '
      '; + + updatePanel(html); + }; + + var updatePanel = function(html) + { + self.panelNode.innerHTML = html.join(""); + + // IE needs this timeout, otherwise the panel won't scroll + setTimeout(function(){ + self.synchronizeUI(); + },0); + }; + + var onFailure = function() + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, self.panelNode); + }; + + var self = this; + + var doc = Firebug.browser.document; + var script = doc.getElementsByTagName("script")[index]; + var url = getScriptURL(script); + var isExternal = url && url != doc.location.href; + + try + { + if (isExternal) + { + Ajax.request({url: url, onSuccess: renderProcess, onFailure: onFailure}); + } + else + { + var src = script.innerHTML; + renderProcess(src); + } + } + catch(e) + { + onFailure(); + } + + this.sourceIndex = index; + } + } +}); + +Firebug.registerPanel(ScriptPanel); + + +// ************************************************************************************************ + + +var getScriptURL = function getScriptURL(script) +{ + var reFile = /([^\/\?#]+)(#.+)?$/; + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = Firebug.browser.document; + + var file = reFile.exec(script.src); + + if (file) + { + var fileName = file[1]; + var fileOptions = file[2]; + + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; + + } + // relative path + else + { + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(doc.location.href)[1]; + + // "../some/path" + if (backDir) + { + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + return path + fileName; + } +}; + +var getFileName = function getFileName(path) +{ + if (!path) return ""; + + var match = path && path.match(/[^\/]+(\?.*)?(#.*)?$/); + + return match && match[0] || path; +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var ElementCache = Firebug.Lite.Cache.Element; + +var insertSliceSize = 18; +var insertInterval = 40; + +var ignoreVars = +{ + "__firebug__": 1, + "eval": 1, + + // We are forced to ignore Java-related variables, because + // trying to access them causes browser freeze + "java": 1, + "sun": 1, + "Packages": 1, + "JavaArray": 1, + "JavaMember": 1, + "JavaObject": 1, + "JavaClass": 1, + "JavaPackage": 1, + "_firebug": 1, + "_FirebugConsole": 1, + "_FirebugCommandLine": 1 +}; + +if (Firebug.ignoreFirebugElements) + ignoreVars[Firebug.Lite.Cache.ID] = 1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var memberPanelRep = + isIE6 ? + {"class": "memberLabel $member.type\\Label", href: "javacript:void(0)"} + : + {"class": "memberLabel $member.type\\Label"}; + +var RowTag = + TR({"class": "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren", role : 'presentation', + level: "$member.level"}, + TD({"class": "memberLabelCell", style: "padding-left: $member.indent\\px", role : 'presentation'}, + A(memberPanelRep, + SPAN({}, "$member.name") + ) + ), + TD({"class": "memberValueCell", role : 'presentation'}, + TAG("$member.tag", {object: "$member.value"}) + ) + ); + +var WatchRowTag = + TR({"class": "watchNewRow", level: 0}, + TD({"class": "watchEditCell", colspan: 2}, + DIV({"class": "watchEditBox a11yFocusNoTab", role: "button", 'tabindex' : '0', + 'aria-label' : $STR('press enter to add new watch expression')}, + $STR("NewWatch") + ) + ) + ); + +var SizerRow = + TR({role : 'presentation'}, + TD({width: "30%"}), + TD({width: "70%"}) + ); + +var domTableClass = isIElt8 ? "domTable domTableIE" : "domTable"; +var DirTablePlate = domplate(Firebug.Rep, +{ + tag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, onclick: "$onClick", role :"tree"}, + TBODY({role: 'presentation'}, + SizerRow, + FOR("member", "$object|memberIterator", RowTag) + ) + ), + + watchTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow, + WatchRowTag + ) + ), + + tableTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow + ) + ), + + rowTag: + FOR("member", "$members", RowTag), + + memberIterator: function(object, level) + { + return getMembers(object, level); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + if (!isLeftClick(event)) + return; + + var target = event.target || event.srcElement; + + var row = getAncestorByClass(target, "memberRow"); + var label = getAncestorByClass(target, "memberLabel"); + if (label && hasClass(row, "hasChildren")) + { + var row = label.parentNode.parentNode; + this.toggleRow(row); + } + else + { + var object = Firebug.getRepObject(target); + if (typeof(object) == "function") + { + Firebug.chrome.select(object, "script"); + cancelEvent(event); + } + else if (event.detail == 2 && !object) + { + var panel = row.parentNode.parentNode.domPanel; + if (panel) + { + var rowValue = panel.getRowPropertyValue(row); + if (typeof(rowValue) == "boolean") + panel.setPropertyValue(row, !rowValue); + else + panel.editProperty(row); + + cancelEvent(event); + } + } + } + + return false; + }, + + toggleRow: function(row) + { + var level = parseInt(row.getAttribute("level")); + var toggles = row.parentNode.parentNode.toggles; + + if (hasClass(row, "opened")) + { + removeClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Remove the path from the toggle tree + for (var i = 0; i < path.length; ++i) + { + if (i == path.length-1) + delete toggles[path[i]]; + else + toggles = toggles[path[i]]; + } + } + + var rowTag = this.rowTag; + var tbody = row.parentNode; + + setTimeout(function() + { + for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling) + { + if (parseInt(firstRow.getAttribute("level")) <= level) + break; + + tbody.removeChild(firstRow); + } + }, row.insertTimeout ? row.insertTimeout : 0); + } + else + { + setClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Mark the path in the toggle tree + for (var i = 0; i < path.length; ++i) + { + var name = path[i]; + if (toggles.hasOwnProperty(name)) + toggles = toggles[name]; + else + toggles = toggles[name] = {}; + } + } + + var value = row.lastChild.firstChild.repObject; + var members = getMembers(value, level+1); + + var rowTag = this.rowTag; + var lastRow = row; + + var delay = 0; + //var setSize = members.length; + //var rowCount = 1; + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + setTimeout(function() + { + if (lastRow.parentNode) + { + var result = rowTag.insertRows({members: slice}, lastRow); + lastRow = result[1]; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [null, result, rowCount, setSize]); + //rowCount += insertSliceSize; + } + if (isLast) + row.removeAttribute("insertTimeout"); + }, delay); + } + + delay += insertInterval; + } + + row.insertTimeout = delay; + } + } +}); + + + +// ************************************************************************************************ + +Firebug.DOMBasePanel = function() {} + +Firebug.DOMBasePanel.prototype = extend(Firebug.Panel, +{ + tag: DirTablePlate.tableTag, + + getRealObject: function(object) + { + // TODO: Move this to some global location + // TODO: Unwrapping should be centralized rather than sprinkling it around ad hoc. + // TODO: We might be able to make this check more authoritative with QueryInterface. + if (!object) return object; + if (object.wrappedJSObject) return object.wrappedJSObject; + return object; + }, + + rebuild: function(update, scrollTop) + { + //dispatch([Firebug.A11yModel], 'onBeforeDomUpdateSelection', [this]); + var members = getMembers(this.selection); + expandMembers(members, this.toggles, 0, 0); + + this.showMembers(members, update, scrollTop); + + //TODO: xxxpedro statusbar + if (!this.parentPanel) + updateStatusBar(this); + }, + + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!tbody.lastChild) return; + + result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //rowCount += insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop) + panelNode.scrollTop = priorScrollTop; + + + // enable to measure rendering performance + //if (isLast) alert(new Date().getTime() - renderStart + "ms"); + + + }, delay)); + + delay += insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + + /* + // new + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + var _insertSliceSize = insertSliceSize; + var _insertInterval = insertInterval; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + var lastSkip = renderStart, now; + + while (members.length) + { + with({slice: members.splice(0, _insertSliceSize), isLast: !members.length}) + { + var _tbody = tbody; + var _rowTag = rowTag; + var _panelNode = panelNode; + var _priorScrollTop = priorScrollTop; + + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!_tbody.lastChild) return; + + result = _rowTag.insertRows({members: slice}, _tbody.lastChild); + + //rowCount += _insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((_panelNode.scrollHeight + _panelNode.offsetHeight) >= _priorScrollTop) + _panelNode.scrollTop = _priorScrollTop; + + + // enable to measure rendering performance + //alert("gap: " + (new Date().getTime() - lastSkip)); + //lastSkip = new Date().getTime(); + + //if (isLast) alert("new: " + (new Date().getTime() - renderStart) + "ms"); + + }, delay)); + + delay += _insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + /**/ + + showEmptyMembers: function() + { + FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode); + }, + + findPathObject: function(object) + { + var pathIndex = -1; + for (var i = 0; i < this.objectPath.length; ++i) + { + // IE needs === instead of == or otherwise some objects will + // be considered equal to different objects, returning the + // wrong index of the objectPath array + if (this.getPathObject(i) === object) + return i; + } + + return -1; + }, + + getPathObject: function(index) + { + var object = this.objectPath[index]; + + if (object instanceof Property) + return object.getObject(); + else + return object; + }, + + getRowObject: function(row) + { + var object = getRowOwnerObject(row); + return object ? object : this.selection; + }, + + getRowPropertyValue: function(row) + { + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object) + { + var propName = getRowName(row); + + if (object instanceof jsdIStackFrame) + return Firebug.Debugger.evaluate(propName, this.context); + else + return object[propName]; + } + }, + /* + copyProperty: function(row) + { + var value = this.getRowPropertyValue(row); + copyToClipboard(value); + }, + + editProperty: function(row, editValue) + { + if (hasClass(row, "watchNewRow")) + { + if (this.context.stopped) + Firebug.Editor.startEditing(row, ""); + else if (Firebug.Console.isAlwaysEnabled()) // not stopped in debugger, need command line + { + if (Firebug.CommandLine.onCommandLineFocus()) + Firebug.Editor.startEditing(row, ""); + else + row.innerHTML = $STR("warning.Command line blocked?"); + } + else + row.innerHTML = $STR("warning.Console must be enabled"); + } + else if (hasClass(row, "watchRow")) + Firebug.Editor.startEditing(row, getRowName(row)); + else + { + var object = this.getRowObject(row); + this.context.thisValue = object; + + if (!editValue) + { + var propValue = this.getRowPropertyValue(row); + + var type = typeof(propValue); + if (type == "undefined" || type == "number" || type == "boolean") + editValue = propValue; + else if (type == "string") + editValue = "\"" + escapeJS(propValue) + "\""; + else if (propValue == null) + editValue = "null"; + else if (object instanceof Window || object instanceof jsdIStackFrame) + editValue = getRowName(row); + else + editValue = "this." + getRowName(row); + } + + + Firebug.Editor.startEditing(row, editValue); + } + }, + + deleteProperty: function(row) + { + if (hasClass(row, "watchRow")) + this.deleteWatch(row); + else + { + var object = getRowOwnerObject(row); + if (!object) + object = this.selection; + object = this.getRealObject(object); + + if (object) + { + var name = getRowName(row); + try + { + delete object[name]; + } + catch (exc) + { + return; + } + + this.rebuild(true); + this.markChange(); + } + } + }, + + setPropertyValue: function(row, value) // value must be string + { + if(FBTrace.DBG_DOM) + { + FBTrace.sysout("row: "+row); + FBTrace.sysout("value: "+value+" type "+typeof(value), value); + } + + var name = getRowName(row); + if (name == "this") + return; + + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object && !(object instanceof jsdIStackFrame)) + { + // unwrappedJSObject.property = unwrappedJSObject + Firebug.CommandLine.evaluate(value, this.context, object, this.context.getGlobalScope(), + function success(result, context) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate success object["+name+"]="+result+" type "+typeof(result), result); + object[name] = result; + }, + function failed(exc, context) + { + try + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate failed with exc:"+exc+" object["+name+"]="+value+" type "+typeof(value), exc); + // If the value doesn't parse, then just store it as a string. Some users will + // not realize they're supposed to enter a JavaScript expression and just type + // literal text + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + ); + } + else if (this.context.stopped) + { + try + { + Firebug.CommandLine.evaluate(name+"="+value, this.context); + } + catch (exc) + { + try + { + // See catch block above... + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + } + + this.rebuild(true); + this.markChange(); + }, + + highlightRow: function(row) + { + if (this.highlightedRow) + cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context); + + this.highlightedRow = row; + + if (row) + setClassTimed(row, "jumpHighlight", this.context); + },/**/ + + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + create: function() + { + // TODO: xxxpedro + this.context = Firebug.browser; + + this.objectPath = []; + this.propertyPath = []; + this.viewPath = []; + this.pathIndex = -1; + this.toggles = {}; + + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.panelNode, "mousemove", this.onMouseMove); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + /* + destroy: function(state) + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + + if (this.pathIndex) + state.pathIndex = this.pathIndex; + if (this.viewPath) + state.viewPath = this.viewPath; + if (this.propertyPath) + state.propertyPath = this.propertyPath; + + if (this.propertyPath.length > 0 && !this.propertyPath[1]) + state.firstSelection = persistObject(this.getPathObject(1), this.context); + + Firebug.Panel.destroy.apply(this, arguments); + }, + /**/ + + ishow: function(state) + { + if (this.context.loaded && !this.selection) + { + if (!state) + { + this.select(null); + return; + } + if (state.viewPath) + this.viewPath = state.viewPath; + if (state.propertyPath) + this.propertyPath = state.propertyPath; + + var defaultObject = this.getDefaultSelection(this.context); + var selectObject = defaultObject; + + if (state.firstSelection) + { + var restored = state.firstSelection(this.context); + if (restored) + { + selectObject = restored; + this.objectPath = [defaultObject, restored]; + } + else + this.objectPath = [defaultObject]; + } + else + this.objectPath = [defaultObject]; + + if (this.propertyPath.length > 1) + { + for (var i = 1; i < this.propertyPath.length; ++i) + { + var name = this.propertyPath[i]; + if (!name) + continue; + + var object = selectObject; + try + { + selectObject = object[name]; + } + catch (exc) + { + selectObject = null; + } + + if (selectObject) + { + this.objectPath.push(new Property(object, name)); + } + else + { + // If we can't access a property, just stop + this.viewPath.splice(i); + this.propertyPath.splice(i); + this.objectPath.splice(i); + selectObject = this.getPathObject(this.objectPath.length-1); + break; + } + } + } + + var selection = state.pathIndex <= this.objectPath.length-1 + ? this.getPathObject(state.pathIndex) + : this.getPathObject(this.objectPath.length-1); + + this.select(selection); + } + }, + /* + hide: function() + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + }, + /**/ + + supportsObject: function(object) + { + if (object == null) + return 1000; + + if (typeof(object) == "undefined") + return 1000; + else if (object instanceof SourceLink) + return 0; + else + return 1; // just agree to support everything but not agressively. + }, + + refresh: function() + { + this.rebuild(true); + }, + + updateSelection: function(object) + { + var previousIndex = this.pathIndex; + var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex]; + + var newPath = this.pathToAppend; + delete this.pathToAppend; + + var pathIndex = this.findPathObject(object); + if (newPath || pathIndex == -1) + { + this.toggles = {}; + + if (newPath) + { + // Remove everything after the point where we are inserting, so we + // essentially replace it with the new path + if (previousView) + { + if (this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + var start = previousIndex + 1, + // Opera needs the length argument in splice(), otherwise + // it will consider that only one element should be removed + length = this.objectPath.length - start; + + this.objectPath.splice(start, length); + this.propertyPath.splice(start, length); + this.viewPath.splice(start, length); + } + + var value = this.getPathObject(previousIndex); + if (!value) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection no pathObject for "+previousIndex+"\n"); + return; + } + + for (var i = 0, length = newPath.length; i < length; ++i) + { + var name = newPath[i]; + var object = value; + try + { + value = value[name]; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection FAILS at path_i="+i+" for name:"+name+"\n"); + return; + } + + ++this.pathIndex; + this.objectPath.push(new Property(object, name)); + this.propertyPath.push(name); + this.viewPath.push({toggles: this.toggles, scrollTop: 0}); + } + } + else + { + this.toggles = {}; + + var win = Firebug.browser.window; + //var win = this.context.getGlobalScope(); + if (object === win) + { + this.pathIndex = 0; + this.objectPath = [win]; + this.propertyPath = [null]; + this.viewPath = [{toggles: this.toggles, scrollTop: 0}]; + } + else + { + this.pathIndex = 1; + this.objectPath = [win, object]; + this.propertyPath = [null, null]; + this.viewPath = [ + {toggles: {}, scrollTop: 0}, + {toggles: this.toggles, scrollTop: 0} + ]; + } + } + + this.panelNode.scrollTop = 0; + this.rebuild(); + } + else + { + this.pathIndex = pathIndex; + + var view = this.viewPath[pathIndex]; + this.toggles = view.toggles; + + // Persist the current scroll location + if (previousView && this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + this.rebuild(false, view.scrollTop); + } + }, + + getObjectPath: function(object) + { + return this.objectPath; + }, + + getDefaultSelection: function() + { + return Firebug.browser.window; + //return this.context.getGlobalScope(); + }/*, + + updateOption: function(name, value) + { + const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1, + showDOMFuncs: 1, showDOMConstants: 1}; + if ( optionMap.hasOwnProperty(name) ) + this.rebuild(true); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowUserProps", "showUserProps"), + optionMenu("ShowUserFuncs", "showUserFuncs"), + optionMenu("ShowDOMProps", "showDOMProps"), + optionMenu("ShowDOMFuncs", "showDOMFuncs"), + optionMenu("ShowDOMConstants", "showDOMConstants"), + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ]; + }, + + getContextMenuItems: function(object, target) + { + var row = getAncestorByClass(target, "memberRow"); + + var items = []; + + if (row) + { + var rowName = getRowName(row); + var rowObject = this.getRowObject(row); + var rowValue = this.getRowPropertyValue(row); + + var isWatch = hasClass(row, "watchRow"); + var isStackFrame = rowObject instanceof jsdIStackFrame; + + if (typeof(rowValue) == "string" || typeof(rowValue) == "number") + { + // Functions already have a copy item in their context menu + items.push( + "-", + {label: "CopyValue", + command: bindFixed(this.copyProperty, this, row) } + ); + } + + items.push( + "-", + {label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"), + command: bindFixed(this.editProperty, this, row) } + ); + + if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName))) + { + items.push( + {label: isWatch ? "DeleteWatch" : "DeleteProperty", + command: bindFixed(this.deleteProperty, this, row) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ); + + return items; + }, + + getEditor: function(target, value) + { + if (!this.editor) + this.editor = new DOMEditor(this.document); + + return this.editor; + }/**/ +}); + +// ************************************************************************************************ + +// TODO: xxxpedro statusbar +var updateStatusBar = function(panel) +{ + var path = panel.propertyPath; + var index = panel.pathIndex; + + var r = []; + + for (var i=0, l=path.length; i'); + r.push(i==0 ? "window" : path[i] || "Object"); + r.push('
      '); + + if(i < l-1) + r.push('>'); + } + panel.statusBarNode.innerHTML = r.join(""); +}; + + +var DOMMainPanel = Firebug.DOMPanel = function () {}; + +Firebug.DOMPanel.DirTable = DirTablePlate; + +DOMMainPanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + onClickStatusBar: function(event) + { + var target = event.srcElement || event.target; + var element = getAncestorByClass(target, "fbHover"); + + if(element) + { + var pathIndex = element.getAttribute("pathIndex"); + + if(pathIndex) + { + this.select(this.getPathObject(pathIndex)); + } + } + }, + + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + this.select(target.repObject, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOM", + title: "DOM", + searchable: true, + statusSeparator: ">", + + options: { + hasToolButtons: true, + hasStatusBar: true + }, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + + //TODO: xxxpedro + this.onClickStatusBar = bind(this.onClickStatusBar, this); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(oldPanelNode) + { + //this.panelNode.addEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'console']); + + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro dom + this.ishow(); + + //TODO: xxxpedro + addEvent(this.statusBarNode, "click", this.onClickStatusBar); + }, + + shutdown: function() + { + //this.panelNode.removeEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'console']); + + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }/*, + + search: function(text, reverse) + { + if (!text) + { + delete this.currentSearch; + this.highlightRow(null); + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + row = this.currentSearch.findNext(true, undefined, reverse, Firebug.searchCaseSensitive); + else + { + function findRow(node) { return getAncestorByClass(node, "memberRow"); } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.searchCaseSensitive); + } + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + + scrollIntoCenterView(row, this.panelNode); + + this.highlightRow(row); + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, null]); + return false; + } + }/**/ +}); + +Firebug.registerPanel(DOMMainPanel); + + +// ************************************************************************************************ + + + +// ************************************************************************************************ +// Local Helpers + +var getMembers = function getMembers(object, level) // we expect object to be user-level object wrapped in security blanket +{ + if (!level) + level = 0; + + var ordinals = [], userProps = [], userClasses = [], userFuncs = [], + domProps = [], domFuncs = [], domConstants = []; + + try + { + var domMembers = getDOMMembers(object); + //var domMembers = {}; // TODO: xxxpedro + //var domConstantMap = {}; // TODO: xxxpedro + + if (object.wrappedJSObject) + var insecureObject = object.wrappedJSObject; + else + var insecureObject = object; + + // IE function prototype is not listed in (for..in) + if (isIE && isFunction(object)) + addMember("user", userProps, "prototype", object.prototype, level); + + for (var name in insecureObject) // enumeration is safe + { + if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined. + continue; + + var val; + try + { + val = insecureObject[name]; // getter is safe + } + catch (exc) + { + // Sometimes we get exceptions trying to access certain members + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers cannot access "+name, exc); + } + + var ordinal = parseInt(name); + if (ordinal || ordinal == 0) + { + addMember("ordinal", ordinals, name, val, level); + } + else if (isFunction(val)) + { + if (isClassFunction(val) && !(name in domMembers)) + addMember("userClass", userClasses, name, val, level); + else if (name in domMembers) + addMember("domFunction", domFuncs, name, val, level, domMembers[name]); + else + addMember("userFunction", userFuncs, name, val, level); + } + else + { + //TODO: xxxpedro + /* + var getterFunction = insecureObject.__lookupGetter__(name), + setterFunction = insecureObject.__lookupSetter__(name), + prefix = ""; + + if(getterFunction && !setterFunction) + prefix = "get "; + /**/ + + var prefix = ""; + + if (name in domMembers && !(name in domConstantMap)) + addMember("dom", domProps, (prefix+name), val, level, domMembers[name]); + else if (name in domConstantMap) + addMember("dom", domConstants, (prefix+name), val, level); + else + addMember("user", userProps, (prefix+name), val, level); + } + } + } + catch (exc) + { + // Sometimes we get exceptions just from trying to iterate the members + // of certain objects, like StorageList, but don't let that gum up the works + throw exc; + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers FAILS: ", exc); + //throw exc; + } + + function sortName(a, b) { return a.name > b.name ? 1 : -1; } + function sortOrder(a, b) { return a.order > b.order ? 1 : -1; } + + var members = []; + + members.push.apply(members, ordinals); + + Firebug.showUserProps = true; // TODO: xxxpedro + Firebug.showUserFuncs = true; // TODO: xxxpedro + Firebug.showDOMProps = true; + Firebug.showDOMFuncs = true; + Firebug.showDOMConstants = true; + + if (Firebug.showUserProps) + { + userProps.sort(sortName); + members.push.apply(members, userProps); + } + + if (Firebug.showUserFuncs) + { + userClasses.sort(sortName); + members.push.apply(members, userClasses); + + userFuncs.sort(sortName); + members.push.apply(members, userFuncs); + } + + if (Firebug.showDOMProps) + { + domProps.sort(sortName); + members.push.apply(members, domProps); + } + + if (Firebug.showDOMFuncs) + { + domFuncs.sort(sortName); + members.push.apply(members, domFuncs); + } + + if (Firebug.showDOMConstants) + members.push.apply(members, domConstants); + + return members; +} + +function expandMembers(members, toggles, offset, level) // recursion starts with offset=0, level=0 +{ + var expanded = 0; + for (var i = offset; i < members.length; ++i) + { + var member = members[i]; + if (member.level > level) + break; + + if ( toggles.hasOwnProperty(member.name) ) + { + member.open = "opened"; // member.level <= level && member.name in toggles. + + var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1 + + var args = [i+1, 0]; + args.push.apply(args, newMembers); + members.splice.apply(members, args); + + /* + if (FBTrace.DBG_DOM) + { + FBTrace.sysout("expandMembers member.name", member.name); + FBTrace.sysout("expandMembers toggles", toggles); + FBTrace.sysout("expandMembers toggles[member.name]", toggles[member.name]); + FBTrace.sysout("dom.expandedMembers level: "+level+" member", member); + } + /**/ + + expanded += newMembers.length; + i += newMembers.length + expandMembers(members, toggles[member.name], i+1, level+1); + } + } + + return expanded; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +function isClassFunction(fn) +{ + try + { + for (var name in fn.prototype) + return true; + } catch (exc) {} + return false; +} + +var hasProperties = function hasProperties(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + + // IE function prototype is not listed in (for..in) + if (isFunction(ob)) return true; + + return false; +} + +FBL.ErrorCopy = function(message) +{ + this.message = message; +}; + +var addMember = function addMember(type, props, name, value, level, order) +{ + var rep = Firebug.getRep(value); // do this first in case a call to instanceof reveals contents + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var ErrorCopy = function(){}; //TODO: xxxpedro + + var valueType = typeof(value); + var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) && + (isFunction(value) || (valueType == "object" && value != null) + || (valueType == "string" && value.length > Firebug.stringCropLength)); + + props.push({ + name: name, + value: value, + type: type, + rowClass: "memberRow-"+type, + open: "", + order: order, + level: level, + indent: level*16, + hasChildren: hasChildren, + tag: tag + }); +} + +var getWatchRowIndex = function getWatchRowIndex(row) +{ + var index = -1; + for (; row && hasClass(row, "watchRow"); row = row.previousSibling) + ++index; + return index; +} + +var getRowName = function getRowName(row) +{ + var node = row.firstChild; + return node.textContent ? node.textContent : node.innerText; +} + +var getRowValue = function getRowValue(row) +{ + return row.lastChild.firstChild.repObject; +} + +var getRowOwnerObject = function getRowOwnerObject(row) +{ + var parentRow = getParentRow(row); + if (parentRow) + return getRowValue(parentRow); +} + +var getParentRow = function getParentRow(row) +{ + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + return row; + } +} + +var getPath = function getPath(row) +{ + var name = getRowName(row); + var path = [name]; + + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + { + var name = getRowName(row); + path.splice(0, 0, name); + + --level; + } + } + + return path; +} + +// ************************************************************************************************ + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// DOM Module + +Firebug.DOM = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("DOM") : null; + } +}); + +Firebug.registerModule(Firebug.DOM); + + +// ************************************************************************************************ +// DOM Panel + +var lastHighlightedObject; + +function DOMSidePanel(){}; + +DOMSidePanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + var object = target.repObject; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + /* + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + object = object ? object.repObject : null; + + if(!object) return; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + /**/ + + + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOMSidePanel", + parentPanel: "HTML", + title: "DOM", + + options: { + hasToolButtons: true + }, + + isInitialized: false, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + }, + + initialize: function(){ + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }, + + reattach: function(oldChrome) + { + //this.isInitialized = oldChrome.getPanel("DOM").isInitialized; + this.toggles = oldChrome.getPanel("DOMSidePanel").toggles; + } + +}); + +Firebug.registerPanel(DOMSidePanel); + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.FBTrace = {}; + +(function() { +// ************************************************************************************************ + +var traceOptions = { + DBG_TIMESTAMP: 1, + DBG_INITIALIZE: 1, + DBG_CHROME: 1, + DBG_ERRORS: 1, + DBG_DISPATCH: 1, + DBG_CSS: 1 +}; + +this.module = null; + +this.initialize = function() +{ + if (!this.messageQueue) + this.messageQueue = []; + + for (var name in traceOptions) + this[name] = traceOptions[name]; +}; + +// ************************************************************************************************ +// FBTrace API + +this.sysout = function() +{ + return this.logFormatted(arguments, ""); +}; + +this.dumpProperties = function(title, object) +{ + return this.logFormatted("dumpProperties() not supported.", "warning"); +}; + +this.dumpStack = function() +{ + return this.logFormatted("dumpStack() not supported.", "warning"); +}; + +this.flush = function(module) +{ + this.module = module; + + var queue = this.messageQueue; + this.messageQueue = []; + + for (var i = 0; i < queue.length; ++i) + this.writeMessage(queue[i][0], queue[i][1], queue[i][2]); +}; + +this.getPanel = function() +{ + return this.module ? this.module.getPanel() : null; +}; + +//************************************************************************************************* + +this.logFormatted = function(objects, className) +{ + var html = this.DBG_TIMESTAMP ? [getTimestamp(), " | "] : []; + var length = objects.length; + + for (var i = 0; i < length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + + if (i == 0) + { + html.push(""); + appendText(object, html); + html.push(""); + } + else + appendText(object, html); + } + + return this.logRow(html, className); +}; + +this.logRow = function(message, className) +{ + var panel = this.getPanel(); + + if (panel && panel.panelNode) + this.writeMessage(message, className); + else + { + this.messageQueue.push([message, className]); + } + + return this.LOG_COMMAND; +}; + +this.writeMessage = function(message, className) +{ + var container = this.getPanel().containerNode; + var isScrolledToBottom = + container.scrollTop + container.offsetHeight >= container.scrollHeight; + + this.writeRow.call(this, message, className); + + if (isScrolledToBottom) + container.scrollTop = container.scrollHeight - container.offsetHeight; +}; + +this.appendRow = function(row) +{ + var container = this.getPanel().panelNode; + container.appendChild(row); +}; + +this.writeRow = function(message, className) +{ + var row = this.getPanel().panelNode.ownerDocument.createElement("div"); + row.className = "logRow" + (className ? " logRow-"+className : ""); + row.innerHTML = message.join(""); + this.appendRow(row); +}; + +//************************************************************************************************* + +function appendText(object, html) +{ + html.push(escapeHTML(objectToString(object))); +}; + +function getTimestamp() +{ + var now = new Date(); + var ms = "" + (now.getMilliseconds() / 1000).toFixed(3); + ms = ms.substr(2); + + return now.toLocaleTimeString() + "." + ms; +}; + +//************************************************************************************************* + +var HTMLtoEntity = +{ + "<": "<", + ">": ">", + "&": "&", + "'": "'", + '"': """ +}; + +function replaceChars(ch) +{ + return HTMLtoEntity[ch]; +}; + +function escapeHTML(value) +{ + return (value+"").replace(/[<>&"']/g, replaceChars); +}; + +//************************************************************************************************* + +function objectToString(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +}).apply(FBL.FBTrace); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// If application isn't in trace mode, the FBTrace panel won't be loaded +if (!Env.Options.enableTrace) return; + +// ************************************************************************************************ +// FBTrace Module + +Firebug.Trace = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Trace") : null; + }, + + clear: function() + { + this.getPanel().panelNode.innerHTML = ""; + } +}); + +Firebug.registerModule(Firebug.Trace); + + +// ************************************************************************************************ +// FBTrace Panel + +function TracePanel(){}; + +TracePanel.prototype = extend(Firebug.Panel, +{ + name: "Trace", + title: "Trace", + + options: { + hasToolButtons: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.clearButton = new Button({ + caption: "Clear", + title: "Clear FBTrace logs", + owner: Firebug.Trace, + onClick: Firebug.Trace.clear + }); + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + this.clearButton.initialize(); + } + +}); + +Firebug.registerPanel(TracePanel); + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; + +var parentPanelMap = {}; + + +var registerModule = Firebug.registerModule; +var registerPanel = Firebug.registerPanel; + +// ************************************************************************************************ +append(Firebug, +{ + extend: function(fn) + { + if (Firebug.chrome && Firebug.chrome.addPanel) + { + var namespace = ns(fn); + fn.call(namespace, FBL); + } + else + { + setTimeout(function(){Firebug.extend(fn);},100); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + registerModule.apply(Firebug, arguments); + + modules.push.apply(modules, arguments); + + dispatch(modules, "initialize", []); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + registerPanel.apply(Firebug, arguments); + + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + // TODO: xxxpedro investigate why Dev Panel throws an error + if (panelType.prototype.name == "Dev") continue; + + panelTypeMap[panelType.prototype.name] = arguments[i]; + + var parentPanelName = panelType.prototype.parentPanel; + if (parentPanelName) + { + parentPanelMap[parentPanelName] = 1; + } + else + { + var panelName = panelType.prototype.name; + var chrome = Firebug.chrome; + chrome.addPanel(panelName); + + // tab click handler + var onTabClick = function onTabClick() + { + chrome.selectPanel(panelName); + return false; + }; + + chrome.addController([chrome.panelMap[panelName].tabNode, "mousedown", onTabClick]); + } + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + } + +}); + + + + +// ************************************************************************************************ +}}); + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +FirebugChrome.Skin = +{ + CSS: '.collapsed{display:none;}[collapsed="true"]{display:none;}#fbCSS{padding:0 !important;}.cssPropDisable{float:left;display:block;width:2em;cursor:default;}.infoTip{z-index:2147483647;position:fixed;padding:2px 3px;border:1px solid #CBE087;background:LightYellow;font-family:Monaco,monospace;color:#000000;display:none;white-space:nowrap;pointer-events:none;}.infoTip[active="true"]{display:block;}.infoTipLoading{width:16px;height:16px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/loading_16.gif) no-repeat;}.infoTipImageBox{font-size:11px;min-width:100px;text-align:center;}.infoTipCaption{font-size:11px;font:Monaco,monospace;}.infoTipLoading > .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorBorders.png) repeat-y;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.png) no-repeat;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/disable.png) no-repeat 2px 1px;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/errorIcon.png) no-repeat !important;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;}#fbPanelBarBox{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/infoIcon.png) !important;background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/warningIcon.png) !important;background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/errorIcon.png) !important;background-image:url(chrome-extension://mdaojmoeahmmokaflgbannaopagamgoj/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}', + HTML: '
       
       
      >>>
      2 errors' +}; + +// ************************************************************************************************ +}}); + +// ************************************************************************************************ +FBL.initialize(); +// ************************************************************************************************ + +})(); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug.jpg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug.jpg new file mode 100755 index 0000000..2a18aa0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug.jpg differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug128.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug128.png new file mode 100755 index 0000000..dbca545 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug128.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug16.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug16.png new file mode 100755 index 0000000..d8d0c24 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug16.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug24.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug24.png new file mode 100755 index 0000000..f50ff92 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug24.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug24_disabled.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug24_disabled.png new file mode 100755 index 0000000..16d4dcd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug24_disabled.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug32.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug32.png new file mode 100755 index 0000000..c02f4f5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug32.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug48.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug48.png new file mode 100755 index 0000000..b443132 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/firebug48.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/googleChrome.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/googleChrome.js new file mode 100755 index 0000000..26c8af3 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/googleChrome.js @@ -0,0 +1,106 @@ +/* See license.txt for terms of usage */ + +Firebug.extend(function(FBL) { with (FBL) { +// ************************************************************************************************ + +if (!Env.isChromeExtension) return; + +// ************************************************************************************************ +// local variables + +var channel; +var channelEvent; + +// ************************************************************************************************ +// GoogleChrome Module + +Firebug.GoogleChrome = extend(Firebug.Module, +{ + initialize: function() + { + var doc = FBL.Env.browser.document; + + if (!doc.getElementById("FirebugChannel")) + { + channel = doc.createElement("div"); + channel.id = "FirebugChannel"; + channel.firebugIgnore = true; + channel.style.display = "none"; + doc.documentElement.insertBefore(channel, doc.documentElement.firstChild); + + channelEvent = document.createEvent("Event"); + channelEvent.initEvent("FirebugChannelEvent", true, true); + + channel.addEventListener("FirebugChannelEvent", onFirebugChannelEvent); + } + }, + + dispatch: function(message) + { + channel.innerText = message; + channel.dispatchEvent(channelEvent); + } +}); + +// ************************************************************************************************ +// internals + +var onFirebugChannelEvent = function() +{ + var name = channel.innerText; + + if (name.indexOf("FB_contextMenuClick") == 0) + { + var doc = FBL.Env.browser.document; + var contextMenuElementXPath = name.split(",")[1]; + var contextMenuElement = getElementsByXPath(doc, contextMenuElementXPath)[0]; + + // If not open, open it first + Firebug.chrome.toggle(true); + + setTimeout(function(){ + + // Select the HTML panel + Firebug.chrome.selectPanel("HTML"); + + // Select the clicked element in the HTML tree + Firebug.HTML.select(contextMenuElement); + + },50); + } + else if (name == "FB_toggle") + { + Firebug.chrome.toggle(); + } + else if (name == "FB_openInNewWindow") + { + setTimeout(function(){ + Firebug.chrome.toggle(true, true); + },0); + } +}; + +var getElementsByXPath = function(doc, xpath) +{ + var nodes = []; + + try { + var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + for (var item = result.iterateNext(); item; item = result.iterateNext()) + nodes.push(item); + } + catch (exc) + { + // Invalid xpath expressions make their way here sometimes. If that happens, + // we still want to return an empty set without an exception. + } + + return nodes; +}; + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.GoogleChrome); + +// ************************************************************************************************ +}}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/license.txt b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/license.txt new file mode 100755 index 0000000..ba43b75 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/license.txt @@ -0,0 +1,30 @@ +Software License Agreement (BSD License) + +Copyright (c) 2007, Parakey Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Parakey Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Parakey Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/manifest.json b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/manifest.json new file mode 100755 index 0000000..1bcfa2e --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/manifest.json @@ -0,0 +1,36 @@ +{ + "name": "Firebug Lite Beta for Google Chrome", + "version": "1.3.2.9760", + "description": "Firebug Lite Beta for Google Chrome, supported by the Firebug Working Group.", + "update_url": "https://getfirebug.com/releases/lite/chrome/beta/updates.xml", + "background_page": "background.html", + "browser_action": + { + "default_icon": "firebug24_disabled.png", + "default_title": "Firebug Lite 1.3.2" + }, + "icons": + { + "128": "firebug128.png", + "16": "firebug16.png", + "32": "firebug32.png", + "48": "firebug48.png" + }, + "content_scripts": + [ + { + "matches": ["http://*/*", "https://*/*"], + "js": ["contentScript.js"], + "run_at": "document_start" + } + ], + "permissions": + [ + "contextMenus", + "tabs", + "http://*/*", + "https://*/*", + "http://127.0.0.1/*", + "http://localhost/*" + ] +} \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/blank.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/blank.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/blank.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/buttonBg.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/buttonBg.png new file mode 100755 index 0000000..f367b42 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/buttonBg.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/buttonBgHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/buttonBgHover.png new file mode 100755 index 0000000..cd37a0d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/buttonBgHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/detach.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/detach.png new file mode 100755 index 0000000..0ddb9a1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/detach.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/detachHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/detachHover.png new file mode 100755 index 0000000..e419272 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/detachHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disable.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disable.gif new file mode 100755 index 0000000..dd9eb0e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disable.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disable.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disable.png new file mode 100755 index 0000000..c28bcdf Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disable.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disableHover.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disableHover.gif new file mode 100755 index 0000000..70565a8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disableHover.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disableHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disableHover.png new file mode 100755 index 0000000..26fe375 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/disableHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/down.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/down.png new file mode 100755 index 0000000..acbbd30 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/down.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/downActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/downActive.png new file mode 100755 index 0000000..f4312b2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/downActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/downHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/downHover.png new file mode 100755 index 0000000..8144e63 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/downHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon-sm.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon-sm.png new file mode 100755 index 0000000..0c377e3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon-sm.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon.gif new file mode 100755 index 0000000..8ee8116 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon.png new file mode 100755 index 0000000..2d75261 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/errorIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug-1.3a2.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug-1.3a2.css new file mode 100755 index 0000000..b5dd5dd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug-1.3a2.css @@ -0,0 +1,817 @@ +.fbBtnPressed { + background: #ECEBE3; + padding: 3px 6px 2px 7px !important; + margin: 1px 0 0 1px; + _margin: 1px -1px 0 1px; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +.fbToolbarButtons { + display: none; +} + +#fbStatusBarBox { + display: none; +} + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +html, body { + margin: 0; + padding: 0; + overflow: hidden; +} + +body { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + position: fixed; + overflow: hidden; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; +} + +#fbTop { + height: 49px; +} + +#fbToolbar { + position: absolute; + z-index: 5; + width: 100%; + top: 0; + background: url(sprite.png) #f1f2ee 0 0; + height: 27px; + font-size: 11px; + overflow: hidden; +} + +#fbPanelBarBox { + top: 27px; + position: absolute; + z-index: 8; + width: 100%; + background: url(sprite.png) #dbd9c9 0 -27px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 4px 5px 0; +} + +#fbToolbarIcon a { + display: block; + height: 20px; + width: 20px; + background: url(sprite.png) 0 -135px; + text-decoration: none; + cursor: default; +} + +#fbToolbarButtons { + float: left; + padding: 4px 2px 0 5px; +} + +#fbToolbarButtons a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 8px 4px; + cursor: default; +} + +#fbToolbarButtons a:hover { + color: #333; + padding: 3px 7px 3px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +#fbStatusBarBox { + position: relative; + top: 5px; + line-height: 19px; + cursor: default; +} + +.fbToolbarSeparator{ + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 10px 6px 0 0; + float: left; +} + +.fbStatusBar span { + color: #808080; + padding: 0 4px 0 0; +} + +.fbStatusBar span a { + text-decoration: none; + color: black; +} + +.fbStatusBar span a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + _width: 50px; + padding: 5px 0 5px 5px; + z-index: 6; + background: url(sprite.png) #f1f2ee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 255px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 22px; + padding-left: 10px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 11px; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + padding-left: 6px; + background: #fff; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 7px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; +} + +div.fbFitHeight { + overflow: auto; + _position: absolute; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +#fbWindowButtons a { + font-size: 1px; + width: 16px; + height: 16px; + display: block; + float: right; + margin-right: 4px; + text-decoration: none; + cursor: default; +} + +#fbWindow_btClose { + background: url(sprite.png) 0 -119px; +} + +#fbWindow_btClose:hover { + background: url(sprite.png) -16px -119px; +} + +#fbWindow_btDetach { + background: url(sprite.png) -32px -119px; +} + +#fbWindow_btDetach:hover { + background: url(sprite.png) -48px -119px; +} + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + display: block; + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #f1f2ee 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #ece9d8; + color: #000; + border: 1px solid #716f64; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 9; + position: absolute; + height: 100%; + top: 27px; + _width: 6px; +} + +/************************************************************************************************/ +div.lineNo { + font: 11px Monaco, monospace; + float: left; + display: inline; + position: relative; + margin: 0; + padding: 0 5px 0 20px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +pre.nodeCode { + font: 11px Monaco, monospace; + margin: 0; + padding-left: 10px; + overflow: hidden; + /* + _width: 100%; + /**/ +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 11px; +} + +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; +} + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + white-space: pre; +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warning { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png); +} + +.logRow-warning { + background-color: cyan; + background-image: url(warningIcon.png); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +} + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.IE6.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.IE6.css new file mode 100755 index 0000000..14f8aa8 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.IE6.css @@ -0,0 +1,20 @@ +/************************************************************************************************/ +#fbToolbarSearch { + background-image: url(search.gif) !important; +} +/************************************************************************************************/ +.fbErrors { + background-image: url(errorIcon.gif) !important; +} +/************************************************************************************************/ +.logRow-info { + background-image: url(infoIcon.gif) !important; +} + +.logRow-warning { + background-image: url(warningIcon.gif) !important; +} + +.logRow-error { + background-image: url(errorIcon.gif) !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.css new file mode 100755 index 0000000..decd591 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.css @@ -0,0 +1,3056 @@ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Loose */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* +.netInfoResponseHeadersTitle, netInfoResponseHeadersBody { + display: none; +} +/**/ + +/* IE6 need a separated rule, otherwise it will not recognize it */ +.collapsed { + display: none; +} + +[collapsed="true"] { + display: none; +} + +#fbCSS { + padding: 0 !important; +} + +.cssPropDisable { + float: left; + display: block; + width: 2em; + cursor: default; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* panelBase */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/************************************************************************************************/ + +.infoTip { + z-index: 2147483647; + position: fixed; + padding: 2px 3px; + border: 1px solid #CBE087; + background: LightYellow; + font-family: Monaco, monospace; + color: #000000; + display: none; + white-space: nowrap; + pointer-events: none; +} + +.infoTip[active="true"] { + display: block; +} + +.infoTipLoading { + width: 16px; + height: 16px; + background: url(chrome://firebug/skin/loading_16.gif) no-repeat; +} + +.infoTipImageBox { + min-width: 100px; + text-align: center; +} + +.infoTipCaption { + font: message-box; +} + +.infoTipLoading > .infoTipImage, +.infoTipLoading > .infoTipCaption { + display: none; +} + +/************************************************************************************************/ + +h1.groupHeader { + padding: 2px 4px; + margin: 0 0 4px 0; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + background: #eee url(group.gif) repeat-x; + font-size: 11px; + font-weight: bold; + _position: relative; +} + +/************************************************************************************************/ + +.inlineEditor, +.fixedWidthEditor { + z-index: 2147483647; + position: absolute; + display: none; +} + +.inlineEditor { + margin-left: -6px; + margin-top: -3px; + /* + _margin-left: -7px; + _margin-top: -5px; + /**/ +} + +.textEditorInner, +.fixedWidthEditor { + margin: 0 0 0 0 !important; + padding: 0; + border: none !important; + font: inherit; + text-decoration: inherit; + background-color: #FFFFFF; +} + +.fixedWidthEditor { + border-top: 1px solid #888888 !important; + border-bottom: 1px solid #888888 !important; +} + +.textEditorInner { + position: relative; + top: -7px; + left: -5px; + + outline: none; + resize: none; + + /* + _border: 1px solid #999 !important; + _padding: 1px !important; + _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040"); + /**/ +} + +.textEditorInner1 { + padding-left: 11px; + background: url(textEditorBorders.png) repeat-y; + _background: url(textEditorBorders.gif) repeat-y; + _overflow: hidden; +} + +.textEditorInner2 { + position: relative; + padding-right: 2px; + background: url(textEditorBorders.png) repeat-y 100% 0; + _background: url(textEditorBorders.gif) repeat-y 100% 0; + _position: fixed; +} + +.textEditorTop1 { + background: url(textEditorCorners.png) no-repeat 100% 0; + margin-left: 11px; + height: 10px; + _background: url(textEditorCorners.gif) no-repeat 100% 0; + _overflow: hidden; +} + +.textEditorTop2 { + position: relative; + left: -11px; + width: 11px; + height: 10px; + background: url(textEditorCorners.png) no-repeat; + _background: url(textEditorCorners.gif) no-repeat; +} + +.textEditorBottom1 { + position: relative; + background: url(textEditorCorners.png) no-repeat 100% 100%; + margin-left: 11px; + height: 12px; + _background: url(textEditorCorners.gif) no-repeat 100% 100%; +} + +.textEditorBottom2 { + position: relative; + left: -11px; + width: 11px; + height: 12px; + background: url(textEditorCorners.png) no-repeat 0 100%; + _background: url(textEditorCorners.gif) no-repeat 0 100%; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* CSS */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-css { + overflow-x: hidden; +} + +.cssSheet > .insertBefore { + height: 1.5em; +} + +.cssRule { + position: relative; + margin: 0; + padding: 1em 0 0 6px; + font-family: Monaco, monospace; + color: #000000; +} + +.cssRule:first-child { + padding-top: 6px; +} + +.cssElementRuleContainer { + position: relative; +} + +.cssHead { + padding-right: 150px; +} + +.cssProp { + /*padding-left: 2em;*/ +} + +.cssPropName { + color: DarkGreen; +} + +.cssPropValue { + margin-left: 8px; + color: DarkBlue; +} + +.cssOverridden span { + text-decoration: line-through; +} + +.cssInheritedRule { +} + +.cssInheritLabel { + margin-right: 0.5em; + font-weight: bold; +} + +.cssRule .objectLink-sourceLink { + top: 0; +} + +.cssProp.editGroup:hover { + background: url(disable.png) no-repeat 2px 1px; + _background: url(disable.gif) no-repeat 2px 1px; +} + +.cssProp.editGroup.editing { + background: none; +} + +.cssProp.disabledStyle { + background: url(disableHover.png) no-repeat 2px 1px; + _background: url(disableHover.gif) no-repeat 2px 1px; + opacity: 1; + color: #CCCCCC; +} + +.disabledStyle .cssPropName, +.disabledStyle .cssPropValue { + color: #CCCCCC; +} + +.cssPropValue.editing + .cssSemi, +.inlineExpander + .cssSemi { + display: none; +} + +.cssPropValue.editing { + white-space: nowrap; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.stylePropName { + font-weight: bold; + padding: 0 4px 4px 4px; + width: 50%; +} + +.stylePropValue { + width: 50%; +} +/* +.useA11y .a11yCSSView .focusRow:focus { + outline: none; + background-color: transparent + } + + .useA11y .a11yCSSView .focusRow:focus .cssSelector, + .useA11y .a11yCSSView .focusRow:focus .cssPropName, + .useA11y .a11yCSSView .focusRow:focus .cssPropValue, + .useA11y .a11yCSSView .computedStyleRow:focus, + .useA11y .a11yCSSView .groupHeader:focus { + outline: 2px solid #FF9933; + outline-offset: -2px; + background-color: #FFFFD6; + } + + .useA11y .a11yCSSView .groupHeader:focus { + outline-offset: -2px; + } +/**/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Net */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-net { + overflow-x: hidden; +} + +.netTable { + width: 100%; +} + +/************************************************************************************************/ + +.hideCategory-undefined .category-undefined, +.hideCategory-html .category-html, +.hideCategory-css .category-css, +.hideCategory-js .category-js, +.hideCategory-image .category-image, +.hideCategory-xhr .category-xhr, +.hideCategory-flash .category-flash, +.hideCategory-txt .category-txt, +.hideCategory-bin .category-bin { + display: none; +} + +/************************************************************************************************/ + +.netHeadRow { + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netHeadCol { + border-bottom: 1px solid #CCCCCC; + padding: 2px 4px 2px 18px; + font-weight: bold; +} + +.netHeadLabel { + white-space: nowrap; + overflow: hidden; +} + +/************************************************************************************************/ +/* Header for Net panel table */ + +.netHeaderRow { + height: 16px; +} + +.netHeaderCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x; + white-space: nowrap; +} + +.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox { + padding: 2px 14px 2px 18px; +} + +.netHeaderCellBox { + padding: 2px 14px 2px 10px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.netHeaderCell:hover:active { + background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x; +} + +.netHeaderSorted { + background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x; +} + +.netHeaderSorted > .netHeaderCellBox { + border-right-color: #6B7C93; + background: url(chrome://firebug/skin/arrowDown.png) no-repeat right; +} + +.netHeaderSorted.sortedAscending > .netHeaderCellBox { + background-image: url(chrome://firebug/skin/arrowUp.png); +} + +.netHeaderSorted:hover:active { + background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x; +} + +/************************************************************************************************/ +/* Breakpoints */ + +.panelNode-net .netRowHeader { + display: block; +} + +.netRowHeader { + cursor: pointer; + display: none; + height: 15px; + margin-right: 0 !important; +} + +/* Display brekpoint disc */ +.netRow .netRowHeader { + background-position: 5px 1px; +} + +.netRow[breakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpoint.png); +} + +.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpointDisabled.png); +} + +.netRow.category-xhr:hover .netRowHeader { + background-color: #F6F6F6; +} + +#netBreakpointBar { + max-width: 38px; +} + +#netHrefCol > .netHeaderCellBox { + border-left: 0px; +} + +.netRow .netRowHeader { + width: 3px; +} + +.netInfoRow .netRowHeader { + display: table-cell; +} + +/************************************************************************************************/ +/* Column visibility */ + +.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"], +.netTable[hiddenCols~=netHrefCol] TD.netHrefCol, +.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"], +.netTable[hiddenCols~=netStatusCol] TD.netStatusCol, +.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"], +.netTable[hiddenCols~=netDomainCol] TD.netDomainCol, +.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"], +.netTable[hiddenCols~=netSizeCol] TD.netSizeCol, +.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"], +.netTable[hiddenCols~=netTimeCol] TD.netTimeCol { + display: none; +} + +/************************************************************************************************/ + +.netRow { + background: LightYellow; +} + +.netRow.loaded { + background: #FFFFFF; +} + +.netRow.loaded:hover { + background: #EFEFEF; +} + +.netCol { + padding: 0; + vertical-align: top; + border-bottom: 1px solid #EFEFEF; + white-space: nowrap; + height: 17px; +} + +.netLabel { + width: 100%; +} + +.netStatusCol { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.responseError > .netStatusCol { + color: red; +} + +.netDomainCol { + padding-left: 5px; +} + +.netSizeCol { + text-align: right; + padding-right: 10px; +} + +.netHrefLabel { + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 10; + position: absolute; + padding-left: 18px; + padding-top: 1px; + max-width: 15%; + font-weight: bold; +} + +.netFullHrefLabel { + display: none; + -moz-user-select: none; + padding-right: 10px; + padding-bottom: 3px; + max-width: 100%; + background: #FFFFFF; + z-index: 200; +} + +.netHrefCol:hover > .netFullHrefLabel { + display: block; +} + +.netRow.loaded:hover .netCol > .netFullHrefLabel { + background-color: #EFEFEF; +} + +.useA11y .a11yShowFullLabel { + display: block; + background-image: none !important; + border: 1px solid #CBE087; + background-color: LightYellow; + font-family: Monaco, monospace; + color: #000000; + font-size: 10px; + z-index: 2147483647; +} + +.netSizeLabel { + padding-left: 6px; +} + +.netStatusLabel, +.netDomainLabel, +.netSizeLabel, +.netBar { + padding: 1px 0 2px 0 !important; +} + +.responseError { + color: red; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.hasHeaders .netHrefLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/************************************************************************************************/ + +.netLoadingIcon { + position: absolute; + border: 0; + margin-left: 14px; + width: 16px; + height: 16px; + background: transparent no-repeat 0 0; + background-image: url(chrome://firebug/skin/loading_16.gif); + display:inline-block; +} + +.loaded .netLoadingIcon { + display: none; +} + +/************************************************************************************************/ + +.netBar, .netSummaryBar { + position: relative; + border-right: 50px solid transparent; +} + +.netResolvingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x; + z-index:60; +} + +.netConnectingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x; + z-index:50; +} + +.netBlockingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x; + z-index:40; +} + +.netSendingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x; + z-index:30; +} + +.netWaitingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x; + z-index:20; + min-width: 1px; +} + +.netReceivingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x; + z-index:10; +} + +.netWindowLoadBar, +.netContentLoadBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 1px; + background-color: red; + z-index: 70; + opacity: 0.5; + display: none; + margin-bottom:-1px; +} + +.netContentLoadBar { + background-color: Blue; +} + +.netTimeLabel { + -moz-box-sizing: padding-box; + position: absolute; + top: 1px; + left: 100%; + padding-left: 6px; + color: #444444; + min-width: 16px; +} + +/* + * Timing info tip is reusing net timeline styles to display the same + * colors for individual request phases. Notice that the info tip must + * respect also loaded and fromCache styles that also modify the + * actual color. These are used both on the same element in case + * of the tooltip. + */ +.loaded .netReceivingBar, +.loaded.netReceivingBar { + background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x; + border-color: #B6B6B6; +} + +.fromCache .netReceivingBar, +.fromCache.netReceivingBar { + background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x; + border-color: #D6D6D6; +} + +.netSummaryRow .netTimeLabel, +.loaded .netTimeLabel { + background: transparent; +} + +/************************************************************************************************/ +/* Time Info tip */ + +.timeInfoTip { + width: 150px; + height: 40px +} + +.timeInfoTipBar, +.timeInfoTipEventBar { + position: relative; + display: block; + margin: 0; + opacity: 1; + height: 15px; + width: 4px; +} + +.timeInfoTipEventBar { + width: 1px !important; +} + +.timeInfoTipCell.startTime { + padding-right: 8px; +} + +.timeInfoTipCell.elapsedTime { + text-align: right; + padding-right: 8px; +} + +/************************************************************************************************/ +/* Size Info tip */ + +.sizeInfoLabelCol { + font-weight: bold; + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; +} + +.sizeInfoSizeCol { + font-weight: bold; +} + +.sizeInfoDetailCol { + color: gray; + text-align: right; +} + +.sizeInfoDescCol { + font-style: italic; +} + +/************************************************************************************************/ +/* Summary */ + +.netSummaryRow .netReceivingBar { + background: #BBBBBB; + border: none; +} + +.netSummaryLabel { + color: #222222; +} + +.netSummaryRow { + background: #BBBBBB !important; + font-weight: bold; +} + +.netSummaryRow .netBar { + border-right-color: #BBBBBB; +} + +.netSummaryRow > .netCol { + border-top: 1px solid #999999; + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 1px; + padding-bottom: 2px; +} + +.netSummaryRow > .netHrefCol:hover { + background: transparent !important; +} + +.netCountLabel { + padding-left: 18px; +} + +.netTotalSizeCol { + text-align: right; + padding-right: 10px; +} + +.netTotalTimeCol { + text-align: right; +} + +.netCacheSizeLabel { + position: absolute; + z-index: 1000; + left: 0; + top: 0; +} + +/************************************************************************************************/ + +.netLimitRow { + background: rgb(255, 255, 225) !important; + font-weight:normal; + color: black; + font-weight:normal; +} + +.netLimitLabel { + padding-left: 18px; +} + +.netLimitRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + vertical-align: middle !important; + padding-top: 2px; + padding-bottom: 2px; +} + +.netLimitButton { + font-size: 11px; + padding-top: 1px; + padding-bottom: 1px; +} + +/************************************************************************************************/ + +.netInfoCol { + border-top: 1px solid #EEEEEE; + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netInfoBody { + margin: 10px 0 4px 10px; +} + +.netInfoTabs { + position: relative; + padding-left: 17px; +} + +.netInfoTab { + position: relative; + top: -3px; + margin-top: 10px; + padding: 4px 6px; + border: 1px solid transparent; + border-bottom: none; + _border: none; + font-weight: bold; + color: #565656; + cursor: pointer; +} + +/*.netInfoTab:hover { + cursor: pointer; +}*/ + +/* replaced by .netInfoTabSelected for IE6 support +.netInfoTab[selected="true"] { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} +/**/ +.netInfoTabSelected { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} + +.logRow-netInfo.error .netInfoTitle { + color: red; +} + +.logRow-netInfo.loading .netInfoResponseText { + font-style: italic; + color: #888888; +} + +.loading .netInfoResponseHeadersTitle { + display: none; +} + +.netInfoResponseSizeLimit { + font-family: Lucida Grande, Tahoma, sans-serif; + padding-top: 10px; + font-size: 11px; +} + +.netInfoText { + display: none; + margin: 0; + border: 1px solid #D7D7D7; + border-right: none; + padding: 8px; + background-color: #FFFFFF; + font-family: Monaco, monospace; + /* white-space: pre; */ + /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */ +} + +/* replaced by .netInfoTextSelected for IE6 support +.netInfoText[selected="true"] { + display: block; +} +/**/ +.netInfoTextSelected { + display: block; +} + +.netInfoParamName { + padding: 0 10px 0 0; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + vertical-align: top; + text-align: right; + white-space: nowrap; +} + +.netInfoParamValue { + width: 100%; +} + +.netInfoHeadersText, +.netInfoPostText, +.netInfoPutText { + padding-top: 0; +} + +.netInfoHeadersGroup, +.netInfoPostParams, +.netInfoPostSource { + margin-bottom: 4px; + border-bottom: 1px solid #D7D7D7; + padding-top: 8px; + padding-bottom: 2px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #565656; +} + +.netInfoPostParamsTable, +.netInfoPostPartsTable, +.netInfoPostJSONTable, +.netInfoPostXMLTable, +.netInfoPostSourceTable { + margin-bottom: 10px; + width: 100%; +} + +.netInfoPostContentType { + color: #bdbdbd; + padding-left: 50px; + font-weight: normal; +} + +.netInfoHtmlPreview { + border: 0; + width: 100%; + height:100%; +} + +/************************************************************************************************/ +/* Request & Response Headers */ + +.netHeadersViewSource { + color: #bdbdbd; + margin-left: 200px; + font-weight: normal; +} + +.netHeadersViewSource:hover { + color: blue; + cursor: pointer; +} + +/************************************************************************************************/ + +.netActivationRow, +.netPageSeparatorRow { + background: rgb(229, 229, 229) !important; + font-weight: normal; + color: black; +} + +.netActivationLabel { + background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px; + padding-left: 22px; +} + +/************************************************************************************************/ + +.netPageSeparatorRow { + height: 5px !important; +} + +.netPageSeparatorLabel { + padding-left: 22px; + height: 5px !important; +} + +.netPageRow { + background-color: rgb(255, 255, 255); +} + +.netPageRow:hover { + background: #EFEFEF; +} + +.netPageLabel { + padding: 1px 0 2px 18px !important; + font-weight: bold; +} + +/************************************************************************************************/ + +.netActivationRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 2px; + padding-bottom: 3px; +} +/* +.useA11y .panelNode-net .a11yFocus:focus, +.useA11y .panelNode-net .focusRow:focus { + outline-offset: -2px; + background-color: #FFFFD6 !important; +} + +.useA11y .panelNode-net .netHeaderCell:focus, +.useA11y .panelNode-net :focus .netHeaderCell, +.useA11y .panelNode-net :focus .netReceivingBar, +.useA11y .netSummaryRow :focus .netBar, +.useA11y .netSummaryRow:focus .netBar { + background-color: #FFFFD6; + background-image: none; + border-color: #FFFFD6; +} +/**/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Windows */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/************************************************************************************************/ +/* Twisties */ + +/* IE6 has problems with > operator, and multiple classes */ +/*.twisty, +.logRow-errorMessage > .hasTwisty > .errorTitle, + /* avoid rule not being parsed IE6 */ +.logRow-spy .spyHead .spyTitle, +.logGroup .logGroupLabel, +.hasChildren .memberLabelCell .memberLabel, +.hasHeaders .netHrefLabel { + background-image: url(tree_open.gif); + background-repeat: no-repeat; + background-position: 2px 2px; +} +/* +.logRow-errorMessage > .hasTwisty.opened > .errorTitle, +/* avoid rule not being parsed IE6 */ +.opened .spyHead .spyTitle, +.opened .logGroupLabel, +.opened .memberLabelCell .memberLabel/*, +.nodeBox.highlightOpen > .nodeLabel > .twisty, +.nodeBox.open > .nodeLabel > .twisty, +.netRow.opened > .netCol > .netHrefLabel /* avoid rule not being parsed IE6 */ { + background-image: url(tree_close.gif); +} + +.twisty { + background-position: 2px 0; +} + + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Console */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-console { + overflow-x: hidden; +} + +.objectLink { + text-decoration: none; +} + +.objectLink:hover { + cursor: pointer; + text-decoration: underline; +} + +.logRow { + position: relative; + margin: 0; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; + overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */ +} + +.useA11y .logRow:focus { + border-bottom: 1px solid #000000 !important; + outline: none !important; + background-color: #FFFFAD !important; +} + +.useA11y .logRow:focus a.objectLink-sourceLink { + background-color: #FFFFAD; +} + +.useA11y .a11yFocus:focus, .useA11y .objectBox:focus { + outline: 2px solid #FF9933; + background-color: #FFFFAD; +} + +.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{ + background-color: #888888 !important; +} + +.useA11y .logGroup.opened > .logRow { + border-bottom: 1px solid #ffffff; +} + +.logGroup { + background: url(group.gif) repeat-x #FFFFFF; + padding: 0 !important; + border: none !important; +} + +.logGroupBody { + display: none; + margin-left: 16px; + border-left: 1px solid #D7D7D7; + border-top: 1px solid #D7D7D7; + background: #FFFFFF; +} + +.logGroup > .logRow { + background-color: transparent !important; + font-weight: bold; +} + +.logGroup.opened > .logRow { + border-bottom: none; +} + +.logGroup.opened > .logGroupBody { + display: block; +} + +/*****************************************************************************************/ + +.logRow-command > .objectBox-text { + font-family: Monaco, monospace; + color: #0000FF; + white-space: pre-wrap; +} + +.logRow-info, +.logRow-warn, +.logRow-error, +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-left: 22px; + background-repeat: no-repeat; + background-position: 4px 2px; +} + +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-top: 0; + padding-bottom: 0; +} + +.logRow-info, +.logRow-info .objectLink-sourceLink { + background-color: #FFFFFF; +} + +.logRow-warn, +.logRow-warningMessage, +.logRow-warn .objectLink-sourceLink, +.logRow-warningMessage .objectLink-sourceLink { + background-color: cyan; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage, +.logRow-error .objectLink-sourceLink, +.logRow-errorMessage .objectLink-sourceLink { + background-color: LightYellow; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + color: #FF0000; +} + +.logRow-info { + /*background-image: url(chrome://firebug/skin/infoIcon.png);*/ +} + +.logRow-warn, +.logRow-warningMessage { + /*background-image: url(chrome://firebug/skin/warningIcon.png);*/ +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + /*background-image: url(chrome://firebug/skin/errorIcon.png);*/ +} + +/*****************************************************************************************/ + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-string, +.objectBox-text, +.objectLink-textNode { + white-space: pre-wrap; +} + +.objectBox-number, +.objectLink-styleRule, +.objectLink-element, +.objectLink-textNode { + color: #000088; +} + +.objectBox-string { + color: #FF0000; +} + +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + color: DarkGreen; +} + +.objectBox-null, +.objectBox-undefined { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-exception { + padding: 0 2px 0 18px; + /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/ + color: red; +} + +.objectLink-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ + +.errorTitle { + margin-top: 0px; + margin-bottom: 1px; + padding-top: 2px; + padding-bottom: 2px; +} + +.errorTrace { + margin-left: 17px; +} + +.errorSourceBox { + margin: 2px 0; +} + +.errorSource-none { + display: none; +} + +.errorSource-syntax > .errorBreak { + visibility: hidden; +} + +.errorSource { + cursor: pointer; + font-family: Monaco, monospace; + color: DarkGreen; +} + +.errorSource:hover { + text-decoration: underline; +} + +.errorBreak { + cursor: pointer; + display: none; + margin: 0 6px 0 0; + width: 13px; + height: 14px; + vertical-align: bottom; + /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/ + opacity: 0.1; +} + +.hasBreakSwitch .errorBreak { + display: inline; +} + +.breakForError .errorBreak { + opacity: 1; +} + +.assertDescription { + margin: 0; +} + +/************************************************************************************************/ + +.logRow-profile > .logRow > .objectBox-text { + font-family: Lucida Grande, Tahoma, sans-serif; + color: #000000; +} + +.logRow-profile > .logRow > .objectBox-text:last-child { + color: #555555; + font-style: italic; +} + +.logRow-profile.opened > .logRow { + padding-bottom: 4px; +} + +.profilerRunning > .logRow { + /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/ + padding-left: 22px !important; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.profileSizer { + width:100%; + overflow-x:auto; + overflow-y: scroll; +} + +.profileTable { + border-bottom: 1px solid #D7D7D7; + padding: 0 0 4px 0; +} + +.profileTable tr[odd="1"] { + background-color: #F5F5F5; + vertical-align:middle; +} + +.profileTable a { + vertical-align:middle; +} + +.profileTable td { + padding: 1px 4px 0 4px; +} + +.headerCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/ +} + +.headerCellBox { + padding: 2px 4px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.headerCell:hover:active { + /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/ +} + +.headerSorted { + /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/ +} + +.headerSorted > .headerCellBox { + border-right-color: #6B7C93; + /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/ +} + +.headerSorted.sortedAscending > .headerCellBox { + /*background-image: url(chrome://firebug/skin/arrowUp.png);*/ +} + +.headerSorted:hover:active { + /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/ +} + +.linkCell { + text-align: right; +} + +.linkCell > .objectLink-sourceLink { + position: static; +} + +/*****************************************************************************************/ + +.logRow-stackTrace { + padding-top: 0; +} + +.logRow-stackTrace > .objectBox-stackFrame { + position: relative; + padding-top: 2px; +} + +/************************************************************************************************/ + +.objectLink-object { + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: DarkGreen; + white-space: pre-wrap; +} + +.objectPropValue { + font-weight: normal; + font-style: italic; + color: #555555; +} + +/************************************************************************************************/ + +.selectorTag, +.selectorId, +.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +.selectorHidden > .selectorTag { + color: #5F82D9; +} + +.selectorHidden > .selectorId { + color: #888888; +} + +.selectorHidden > .selectorClass { + color: #D86060; +} + +.selectorValue { + font-family: Lucida Grande, sans-serif; + font-style: italic; + color: #555555; +} + +/*****************************************************************************************/ + +.panelNode.searching .logRow { + display: none; +} + +.logRow.matched { + display: block !important; +} + +.logRow.matching { + position: absolute; + left: -1000px; + top: -1000px; + max-width: 0; + max-height: 0; + overflow: hidden; +} + +/*****************************************************************************************/ + +.arrayLeftBracket, +.arrayRightBracket, +.arrayComma { + font-family: Monaco, monospace; +} + +.arrayLeftBracket, +.arrayRightBracket { + font-weight: bold; +} + +.arrayLeftBracket { + margin-right: 4px; +} + +.arrayRightBracket { + margin-left: 4px; +} + +/*****************************************************************************************/ + +.logRow-dir { + padding: 0; +} + +/************************************************************************************************/ + +/* +.logRow-errorMessage > .hasTwisty > .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup > .logRow +*/ +.logRow-errorMessage .hasTwisty .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup .logRow { + cursor: pointer; + padding-left: 18px; + background-repeat: no-repeat; + background-position: 3px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle { + background-position: 2px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle:hover, +.logRow-spy .spyHead .spyTitle:hover, +.logGroup > .logRow:hover { + text-decoration: underline; +} + +/*****************************************************************************************/ + +.logRow-spy { + padding: 0 !important; +} + +.logRow-spy, +.logRow-spy .objectLink-sourceLink { + background: url(group.gif) repeat-x #FFFFFF; + padding-right: 4px; + right: 0; +} + +.logRow-spy.opened { + padding-bottom: 4px; + border-bottom: none; +} + +.spyTitle { + color: #000000; + font-weight: bold; + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 100; + padding-left: 18px; +} + +.spyCol { + padding: 0; + white-space: nowrap; + height: 16px; +} + +.spyTitleCol:hover > .objectLink-sourceLink, +.spyTitleCol:hover > .spyTime, +.spyTitleCol:hover > .spyStatus, +.spyTitleCol:hover > .spyTitle { + display: none; +} + +.spyFullTitle { + display: none; + -moz-user-select: none; + max-width: 100%; + background-color: Transparent; +} + +.spyTitleCol:hover > .spyFullTitle { + display: block; +} + +.spyStatus { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.spyTime { + margin-left:4px; + margin-right:4px; + color: rgb(128, 128, 128); +} + +.spyIcon { + margin-right: 4px; + margin-left: 4px; + width: 16px; + height: 16px; + vertical-align: middle; + background: transparent no-repeat 0 0; + display: none; +} + +.loading .spyHead .spyRow .spyIcon { + background-image: url(loading_16.gif); + display: block; +} + +.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon { + width: 0; + margin: 0; +} + +.logRow-spy.error .spyHead .spyRow .spyIcon { + background-image: url(errorIcon-sm.png); + display: block; + background-position: 2px 2px; +} + +.logRow-spy .spyHead .netInfoBody { + display: none; +} + +.logRow-spy.opened .spyHead .netInfoBody { + margin-top: 10px; + display: block; +} + +.logRow-spy.error .spyTitle, +.logRow-spy.error .spyStatus, +.logRow-spy.error .spyTime { + color: red; +} + +.logRow-spy.loading .spyResponseText { + font-style: italic; + color: #888888; +} + +/************************************************************************************************/ + +.caption { + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #444444; +} + +.warning { + padding: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #888888; +} + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* DOM */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-dom { + overflow-x: hidden !important; +} + +.domTable { + font-size: 1em; + width: 100%; + table-layout: fixed; + background: #fff; +} + +.domTableIE { + width: auto; +} + +.memberLabelCell { + padding: 2px 0 2px 0; + vertical-align: top; +} + +.memberValueCell { + padding: 1px 0 1px 5px; + display: block; + overflow: hidden; +} + +.memberLabel { + display: block; + cursor: default; + -moz-user-select: none; + overflow: hidden; + /*position: absolute;*/ + padding-left: 18px; + /*max-width: 30%;*/ + /*white-space: nowrap;*/ + background-color: #FFFFFF; + text-decoration: none; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.memberRow.hasChildren .memberLabelCell .memberLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.userLabel { + color: #000000; + font-weight: bold; +} + +.userClassLabel { + color: #E90000; + font-weight: bold; +} + +.userFunctionLabel { + color: #025E2A; + font-weight: bold; +} + +.domLabel { + color: #000000; +} + +.domFunctionLabel { + color: #025E2A; +} + +.ordinalLabel { + color: SlateBlue; + font-weight: bold; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +.scopesRow { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 5px solid #BEBEBE; + color: #666666; +} +.scopesLabel { + background-color: LightYellow; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchEditCell { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 1px solid #BEBEBE; + color: #666666; +} + +.editor-watchNewRow, +.editor-memberRow { + font-family: Monaco, monospace !important; +} + +.editor-memberRow { + padding: 1px 0 !important; +} + +.editor-watchRow { + padding-bottom: 0 !important; +} + +.watchRow > .memberLabelCell { + font-family: Monaco, monospace; + padding-top: 1px; + padding-bottom: 1px; +} + +.watchRow > .memberLabelCell > .memberLabel { + background-color: transparent; +} + +.watchRow > .memberValueCell { + padding-top: 2px; + padding-bottom: 2px; +} + +.watchRow > .memberLabelCell, +.watchRow > .memberValueCell { + background-color: #F5F5F5; + border-bottom: 1px solid #BEBEBE; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchToolbox { + z-index: 2147483647; + position: absolute; + right: 0; + padding: 1px 2px; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* FROM ORIGINAL FIREBUG */ + + + + +/************************************************************************************************ + CSS Not organized +*************************************************************************************************/ +#fbConsole { + overflow-x: hidden !important; +} + +#fbCSS { + font: 1em Monaco, monospace; + padding: 0 7px; +} + +#fbstylesheetButtons select, #fbScriptButtons select { + font: 11px Lucida Grande, Tahoma, sans-serif; + margin-top: 1px; + padding-left: 3px; + background: #fafafa; + border: 1px inset #fff; + width: 220px; + outline: none; +} + +.Selector { margin-top:10px } +.CSSItem {margin-left: 4% } +.CSSText { padding-left:20px; } +.CSSProperty { color:#005500; } +.CSSValue { padding-left:5px; color:#000088; } + + +/************************************************************************************************ + Not organized +*************************************************************************************************/ + +#fbHTMLStatusBar { + display: inline; +} + +.fbToolbarButtons { + display: none; +} + +.fbStatusSeparator{ + display: block; + float: left; + padding-top: 4px; +} + +#fbStatusBarBox { + display: none; +} + +#fbToolbarContent { + display: block; + position: absolute; + _position: absolute; + top: 0; + padding-top: 4px; + height: 23px; + clip: rect(0, 2048px, 27px, 0); +} + +.fbTabMenuTarget { + display: none !important; + float: left; + width: 10px; + height: 10px; + margin-top: 6px; + background: url(tabMenuTarget.png); +} + +.fbTabMenuTarget:hover { + background: url(tabMenuTargetHover.png); +} + +.fbShadow { + float: left; + background: url(shadowAlpha.png) no-repeat bottom right !important; + background: url(shadow2.gif) no-repeat bottom right; + margin: 10px 0 0 10px !important; + margin: 10px 0 0 5px; +} + +.fbShadowContent { + display: block; + position: relative; + background-color: #fff; + border: 1px solid #a9a9a9; + top: -6px; + left: -6px; +} + +.fbMenu { + display: none; + position: absolute; + font-size: 11px; + z-index: 2147483647; +} + +.fbMenuContent { + padding: 2px; +} + +.fbMenuSeparator { + display: block; + position: relative; + padding: 1px 18px 0; + text-decoration: none; + color: #000; + cursor: default; + background: #ACA899; + margin: 4px 0; +} + +.fbMenuOption +{ + display: block; + position: relative; + padding: 2px 18px; + text-decoration: none; + color: #000; + cursor: default; +} + +.fbMenuOption:hover +{ + color: #fff; + background: #316AC5; +} + +.fbMenuGroup { + background: transparent url(tabMenuPin.png) no-repeat right 0; +} + +.fbMenuGroup:hover { + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuGroupSelected { + color: #fff; + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuChecked { + background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0; +} + +.fbMenuChecked:hover { + background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px; +} + +.fbMenuRadioSelected { + background: transparent url(tabMenuRadio.png) no-repeat 4px 0; +} + +.fbMenuRadioSelected:hover { + background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px; +} + +.fbMenuShortcut { + padding-right: 85px; +} + +.fbMenuShortcutKey { + position: absolute; + right: 0; + top: 2px; + width: 77px; +} + +#fbFirebugMenu { + top: 22px; + left: 0; +} + +.fbMenuDisabled { + color: #ACA899 !important; +} + +#fbFirebugSettingsMenu { + left: 245px; + top: 99px; +} + +#fbConsoleMenu { + top: 42px; + left: 48px; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; + float: left; + height: 20px; + width: 20px; + color: #000; + margin-right: 2px; + text-decoration: none; + cursor: default; +} + +.fbIconButton:hover { + position: relative; + top: -1px; + left: -1px; + margin-right: 0; + _margin-right: 1px; + color: #333; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbIconPressed { + position: relative; + margin-right: 0; + _margin-right: 1px; + top: 0 !important; + left: 0 !important; + height: 19px; + color: #333 !important; + border: 1px solid #bbb !important; + border-bottom: 1px solid #cfcfcf !important; + border-right: 1px solid #ddd !important; +} + + + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +.fbBody { + margin: 0; + padding: 0; + overflow: hidden; + + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px !important; + background: #fff url(search.gif) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat !important; + background: url(errorIcon.gif) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + position: absolute; + _position: static; + top: 0; + left: 0; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; + overflow: hidden; +} + +#fbTop { + height: 49px; +} + +#fbToolbar { + background: url(sprite.png) #f1f2ee 0 0; + height: 27px; + font-size: 11px; +} + +#fbPanelBarBox { + background: url(sprite.png) #dbd9c9 0 -27px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 0 5px 0; +} + +#fbToolbarIcon a { + background: url(sprite.png) 0 -135px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} +/* +#fbStatusBarBox a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 5px; + margin: 0 0 0 1px; + cursor: default; +} + +#fbStatusBarBox a:hover { + color: #333; + padding: 3px 4px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} +/**/ + +.fbButton { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 6px 4px 7px; + cursor: default; +} + +.fbButton:hover { + color: #333; + background: #f5f5ef url(buttonBg.png); + padding: 3px 5px 3px 6px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbBtnPressed { + background: #e3e3db url(buttonBgHover.png) !important; + padding: 3px 4px 2px 6px !important; + margin: 1px 0 0 1px !important; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +#fbStatusBarBox { + top: 4px; + cursor: default; +} + +.fbToolbarSeparator { + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 6px 3px; + float: left; +} + +.fbBtnSelected { + font-weight: bold; +} + +.fbStatusBar { + color: #aca899; +} + +.fbStatusBar a { + text-decoration: none; + color: black; +} + +.fbStatusBar a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + width: 48px; + padding: 5px; + z-index: 6; + background: url(sprite.png) #f1f2ee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 1024px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 22px; + padding-left: 4px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 1em; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + margin-left: 6px; + background: #fff; +} + +#fbLargeCommandLine { + display: none; + position: absolute; + z-index: 9; + top: 27px; + right: 0; + width: 294px; + height: 201px; + border-width: 0; + margin: 0; + padding: 2px 0 0 2px; + resize: none; + outline: none; + font-size: 11px; + overflow: auto; + border-top: 1px solid #B9B7AF; + _right: -1px; + _border-left: 1px solid #fff; +} + +#fbLargeCommandButtons { + display: none; + background: #ECE9D8; + bottom: 0; + right: 0; + width: 294px; + height: 21px; + padding-top: 1px; + position: fixed; + border-top: 1px solid #ACA899; + z-index: 9; +} + +#fbSmallCommandLineIcon { + background: url(down.png) no-repeat; + position: absolute; + right: 2px; + bottom: 3px; + + z-index: 99; +} + +#fbSmallCommandLineIcon:hover { + background: url(downHover.png) no-repeat; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: fixed; + _position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 6px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; + outline: none; +} + +#fbLargeCommandLineIcon { + background: url(up.png) no-repeat; + position: absolute; + right: 1px; + bottom: 1px; + z-index: 10; +} + +#fbLargeCommandLineIcon:hover { + background: url(upHover.png) no-repeat; +} + +div.fbFitHeight { + overflow: auto; + position: relative; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +.fbSmallButton { + overflow: hidden; + width: 16px; + height: 16px; + display: block; + text-decoration: none; + cursor: default; +} + +#fbWindowButtons .fbSmallButton { + float: right; +} + +#fbWindow_btClose { + background: url(min.png); +} + +#fbWindow_btClose:hover { + background: url(minHover.png); +} + +#fbWindow_btDetach { + background: url(detach.png); +} + +#fbWindow_btDetach:hover { + background: url(detachHover.png); +} + +#fbWindow_btDeactivate { + background: url(off.png); +} + +#fbWindow_btDeactivate:hover { + background: url(offHover.png); +} + + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + /*display: block; TODO: safe to remove this? */ + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #f1f2ee 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: fixed; + _position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #ece9d8; + color: #000; + border: 1px solid #716f64; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 10; + position: absolute; + height: 100%; + top: 27px; +} + +/************************************************************************************************/ +div.lineNo { + font: 1em Monaco, monospace; + position: absolute; + top: 0; + left: 0; + margin: 0; + padding: 0 5px 0 20px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +.sourceBox { + position: absolute; +} + +.sourceCode { + font: 1em Monaco, monospace; + overflow: hidden; + white-space: pre; + display: inline; +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* IE6 need this hack */ +* html .selectedElement { + position: relative; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 1em; +} + +/* TODO: remove this? */ +/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to +position. if so, override it at chrome.js initialization when creating the div */ +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + zbackground-color: #FFFFFF; +} +/**/ + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + + /* TODO: xxxpedro make long strings break line */ + /*white-space: pre; */ +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warning { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png) !important; + background-image: url(infoIcon.gif); +} + +.logRow-warning { + background-color: cyan; + background-image: url(warningIcon.png) !important; + background-image: url(warningIcon.gif); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png) !important; + background-image: url(errorIcon.gif); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +/* +//TODO: remove this when console2 is finished +*/ +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +}/**/ + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.html new file mode 100755 index 0000000..4432a32 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.html @@ -0,0 +1,213 @@ + + + + +Firebug Lite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + +
      +   +   +   +
      + + +
      +
      + + + +   + + + + + + + + + Inspect + + + + + Clear + + + + + + + + + + + + + +
      + +
      + + + + + +
       
      + +
      +
      +
      +
      +
      +
      + + +
       
      + + +
      + + +
      +
      +
      + +
      + + + + + +
      + Run + Clear + + +
      + +
      +
      +
      >>>
      + + +
      +
      + + + + 2 errors + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.png new file mode 100755 index 0000000..e10affe Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/firebug.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/group.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/group.gif new file mode 100755 index 0000000..8db97c2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/group.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/infoIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/infoIcon.gif new file mode 100755 index 0000000..0618e20 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/infoIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/infoIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/infoIcon.png new file mode 100755 index 0000000..da1e533 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/infoIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/loading_16.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/loading_16.gif new file mode 100755 index 0000000..085ccae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/loading_16.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/min.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/min.png new file mode 100755 index 0000000..1034d66 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/min.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/minHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/minHover.png new file mode 100755 index 0000000..b0d1e1a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/minHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/off.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/off.png new file mode 100755 index 0000000..b70b1d2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/off.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/offHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/offHover.png new file mode 100755 index 0000000..f3670f1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/offHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/pixel_transparent.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/pixel_transparent.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/pixel_transparent.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/roundCorner.svg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/roundCorner.svg new file mode 100755 index 0000000..be0291f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/roundCorner.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/search.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/search.gif new file mode 100755 index 0000000..2a62098 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/search.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/search.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/search.png new file mode 100755 index 0000000..fba33b8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/search.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadow.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadow.gif new file mode 100755 index 0000000..af7f537 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadow.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadow2.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadow2.gif new file mode 100755 index 0000000..099cbf3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadow2.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadowAlpha.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadowAlpha.png new file mode 100755 index 0000000..a2561df Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/shadowAlpha.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/sprite.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/sprite.png new file mode 100755 index 0000000..33d2c4d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/sprite.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverLeft.png new file mode 100755 index 0000000..0fb24d0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverMid.png new file mode 100755 index 0000000..fbccab5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverRight.png new file mode 100755 index 0000000..3db0f36 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabHoverRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabLeft.png new file mode 100755 index 0000000..a6cc9e9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuCheckbox.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuCheckbox.png new file mode 100755 index 0000000..4726e62 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuCheckbox.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuPin.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuPin.png new file mode 100755 index 0000000..eb4b11e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuPin.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuRadio.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuRadio.png new file mode 100755 index 0000000..55b982d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuRadio.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuTarget.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuTarget.png new file mode 100755 index 0000000..957bd9f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuTarget.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuTargetHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuTargetHover.png new file mode 100755 index 0000000..200a370 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMenuTargetHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMid.png new file mode 100755 index 0000000..68986c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabRight.png new file mode 100755 index 0000000..5011307 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tabRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorBorders.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorBorders.gif new file mode 100755 index 0000000..0ee5497 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorBorders.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorBorders.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorBorders.png new file mode 100755 index 0000000..21682c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorBorders.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorCorners.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorCorners.gif new file mode 100755 index 0000000..04f8421 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorCorners.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorCorners.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorCorners.png new file mode 100755 index 0000000..a0f839d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/textEditorCorners.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/titlebarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/titlebarMid.png new file mode 100755 index 0000000..10998ae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/titlebarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/toolbarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/toolbarMid.png new file mode 100755 index 0000000..aa21dee Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/toolbarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tree_close.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tree_close.gif new file mode 100755 index 0000000..e26728a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tree_close.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tree_open.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tree_open.gif new file mode 100755 index 0000000..edf662f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/tree_open.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/up.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/up.png new file mode 100755 index 0000000..2174d03 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/up.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/upActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/upActive.png new file mode 100755 index 0000000..236cf67 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/upActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/upHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/upHover.png new file mode 100755 index 0000000..cd81317 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/upHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/warningIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/warningIcon.gif new file mode 100755 index 0000000..8497278 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/warningIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/warningIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/warningIcon.png new file mode 100755 index 0000000..de51084 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension-beta/skin/xp/warningIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/background.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/background.html new file mode 100755 index 0000000..c4133a1 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/background.html @@ -0,0 +1,187 @@ + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/contentScript.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/contentScript.js new file mode 100755 index 0000000..90b3730 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/contentScript.js @@ -0,0 +1,378 @@ +// ************************************************************************************************* + +var isActive = false; +var isOpen = false; +var extensionURL = null; + +var contextMenuElementXPath = null; +var isListeningKeyboardActivation = false; + +// ************************************************************************************************* + +// restore Firebug Lite state +var loadStateData = function() +{ + var FirebugData = localStorage.getItem("Firebug"); + + isActive = false; + isOpen = false; + extensionURL = chrome.extension.getURL(""); + + if (FirebugData) + { + FirebugData = FirebugData.split(","); + isActive = FirebugData[0] == "1"; + isOpen = FirebugData[1] == "1"; + } +} + +// ************************************************************************************************* + +// load Firebug Lite application +var loadFirebug = function() +{ + document.documentElement.setAttribute("debug", isOpen); + + injectScriptText("("+listenConsoleCalls+")()"); + + // TODO: xxxpedro - change to XHR when Issue 41024 is solved + // Issue 41024: XHR using file: and chrome-extension: protocols not working. + // http://code.google.com/p/chromium/issues/detail?id=41024 + injectFirebugScript(); +} + +// TODO: think a better solution than using the stateData parameter, required +// by the keyboard activation. +var loadFirebugAndWait = function(callback, stateData) +{ + stateData = stateData || ('1,1,'+extensionURL); + localStorage.setItem('Firebug', stateData); + loadStateData(); + chrome.extension.sendRequest({name: isActive ? "FB_enableIcon" : "FB_disableIcon"}); + + document.documentElement.setAttribute("debug", isOpen); + + injectFirebugScript(); + + setTimeout(function(){ + waitFirebug(callback); + },0); +}; + +var waitFirebug = function(callback) +{ + if (document && document.getElementById("FirebugChannel")) + { + stopListeningKeyboardActivation(); + callback(); + } + else + setTimeout(function(){ waitFirebug(callback); }, 100); + +}; + +// ************************************************************************************************* + +// inject Firebug Lite script into the page +var injectFirebugScript = function(url) +{ + scriptElement = document.getElementById("FirebugLite"); + if (scriptElement) + { + firebugDispatch("FB_toggle"); + } + else + { + var script = document.createElement("script"); + + script.src = extensionURL + "firebug-lite.js"; + script.setAttribute("id", "FirebugLite"); + script.setAttribute("firebugIgnore", "true"); + script.setAttribute("extension", "Chrome"); + document.documentElement.appendChild(script); + + script.onload = function() { + // TODO: xxxpedro remove this files when deploy the new structure + script = document.createElement("script"); + script.src = extensionURL + "googleChrome.js"; + document.documentElement.appendChild(script); + }; + } +} + +// inject a script into the page +var injectScriptText = function(text) +{ + var script = document.createElement("script"); + var parent = document.documentElement; + + script.text = text; + script.setAttribute("id", "FirebugLite"); + script.setAttribute("firebugIgnore", "true"); + script.setAttribute("extension", "Chrome"); + parent.appendChild(script); + parent.removeChild(script); +} + +// ************************************************************************************************* + +// communication with the background page +chrome.extension.onRequest.addListener +( + function(request, sender, sendResponse) + { + // check if Firebug Lite is active + if (request.name == "FB_isActive") + { + loadStateData(); + sendResponse({value: ""+isActive}); + } + // load Firebug Lite application + else if (request.name == "FB_loadFirebug") + { + setTimeout(function(){ + + loadStateData(); + + //loadFirebug(); + loadFirebugAndWait(function(){ + + isActive = true; + var message = isActive ? "FB_enableIcon" : "FB_disableIcon"; + chrome.extension.sendRequest({name: message}); + + loadChannel(); + }); + + },0); + + sendResponse({}); + } + // handle context menu click by sending "FB_contextMenuClick" message + // to Firebug Lite application + else if (request.name == "FB_contextMenuClick") + { + // TODO: if not active, activate first, wait the activation to complete + // and only then dispatch the event to Firebug Lite application + if (isActive) + firebugDispatch("FB_contextMenuClick,"+contextMenuElementXPath); + else + loadFirebugAndWait(function(){ + firebugDispatch("FB_contextMenuClick,"+contextMenuElementXPath); + }); + } + else if (request.name == "FB_deactivate") + { + listenKeyboardActivation(); + } + else + sendResponse({}); // snub them. + } +); + +// ************************************************************************************************* + +// communication with the page +var channel = null; +var channelEvent; + +var onFirebugChannelEvent = function() +{ + channel = document.getElementById("FirebugChannel"); + + if (channel) + { + chrome.extension.sendRequest({name: channel.innerText}); + } +}; + +var loadChannel = function() +{ + channel = document.getElementById("FirebugChannel"); + + if (channel) + { + channel.addEventListener("FirebugChannelEvent", onFirebugChannelEvent); + channelEvent = document.createEvent("Event"); + channelEvent.initEvent("FirebugChannelEvent", true, true); + } +} + +var firebugDispatch = function(data) +{ + if (!channel) + loadChannel(); + + channel.innerText = data; + channel.dispatchEvent(channelEvent); +}; + +// ************************************************************************************************* + +var onContextMenu = function(event) +{ + contextMenuElementXPath = getElementXPath(event.target); +}; + +var loadListeners = function() +{ + window.addEventListener("contextmenu", onContextMenu); + window.addEventListener("unload", unloadListeners); +}; + +var unloadListeners = function() +{ + if (channel) + { + channel.removeEventListener("FirebugChannelEvent", onFirebugChannelEvent); + } + + window.removeEventListener("contextmenu", onContextMenu); + window.removeEventListener("unload", unloadListeners); +}; + +// ************************************************************************************************* + +// listen to console calls before Firebug Lite finishes to load +var listenConsoleCalls = function() +{ + // TODO: xxxpedro add all console functions + var fns = ["log", "info", "warn", "error"]; + + var listener = {consoleQueue: ["chromeConsoleQueueHack"]}; + var queue = listener.consoleQueue; + + for (var i=0, l=fns.length; i 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; + if (FBL.Env.isChromeExtension) + { + path = productionDir; + FBL.Env.bookmarkletOutdated = false; + script = {innerHTML: "{showIconWhenHidden:false}"}; + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + var Env = FBL.Env; + + // Always use the local skin when running in the same domain + // See Issue 3554: Firebug Lite should use local images when loaded locally + Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0; + + // detecting development and debug modes via file name + if (fileName == "firebug-lite-dev.js") + { + Env.isDevelopmentMode = true; + Env.isDebugMode = true; + } + else if (fileName == "firebug-lite-debug.js") + { + Env.isDebugMode = true; + } + + // process the + if (Env.browser.document.documentElement.getAttribute("debug") == "true") + { + Env.Options.startOpened = true; + } + + // process the Script URL Options + if (fileOptions) + { + var options = fileOptions.split(","); + + for (var i = 0, length = options.length; i < length; i++) + { + var option = options[i]; + var name, value; + + if (option.indexOf("=") != -1) + { + var parts = option.split("="); + name = parts[0]; + value = eval(unescape(parts[1])); + } + else + { + name = option; + value = true; + } + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Script JSON Options + var innerOptions = FBL.trim(script.innerHTML); + if (innerOptions) + { + var innerOptionsObject = eval("(" + innerOptions + ")"); + + for (var name in innerOptionsObject) + { + var value = innerOptionsObject[name]; + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Debug Mode + if (Env.isDebugMode) + { + Env.Options.startOpened = true; + Env.Options.enableTrace = true; + Env.Options.disableWhenFirebugActive = false; + } + + var loc = Env.Location; + var isProductionRelease = path.indexOf(productionDir) != -1; + + loc.sourceDir = path; + loc.baseDir = path.substr(0, path.length - m[1].length - 1); + loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/"; + loc.skin = loc.skinDir + "firebug.html"; + loc.app = path + fileName; + } + else + { + throw new Error("Firebug Error: Library path not found"); + } +}; + +// ************************************************************************************************ +// Basics + +this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }; +}; + +this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, args); }; +}; + +this.extend = function(l, r) +{ + var newOb = {}; + for (var n in l) + newOb[n] = l[n]; + for (var n in r) + newOb[n] = r[n]; + return newOb; +}; + +this.descend = function(prototypeParent, childProperties) +{ + function protoSetter() {}; + protoSetter.prototype = prototypeParent; + var newOb = new protoSetter(); + for (var n in childProperties) + newOb[n] = childProperties[n]; + return newOb; +}; + +this.append = function(l, r) +{ + for (var n in r) + l[n] = r[n]; + + return l; +}; + +this.keys = function(map) // At least sometimes the keys will be on user-level window objects +{ + var keys = []; + try + { + for (var name in map) // enumeration is safe + keys.push(name); // name is string, safe + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + } + + return keys; // return is safe +}; + +this.values = function(map) +{ + var values = []; + try + { + for (var name in map) + { + try + { + values.push(map[name]); + } + catch (exc) + { + // Sometimes we get exceptions trying to access properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + } + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + return values; +}; + +this.remove = function(list, item) +{ + for (var i = 0; i < list.length; ++i) + { + if (list[i] == item) + { + list.splice(i, 1); + break; + } + } +}; + +this.sliceArray = function(array, index) +{ + var slice = []; + for (var i = index; i < array.length; ++i) + slice.push(array[i]); + + return slice; +}; + +function cloneArray(array, fn) +{ + var newArray = []; + + if (fn) + for (var i = 0; i < array.length; ++i) + newArray.push(fn(array[i])); + else + for (var i = 0; i < array.length; ++i) + newArray.push(array[i]); + + return newArray; +} + +function extendArray(array, array2) +{ + var newArray = []; + newArray.push.apply(newArray, array); + newArray.push.apply(newArray, array2); + return newArray; +} + +this.extendArray = extendArray; +this.cloneArray = cloneArray; + +function arrayInsert(array, index, other) +{ + for (var i = 0; i < other.length; ++i) + array.splice(i+index, 0, other[i]); + + return array; +} + +// ************************************************************************************************ + +this.createStyleSheet = function(doc, url) +{ + //TODO: xxxpedro + //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + var style = this.createElement("link"); + style.setAttribute("charset","utf-8"); + style.firebugIgnore = true; + style.setAttribute("rel", "stylesheet"); + style.setAttribute("type", "text/css"); + style.setAttribute("href", url); + + //TODO: xxxpedro + //style.innerHTML = this.getResource(url); + return style; +}; + +this.addStyleSheet = function(doc, style) +{ + var heads = doc.getElementsByTagName("head"); + if (heads.length) + heads[0].appendChild(style); + else + doc.documentElement.appendChild(style); +}; + +this.appendStylesheet = function(doc, uri) +{ + // Make sure the stylesheet is not appended twice. + if (this.$(uri, doc)) + return; + + var styleSheet = this.createStyleSheet(doc, uri); + styleSheet.setAttribute("id", uri); + this.addStyleSheet(doc, styleSheet); +}; + +this.addScript = function(doc, id, src) +{ + var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script"); + element.setAttribute("type", "text/javascript"); + element.setAttribute("id", id); + if (!FBTrace.DBG_CONSOLE) + FBL.unwrapObject(element).firebugIgnore = true; + + element.innerHTML = src; + if (doc.documentElement) + doc.documentElement.appendChild(element); + else + { + // See issue 1079, the svg test case gives this error + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.addScript doc has no documentElement:", doc); + } + return element; +}; + + +// ************************************************************************************************ + +this.getStyle = this.isIE ? + function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : + function(el, name) + { + return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + }; + + +// ************************************************************************************************ +// Whitespace and Entity conversions + +var entityConversionLists = this.entityConversionLists = { + normal : { + whitespace : { + '\t' : '\u200c\u2192', + '\n' : '\u200c\u00b6', + '\r' : '\u200c\u00ac', + ' ' : '\u200c\u00b7' + } + }, + reverse : { + whitespace : { + ' ' : '\t', + ' ' : '\n', + '\u200c\u2192' : '\t', + '\u200c\u00b6' : '\n', + '\u200c\u00ac' : '\r', + '\u200c\u00b7' : ' ' + } + } +}; + +var normal = entityConversionLists.normal, + reverse = entityConversionLists.reverse; + +function addEntityMapToList(ccode, entity) +{ + var lists = Array.prototype.slice.call(arguments, 2), + len = lists.length, + ch = String.fromCharCode(ccode); + for (var i = 0; i < len; i++) + { + var list = lists[i]; + normal[list]=normal[list] || {}; + normal[list][ch] = '&' + entity + ';'; + reverse[list]=reverse[list] || {}; + reverse[list]['&' + entity + ';'] = ch; + } +}; + +var e = addEntityMapToList, + white = 'whitespace', + text = 'text', + attr = 'attributes', + css = 'css', + editor = 'editor'; + +e(0x0022, 'quot', attr, css); +e(0x0026, 'amp', attr, text, css); +e(0x0027, 'apos', css); +e(0x003c, 'lt', attr, text, css); +e(0x003e, 'gt', attr, text, css); +e(0xa9, 'copy', text, editor); +e(0xae, 'reg', text, editor); +e(0x2122, 'trade', text, editor); + +// See http://en.wikipedia.org/wiki/Dash +e(0x2012, '#8210', attr, text, editor); // figure dash +e(0x2013, 'ndash', attr, text, editor); // en dash +e(0x2014, 'mdash', attr, text, editor); // em dash +e(0x2015, '#8213', attr, text, editor); // horizontal bar + +e(0x00a0, 'nbsp', attr, text, white, editor); +e(0x2002, 'ensp', attr, text, white, editor); +e(0x2003, 'emsp', attr, text, white, editor); +e(0x2009, 'thinsp', attr, text, white, editor); +e(0x200c, 'zwnj', attr, text, white, editor); +e(0x200d, 'zwj', attr, text, white, editor); +e(0x200e, 'lrm', attr, text, white, editor); +e(0x200f, 'rlm', attr, text, white, editor); +e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP) + +//************************************************************************************************ +// Entity escaping + +var entityConversionRegexes = { + normal : {}, + reverse : {} + }; + +var escapeEntitiesRegEx = { + normal : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('([' + chars.join('') + '])', 'gm'); + }, + reverse : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('(' + chars.join('|') + ')', 'gm'); + } +}; + +function getEscapeRegexp(direction, lists) +{ + var name = '', re; + var groups = [].concat(lists); + for (i = 0; i < groups.length; i++) + { + name += groups[i].group; + } + re = entityConversionRegexes[direction][name]; + if (!re) + { + var list = {}; + if (groups.length > 1) + { + for ( var i = 0; i < groups.length; i++) + { + var aList = entityConversionLists[direction][groups[i].group]; + for ( var item in aList) + list[item] = aList[item]; + } + } else if (groups.length==1) + { + list = entityConversionLists[direction][groups[0].group]; // faster for special case + } else { + list = {}; // perhaps should print out an error here? + } + re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list); + } + return re; +}; + +function createSimpleEscape(name, direction) +{ + return function(value) + { + var list = entityConversionLists[direction][name]; + return String(value).replace( + getEscapeRegexp(direction, { + group : name, + list : list + }), + function(ch) + { + return list[ch]; + } + ); + }; +}; + +function escapeGroupsForEntities(str, lists) +{ + lists = [].concat(lists); + var re = getEscapeRegexp('normal', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list, last = ''; + if (!len) + return [ { + str : String(str), + group : '', + name : '' + } ]; + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.normal[list.group][cur]; + // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space + // r = ' '; + if (r) + { + results[ri] = { + 'str' : r, + 'class' : list['class'], + 'extra' : list.extra[cur] ? list['class'] + + list.extra[cur] : '' + }; + break; + } + } + // last=cur; + if (!r) + results[ri] = { + 'str' : cur, + 'class' : '', + 'extra' : '' + }; + ri++; + } + return results; +}; + +this.escapeGroupsForEntities = escapeGroupsForEntities; + + +function unescapeEntities(str, lists) +{ + var re = getEscapeRegexp('reverse', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list; + if (!len) + return str; + lists = [].concat(lists); + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.reverse[list.group][cur]; + if (r) + { + results[ri] = r; + break; + } + } + if (!r) + results[ri] = cur; + ri++; + } + return results.join('') || ''; +}; + + +// ************************************************************************************************ +// String escaping + +var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal'); +var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal'); +var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal'); +var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal'); + +// deprecated compatibility functions +//this.deprecateEscapeHTML = createSimpleEscape('text', 'normal'); +//this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse'); +//this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML); +//this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML); + +var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); + +var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); + +this.unescapeForTextNode = function(str) +{ + if (Firebug.showTextNodesWithWhitespace) + str = unescapeWhitespace(str); + if (!Firebug.showTextNodesWithEntities) + str = escapeForElementAttribute(str); + return str; +}; + +this.escapeNewLines = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); +}; + +this.stripNewLines = function(value) +{ + return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; +}; + +this.escapeJS = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); +}; + +function escapeHTMLAttribute(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "&": + return "&"; + case "'": + return apos; + case '"': + return quot; + } + return "?"; + }; + var apos = "'", quot = """, around = '"'; + if( value.indexOf('"') == -1 ) { + quot = '"'; + apos = "'"; + } else if( value.indexOf("'") == -1 ) { + quot = '"'; + around = "'"; + } + return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; +} + + +function escapeHTML(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); +} + +this.escapeHTML = escapeHTML; + +this.cropString = function(text, limit) +{ + text = text + ""; + + if (!limit) + var halfLimit = 50; + else + var halfLimit = limit / 2; + + if (text.length > limit) + return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); + else + return this.escapeNewLines(text); +}; + +this.isWhitespace = function(text) +{ + return !reNotWhitespace.exec(text); +}; + +this.splitLines = function(text) +{ + var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; + var lines; + if (text.match) + { + lines = text.match(reSplitLines2); + } + else + { + var str = text+""; + lines = str.match(reSplitLines2); + } + lines.pop(); + return lines; +}; + + +// ************************************************************************************************ + +this.safeToString = function(ob) +{ + if (this.isIE) + return ob + ""; + + try + { + if (ob && "toString" in ob && typeof ob.toString == "function") + return ob.toString(); + } + catch (exc) + { + // xxxpedro it is not safe to use ob+""? + return ob + ""; + ///return "[an object with no toString() function]"; + } +}; + +// ************************************************************************************************ + +this.hasProperties = function(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + return false; +}; + +// ************************************************************************************************ +// String Util + +var reTrim = /^\s+|\s+$/g; +this.trim = function(s) +{ + return s.replace(reTrim, ""); +}; + + +// ************************************************************************************************ +// Empty + +this.emptyFn = function(){}; + + + +// ************************************************************************************************ +// Visibility + +this.isVisible = function(elt) +{ + /* + if (elt instanceof XULElement) + { + //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); + return (!elt.hidden && !elt.collapsed); + } + /**/ + + return this.getStyle(elt, "visibility") != "hidden" && + ( elt.offsetWidth > 0 || elt.offsetHeight > 0 + || elt.tagName in invisibleTags + || elt.namespaceURI == "http://www.w3.org/2000/svg" + || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" ); +}; + +this.collapse = function(elt, collapsed) +{ + // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector, + // but it is causing a bug (the element disappears when you set the "collapsed" + // attribute, but it doesn't appear when you remove the attribute. So, for those + // cases, we need to use the class attribute. + if (this.isIElt8) + { + if (collapsed) + this.setClass(elt, "collapsed"); + else + this.removeClass(elt, "collapsed"); + } + else + elt.setAttribute("collapsed", collapsed ? "true" : "false"); +}; + +this.obscure = function(elt, obscured) +{ + if (obscured) + this.setClass(elt, "obscured"); + else + this.removeClass(elt, "obscured"); +}; + +this.hide = function(elt, hidden) +{ + elt.style.visibility = hidden ? "hidden" : "visible"; +}; + +this.clearNode = function(node) +{ + var nodeName = " " + node.nodeName.toLowerCase() + " "; + var ignoreTags = " table tbody thead tfoot th tr td "; + + // IE can't use innerHTML of table elements + if (this.isIE && ignoreTags.indexOf(nodeName) != -1) + this.eraseNode(node); + else + node.innerHTML = ""; +}; + +this.eraseNode = function(node) +{ + while (node.lastChild) + node.removeChild(node.lastChild); +}; + +// ************************************************************************************************ +// Window iteration + +this.iterateWindows = function(win, handler) +{ + if (!win || !win.document) + return; + + handler(win); + + if (win == top || !win.frames) return; // XXXjjb hack for chromeBug + + for (var i = 0; i < win.frames.length; ++i) + { + var subWin = win.frames[i]; + if (subWin != win) + this.iterateWindows(subWin, handler); + } +}; + +this.getRootWindow = function(win) +{ + for (; win; win = win.parent) + { + if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) + return win; + } + return null; +}; + +// ************************************************************************************************ +// Graphics + +this.getClientOffset = function(elt) +{ + var addOffset = function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + + var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, ""); + + if (elt.offsetLeft) + coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth); + if (elt.offsetTop) + coords.y += elt.offsetTop + parseInt(style.borderTopWidth); + + if (p) + { + if (p.nodeType == 1) + addOffset(p, coords, view); + } + else + { + var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + if (otherView.frameElement) + addOffset(otherView.frameElement, coords, otherView); + } + }; + + var isIE = this.isIE; + var coords = {x: 0, y: 0}; + if (elt) + { + var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + addOffset(elt, coords, view); + } + + return coords; +}; + +this.getViewOffset = function(elt, singleFrame) +{ + function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); + coords.y += elt.offsetTop - (p ? p.scrollTop : 0); + + if (p) + { + if (p.nodeType == 1) + { + var parentStyle = view.getComputedStyle(p, ""); + if (parentStyle.position != "static") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + + if (p.localName == "TABLE") + { + coords.x += parseInt(parentStyle.paddingLeft); + coords.y += parseInt(parentStyle.paddingTop); + } + else if (p.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.marginLeft); + coords.y += parseInt(style.marginTop); + } + } + else if (p.localName == "BODY") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + } + + var parent = elt.parentNode; + while (p != parent) + { + coords.x -= parent.scrollLeft; + coords.y -= parent.scrollTop; + parent = parent.parentNode; + } + addOffset(p, coords, view); + } + } + else + { + if (elt.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.borderLeftWidth); + coords.y += parseInt(style.borderTopWidth); + + var htmlStyle = view.getComputedStyle(elt.parentNode, ""); + coords.x -= parseInt(htmlStyle.paddingLeft); + coords.y -= parseInt(htmlStyle.paddingTop); + } + + if (elt.scrollLeft) + coords.x += elt.scrollLeft; + if (elt.scrollTop) + coords.y += elt.scrollTop; + + var win = elt.ownerDocument.defaultView; + if (win && (!singleFrame && win.frameElement)) + addOffset(win.frameElement, coords, win); + } + + } + + var coords = {x: 0, y: 0}; + if (elt) + addOffset(elt, coords, elt.ownerDocument.defaultView); + + return coords; +}; + +this.getLTRBWH = function(elt) +{ + var bcrect, + dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; + + if (elt) + { + bcrect = elt.getBoundingClientRect(); + dims.left = bcrect.left; + dims.top = bcrect.top; + dims.right = bcrect.right; + dims.bottom = bcrect.bottom; + + if(bcrect.width) + { + dims.width = bcrect.width; + dims.height = bcrect.height; + } + else + { + dims.width = dims.right - dims.left; + dims.height = dims.bottom - dims.top; + } + } + return dims; +}; + +this.applyBodyOffsets = function(elt, clientRect) +{ + var od = elt.ownerDocument; + if (!od.body) + return clientRect; + + var style = od.defaultView.getComputedStyle(od.body, null); + + var pos = style.getPropertyValue('position'); + if(pos === 'absolute' || pos === 'relative') + { + var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0; + var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0; + var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0; + var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0; + var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0; + var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0; + + var offsetX = borderLeft + paddingLeft + marginLeft; + var offsetY = borderTop + paddingTop + marginTop; + + clientRect.left -= offsetX; + clientRect.top -= offsetY; + clientRect.right -= offsetX; + clientRect.bottom -= offsetY; + } + + return clientRect; +}; + +this.getOffsetSize = function(elt) +{ + return {width: elt.offsetWidth, height: elt.offsetHeight}; +}; + +this.getOverflowParent = function(element) +{ + for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) + { + if (scrollParent.scrollHeight > scrollParent.offsetHeight) + return scrollParent; + } +}; + +this.isScrolledToBottom = function(element) +{ + var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight; + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom); + return onBottom; +}; + +this.scrollToBottom = function(element) +{ + element.scrollTop = element.scrollHeight; + + if (FBTrace.DBG_CONSOLE) + { + FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); + if (element.scrollHeight == element.offsetHeight) + FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element); + } + + return (element.scrollTop == element.scrollHeight); +}; + +this.move = function(element, x, y) +{ + element.style.left = x + "px"; + element.style.top = y + "px"; +}; + +this.resize = function(element, w, h) +{ + element.style.width = w + "px"; + element.style.height = h + "px"; +}; + +this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} +{ + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var split = (scrollBox.clientHeight/2); + var centerY = offset.y - split; + scrollBox.scrollTop = centerY; + topSpace = split; + bottomSpace = split - element.offsetHeight; + } + + return {before: Math.round((topSpace/element.offsetHeight) + 0.5), + after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; +}; + +this.scrollIntoCenterView = function(element, scrollBox, notX, notY) +{ + if (!element) + return; + + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + if (!notY) + { + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var centerY = offset.y - (scrollBox.clientHeight/2); + scrollBox.scrollTop = centerY; + } + } + + if (!notX) + { + var leftSpace = offset.x - scrollBox.scrollLeft; + var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) + - (offset.x + element.clientWidth); + + if (leftSpace < 0 || rightSpace < 0) + { + var centerX = offset.x - (scrollBox.clientWidth/2); + scrollBox.scrollLeft = centerX; + } + } + if (FBTrace.DBG_SOURCEFILES) + FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); +}; + + +// ************************************************************************************************ +// CSS + +var cssKeywordMap = null; +var cssPropNames = null; +var cssColorNames = null; +var imageRules = null; + +this.getCSSKeywordsByProperty = function(propName) +{ + if (!cssKeywordMap) + { + cssKeywordMap = {}; + + for (var name in this.cssInfo) + { + var list = []; + + var types = this.cssInfo[name]; + for (var i = 0; i < types.length; ++i) + { + var keywords = this.cssKeywords[types[i]]; + if (keywords) + list.push.apply(list, keywords); + } + + cssKeywordMap[name] = list; + } + } + + return propName in cssKeywordMap ? cssKeywordMap[propName] : []; +}; + +this.getCSSPropertyNames = function() +{ + if (!cssPropNames) + { + cssPropNames = []; + + for (var name in this.cssInfo) + cssPropNames.push(name); + } + + return cssPropNames; +}; + +this.isColorKeyword = function(keyword) +{ + if (keyword == "transparent") + return false; + + if (!cssColorNames) + { + cssColorNames = []; + + var colors = this.cssKeywords["color"]; + for (var i = 0; i < colors.length; ++i) + cssColorNames.push(colors[i].toLowerCase()); + + var systemColors = this.cssKeywords["systemColor"]; + for (var i = 0; i < systemColors.length; ++i) + cssColorNames.push(systemColors[i].toLowerCase()); + } + + return cssColorNames.indexOf ? // Array.indexOf is not available in IE + cssColorNames.indexOf(keyword.toLowerCase()) != -1 : + (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; +}; + +this.isImageRule = function(rule) +{ + if (!imageRules) + { + imageRules = []; + + for (var i in this.cssInfo) + { + var r = i.toLowerCase(); + var suffix = "image"; + if (r.match(suffix + "$") == suffix || r == "background") + imageRules.push(r); + } + } + + return imageRules.indexOf ? // Array.indexOf is not available in IE + imageRules.indexOf(rule.toLowerCase()) != -1 : + (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; +}; + +this.copyTextStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.fontFamily = style.fontFamily; + + // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE + // returns wrong computed styles for inherited properties (like font-*) + // + // Also would be good to create a FBL.getStyle() + toNode.style.fontSize = style.fontSize; + toNode.style.fontWeight = style.fontWeight; + toNode.style.fontStyle = style.fontStyle; + + return style; + } +}; + +this.copyBoxStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.marginTop = style.marginTop; + toNode.style.marginRight = style.marginRight; + toNode.style.marginBottom = style.marginBottom; + toNode.style.marginLeft = style.marginLeft; + toNode.style.borderTopWidth = style.borderTopWidth; + toNode.style.borderRightWidth = style.borderRightWidth; + toNode.style.borderBottomWidth = style.borderBottomWidth; + toNode.style.borderLeftWidth = style.borderLeftWidth; + + return style; + } +}; + +this.readBoxStyles = function(style) +{ + var styleNames = { + "margin-top": "marginTop", "margin-right": "marginRight", + "margin-left": "marginLeft", "margin-bottom": "marginBottom", + "border-top-width": "borderTop", "border-right-width": "borderRight", + "border-left-width": "borderLeft", "border-bottom-width": "borderBottom", + "padding-top": "paddingTop", "padding-right": "paddingRight", + "padding-left": "paddingLeft", "padding-bottom": "paddingBottom", + "z-index": "zIndex" + }; + + var styles = {}; + for (var styleName in styleNames) + styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0; + if (FBTrace.DBG_INSPECT) + FBTrace.sysout("readBoxStyles ", styles); + return styles; +}; + +this.getBoxFromStyles = function(style, element) +{ + var args = this.readBoxStyles(style); + args.width = element.offsetWidth + - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight); + args.height = element.offsetHeight + - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom); + return args; +}; + +this.getElementCSSSelector = function(element) +{ + var label = element.localName.toLowerCase(); + if (element.id) + label += "#" + element.id; + if (element.hasAttribute("class")) + label += "." + element.getAttribute("class").split(" ")[0]; + + return label; +}; + +this.getURLForStyleSheet= function(styleSheet) +{ + //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null. + return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL); +}; + +this.getDocumentForStyleSheet = function(styleSheet) +{ + while (styleSheet.parentStyleSheet && !styleSheet.ownerNode) + { + styleSheet = styleSheet.parentStyleSheet; + } + if (styleSheet.ownerNode) + return styleSheet.ownerNode.ownerDocument; +}; + +/** + * Retrieves the instance number for a given style sheet. The instance number + * is sheet's index within the set of all other sheets whose URL is the same. + */ +this.getInstanceForStyleSheet = function(styleSheet, ownerDocument) +{ + // System URLs are always unique (or at least we are making this assumption) + if (FBL.isSystemStyleSheet(styleSheet)) + return 0; + + // ownerDocument is an optional hint for performance + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument); + ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet); + + var ret = 0, + styleSheets = ownerDocument.styleSheets, + href = styleSheet.href; + for (var i = 0; i < styleSheets.length; i++) + { + var curSheet = styleSheets[i]; + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode))); + if (curSheet == styleSheet) + break; + if (curSheet.href == href) + ret++; + } + return ret; +}; + +// ************************************************************************************************ +// HTML and XML Serialization + + +var getElementType = this.getElementType = function(node) +{ + if (isElementXUL(node)) + return 'xul'; + else if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else if (isElementXHTML(node)) + return 'xhtml'; + else if (isElementHTML(node)) + return 'html'; +} + +var getElementSimpleType = this.getElementSimpleType = function(node) +{ + if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else + return 'html'; +} + +var isElementHTML = this.isElementHTML = function(node) +{ + return node.nodeName == node.nodeName.toUpperCase(); +} + +var isElementXHTML = this.isElementXHTML = function(node) +{ + return node.nodeName == node.nodeName.toLowerCase(); +} + +var isElementMathML = this.isElementMathML = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; +} + +var isElementSVG = this.isElementSVG = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/2000/svg'; +} + +var isElementXUL = this.isElementXUL = function(node) +{ + return node instanceof XULElement; +} + +this.isSelfClosing = function(element) +{ + if (isElementSVG(element) || isElementMathML(element)) + return true; + var tag = element.localName.toLowerCase(); + return (this.selfClosingTags.hasOwnProperty(tag)); +}; + +this.getElementHTML = function(element) +{ + var self=this; + function toHTML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + html.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + html.push('>'); + + var pureText=true; + for (var child = element.firstChild; child; child = child.nextSibling) + pureText=pureText && (child.nodeType == Node.TEXT_NODE); + + if (pureText) + html.push(escapeForHtmlEditor(elt.textContent)); + else { + for (var child = elt.firstChild; child; child = child.nextSibling) + toHTML(child); + } + + html.push(''); + } + else if (isElementSVG(elt) || isElementMathML(elt)) + { + html.push('/>'); + } + else if (self.isSelfClosing(elt)) + { + html.push((isElementXHTML(elt))?'/>':'>'); + } + else + { + html.push('>'); + } + } + else if (elt.nodeType == Node.TEXT_NODE) + html.push(escapeForTextNode(elt.textContent)); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + html.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + html.push(''); + } + + var html = []; + toHTML(element); + return html.join(""); +}; + +this.getElementXML = function(element) +{ + function toXML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + xml.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + xml.push('>'); + + for (var child = elt.firstChild; child; child = child.nextSibling) + toXML(child); + + xml.push(''); + } + else + xml.push('/>'); + } + else if (elt.nodeType == Node.TEXT_NODE) + xml.push(elt.nodeValue); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + xml.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + xml.push(''); + } + + var xml = []; + toXML(element); + return xml.join(""); +}; + + +// ************************************************************************************************ +// CSS classes + +this.hasClass = function(node, name) // className, className, ... +{ + // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments? + // this function can be optimized a lot if assumed 2 arguments only, + // which seems to be what happens 99% of the time + if (arguments.length == 2) + return (' '+node.className+' ').indexOf(' '+name+' ') != -1; + + if (!node || node.nodeType != 1) + return false; + else + { + for (var i=1; i= 0) + { + var size = name.length; + node.className = node.className.substr(0,index-1) + node.className.substr(index+size); + } + } +}; + +this.toggleClass = function(elt, name) +{ + if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1) + ///if (this.hasClass(elt, name)) + this.removeClass(elt, name); + else + this.setClass(elt, name); +}; + +this.setClassTimed = function(elt, name, context, timeout) +{ + if (!timeout) + timeout = 1300; + + if (elt.__setClassTimeout) + context.clearTimeout(elt.__setClassTimeout); + else + this.setClass(elt, name); + + elt.__setClassTimeout = context.setTimeout(function() + { + delete elt.__setClassTimeout; + + FBL.removeClass(elt, name); + }, timeout); +}; + +this.cancelClassTimed = function(elt, name, context) +{ + if (elt.__setClassTimeout) + { + FBL.removeClass(elt, name); + context.clearTimeout(elt.__setClassTimeout); + delete elt.__setClassTimeout; + } +}; + + +// ************************************************************************************************ +// DOM queries + +this.$ = function(id, doc) +{ + if (doc) + return doc.getElementById(id); + else + { + return FBL.Firebug.chrome.document.getElementById(id); + } +}; + +this.$$ = function(selector, doc) +{ + if (doc || !FBL.Firebug.chrome) + return FBL.Firebug.Selector(selector, doc); + else + { + return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document); + } +}; + +this.getChildByClass = function(node) // ,classname, classname, classname... +{ + for (var i = 1; i < arguments.length; ++i) + { + var className = arguments[i]; + var child = node.firstChild; + node = null; + for (; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + { + node = child; + break; + } + } + } + + return node; +}; + +this.getAncestorByClass = function(node, className) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (this.hasClass(parent, className)) + return parent; + } + + return null; +}; + + +this.getElementsByClass = function(node, className) +{ + var result = []; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + result.push(child); + } + + return result; +}; + +this.getElementByClass = function(node, className) // className, className, ... +{ + var args = cloneArray(arguments); args.splice(0, 1); + for (var child = node.firstChild; child; child = child.nextSibling) + { + var args1 = cloneArray(args); args1.unshift(child); + if (FBL.hasClass.apply(null, args1)) + return child; + else + { + var found = FBL.getElementByClass.apply(null, args1); + if (found) + return found; + } + } + + return null; +}; + +this.isAncestor = function(node, potentialAncestor) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (parent == potentialAncestor) + return true; + } + + return false; +}; + +this.getNextElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.nextSibling; + + return node; +}; + +this.getPreviousElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.previousSibling; + + return node; +}; + +this.getBody = function(doc) +{ + if (doc.body) + return doc.body; + + var body = doc.getElementsByTagName("body")[0]; + if (body) + return body; + + return doc.firstChild; // For non-HTML docs +}; + +this.findNextDown = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (criteria(child)) + return child; + + var next = this.findNextDown(child, criteria); + if (next) + return next; + } +}; + +this.findPreviousUp = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.lastChild; child; child = child.previousSibling) + { + var next = this.findPreviousUp(child, criteria); + if (next) + return next; + + if (criteria(child)) + return child; + } +}; + +this.findNext = function(node, criteria, upOnly, maxRoot) +{ + if (!node) + return null; + + if (!upOnly) + { + var next = this.findNextDown(node, criteria); + if (next) + return next; + } + + for (var sib = node.nextSibling; sib; sib = sib.nextSibling) + { + if (criteria(sib)) + return sib; + + var next = this.findNextDown(sib, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + return this.findNext(node.parentNode, criteria, true); +}; + +this.findPrevious = function(node, criteria, downOnly, maxRoot) +{ + if (!node) + return null; + + for (var sib = node.previousSibling; sib; sib = sib.previousSibling) + { + var prev = this.findPreviousUp(sib, criteria); + if (prev) + return prev; + + if (criteria(sib)) + return sib; + } + + if (!downOnly) + { + var next = this.findPreviousUp(node, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + { + if (criteria(node.parentNode)) + return node.parentNode; + + return this.findPrevious(node.parentNode, criteria, true); + } +}; + +this.getNextByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findNext(root, iter); +}; + +this.getPreviousByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findPrevious(root, iter); +}; + +this.isElement = function(o) +{ + try { + return o && this.instanceOf(o, "Element"); + } + catch (ex) { + return false; + } +}; + + +// ************************************************************************************************ +// DOM Modification + +// TODO: xxxpedro use doc fragments in Context API +var appendFragment = null; + +this.appendInnerHTML = function(element, html, referenceElement) +{ + // if undefined, we must convert it to null otherwise it will throw an error in IE + // when executing element.insertBefore(firstChild, referenceElement) + referenceElement = referenceElement || null; + + var doc = element.ownerDocument; + + // doc.createRange not available in IE + if (doc.createRange) + { + var range = doc.createRange(); // a helper object + range.selectNodeContents(element); // the environment to interpret the html + + var fragment = range.createContextualFragment(html); // parse + var firstChild = fragment.firstChild; + element.insertBefore(fragment, referenceElement); + } + else + { + if (!appendFragment || appendFragment.ownerDocument != doc) + appendFragment = doc.createDocumentFragment(); + + var div = doc.createElement("div"); + div.innerHTML = html; + + var firstChild = div.firstChild; + while (div.firstChild) + appendFragment.appendChild(div.firstChild); + + element.insertBefore(appendFragment, referenceElement); + + div = null; + } + + return firstChild; +}; + + +// ************************************************************************************************ +// DOM creation + +this.createElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = properties.document || FBL.Firebug.chrome.document; + + var element = doc.createElement(tagName); + + for(var name in properties) + { + if (name != "document") + { + element[name] = properties[name]; + } + } + + return element; +}; + +this.createGlobalElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = FBL.Env.browser.document; + + var element = this.NS && doc.createElementNS ? + doc.createElementNS(FBL.NS, tagName) : + doc.createElement(tagName); + + for(var name in properties) + { + var propname = name; + if (FBL.isIE && name == "class") propname = "className"; + + if (name != "document") + { + element.setAttribute(propname, properties[name]); + } + } + + return element; +}; + +//************************************************************************************************ + +this.safeGetWindowLocation = function(window) +{ + try + { + if (window) + { + if (window.closed) + return "(window.closed)"; + if ("location" in window) + return window.location+""; + else + return "(no window.location)"; + } + else + return "(no context.window)"; + } + catch(exc) + { + if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS) + FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc); + FBTrace.sysout("TabContext.getWindowLocation failed window:", window); + return "(getWindowLocation: "+exc+")"; + } +}; + +// ************************************************************************************************ +// Events + +this.isLeftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && // others + this.noKeyModifiers(event); +}; + +this.isMiddleClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 4 : // IE "click" and "dblclick" button model + event.button == 1) && + this.noKeyModifiers(event); +}; + +this.isRightClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 2 : // IE "click" and "dblclick" button model + event.button == 2) && + this.noKeyModifiers(event); +}; + +this.noKeyModifiers = function(event) +{ + return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey; +}; + +this.isControlClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isControl(event); +}; + +this.isShiftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isShift(event); +}; + +this.isControl = function(event) +{ + return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; +}; + +this.isAlt = function(event) +{ + return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey; +}; + +this.isAltClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isAlt(event); +}; + +this.isControlShift = function(event) +{ + return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey; +}; + +this.isShift = function(event) +{ + return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey; +}; + +this.addEvent = function(object, name, handler, useCapture) +{ + if (object.addEventListener) + object.addEventListener(name, handler, useCapture); + else + object.attachEvent("on"+name, handler); +}; + +this.removeEvent = function(object, name, handler, useCapture) +{ + try + { + if (object.removeEventListener) + object.removeEventListener(name, handler, useCapture); + else + object.detachEvent("on"+name, handler); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("FBL.removeEvent error: ", object, name); + } +}; + +this.cancelEvent = function(e, preventDefault) +{ + if (!e) return; + + if (preventDefault) + { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + } + + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.addGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.addEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.addEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.addEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +this.removeGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.removeEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.removeEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.removeEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.dispatch = function(listeners, name, args) +{ + if (!listeners) return; + + try + {/**/ + if (typeof listeners.length != "undefined") + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); + + for (var i = 0; i < listeners.length; ++i) + { + var listener = listeners[i]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + else + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object"); + + for (var prop in listeners) + { + var listener = listeners[prop]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout(" Exception in lib.dispatch "+ name, exc); + //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener); + } + } + /**/ +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var disableTextSelectionHandler = function(event) +{ + FBL.cancelEvent(event, true); + + return false; +}; + +this.disableTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.addEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.addEvent(e, "mousedown", disableTextSelectionHandler); + } + + e.style.cursor = "default"; +}; + +this.restoreTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.removeEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "cursor: default;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.removeEvent(e, "mousedown", disableTextSelectionHandler); + } +}; + +// ************************************************************************************************ +// DOM Events + +var eventTypes = +{ + composition: [ + "composition", + "compositionstart", + "compositionend" ], + contextmenu: [ + "contextmenu" ], + drag: [ + "dragenter", + "dragover", + "dragexit", + "dragdrop", + "draggesture" ], + focus: [ + "focus", + "blur" ], + form: [ + "submit", + "reset", + "change", + "select", + "input" ], + key: [ + "keydown", + "keyup", + "keypress" ], + load: [ + "load", + "beforeunload", + "unload", + "abort", + "error" ], + mouse: [ + "mousedown", + "mouseup", + "click", + "dblclick", + "mouseover", + "mouseout", + "mousemove" ], + mutation: [ + "DOMSubtreeModified", + "DOMNodeInserted", + "DOMNodeRemoved", + "DOMNodeRemovedFromDocument", + "DOMNodeInsertedIntoDocument", + "DOMAttrModified", + "DOMCharacterDataModified" ], + paint: [ + "paint", + "resize", + "scroll" ], + scroll: [ + "overflow", + "underflow", + "overflowchanged" ], + text: [ + "text" ], + ui: [ + "DOMActivate", + "DOMFocusIn", + "DOMFocusOut" ], + xul: [ + "popupshowing", + "popupshown", + "popuphiding", + "popuphidden", + "close", + "command", + "broadcast", + "commandupdate" ] +}; + +this.getEventFamily = function(eventType) +{ + if (!this.families) + { + this.families = {}; + + for (var family in eventTypes) + { + var types = eventTypes[family]; + for (var i = 0; i < types.length; ++i) + this.families[types[i]] = family; + } + } + + return this.families[eventType]; +}; + + +// ************************************************************************************************ +// URLs + +this.getFileName = function(url) +{ + var split = this.splitURLBase(url); + return split.name; +}; + +this.splitURLBase = function(url) +{ + if (this.isDataURL(url)) + return this.splitDataURL(url); + return this.splitURLTrue(url); +}; + +this.splitDataURL = function(url) +{ + var mark = url.indexOf(':', 3); + if (mark != 4) + return false; // the first 5 chars must be 'data:' + + var point = url.indexOf(',', mark+1); + if (point < mark) + return false; // syntax error + + var props = { encodedContent: url.substr(point+1) }; + + var metadataBuffer = url.substr(mark+1, point); + var metadata = metadataBuffer.split(';'); + for (var i = 0; i < metadata.length; i++) + { + var nv = metadata[i].split('='); + if (nv.length == 2) + props[nv[0]] = nv[1]; + } + + // Additional Firebug-specific properties + if (props.hasOwnProperty('fileName')) + { + var caller_URL = decodeURIComponent(props['fileName']); + var caller_split = this.splitURLTrue(caller_URL); + + if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval() + { + props['path'] = caller_split.path; + props['line'] = props['baseLineNumber']; + var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + props['name'] = 'eval->'+hint; + } + else + { + props['name'] = caller_split.name; + props['path'] = caller_split.path; + } + } + else + { + if (!props.hasOwnProperty('path')) + props['path'] = "data:"; + if (!props.hasOwnProperty('name')) + props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + } + + return props; +}; + +this.splitURLTrue = function(url) +{ + var m = reSplitFile.exec(url); + if (!m) + return {name: url, path: url}; + else if (!m[2]) + return {path: m[1], name: m[1]}; + else + return {path: m[1], name: m[2]+m[3]}; +}; + +this.getFileExtension = function(url) +{ + if (!url) + return null; + + // Remove query string from the URL if any. + var queryString = url.indexOf("?"); + if (queryString != -1) + url = url.substr(0, queryString); + + // Now get the file extension. + var lastDot = url.lastIndexOf("."); + return url.substr(lastDot+1); +}; + +this.isSystemURL = function(url) +{ + if (!url) return true; + if (url.length == 0) return true; + if (url[0] == 'h') return false; + if (url.substr(0, 9) == "resource:") + return true; + else if (url.substr(0, 16) == "chrome://firebug") + return true; + else if (url == "XPCSafeJSObjectWrapper.cpp") + return true; + else if (url.substr(0, 6) == "about:") + return true; + else if (url.indexOf("firebug-service.js") != -1) + return true; + else + return false; +}; + +this.isSystemPage = function(win) +{ + try + { + var doc = win.document; + if (!doc) + return false; + + // Detect pages for pretty printed XML + if ((doc.styleSheets.length && doc.styleSheets[0].href + == "chrome://global/content/xml/XMLPrettyPrint.css") + || (doc.styleSheets.length > 1 && doc.styleSheets[1].href + == "chrome://browser/skin/feeds/subscribe.css")) + return true; + + return FBL.isSystemURL(win.location.href); + } + catch (exc) + { + // Sometimes documents just aren't ready to be manipulated here, but don't let that + // gum up the works + ERROR("tabWatcher.isSystemPage document not ready:"+ exc); + return false; + } +}; + +this.isSystemStyleSheet = function(sheet) +{ + var href = sheet && sheet.href; + return href && FBL.isSystemURL(href); +}; + +this.getURIHost = function(uri) +{ + try + { + if (uri) + return uri.host; + else + return ""; + } + catch (exc) + { + return ""; + } +}; + +this.isLocalURL = function(url) +{ + if (url.substr(0, 5) == "file:") + return true; + else if (url.substr(0, 8) == "wyciwyg:") + return true; + else + return false; +}; + +this.isDataURL = function(url) +{ + return (url && url.substr(0,5) == "data:"); +}; + +this.getLocalPath = function(url) +{ + if (this.isLocalURL(url)) + { + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var file = fileHandler.getFileFromURLSpec(url); + return file.path; + } +}; + +this.getURLFromLocalFile = function(file) +{ + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var URL = fileHandler.getURLSpecFromFile(file); + return URL; +}; + +this.getDataURLForContent = function(content, url) +{ + // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10, + var uri = "data:text/html;"; + uri += "fileName="+encodeURIComponent(url)+ ","; + uri += encodeURIComponent(content); + return uri; +}, + +this.getDomain = function(url) +{ + var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url); + return m ? m[1] : ""; +}; + +this.getURLPath = function(url) +{ + var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); + return m ? m[1] : ""; +}; + +this.getPrettyDomain = function(url) +{ + var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); + return m ? m[2] : ""; +}; + +this.absoluteURL = function(url, baseURL) +{ + return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g"); +}; + +this.absoluteURLWithDots = function(url, baseURL) +{ + if (url[0] == "?") + return baseURL + url; + + var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/; + var m = reURL.exec(url); + if (m) + return url; + + var m = reURL.exec(baseURL); + if (!m) + return ""; + + var head = m[1]; + var tail = m[3]; + if (url.substr(0, 2) == "//") + return m[2] + url; + else if (url[0] == "/") + { + return head + url; + } + else if (tail[tail.length-1] == "/") + return baseURL + url; + else + { + var parts = tail.split("/"); + return head + parts.slice(0, parts.length-1).join("/") + "/" + url; + } +}; + +this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome +{ + if (!url) + return ""; + // Replace one or more characters that are not forward-slash followed by /.., by space. + if (url.length < 255) // guard against monsters. + { + // Replace one or more characters that are not forward-slash followed by /.., by space. + url = url.replace(/[^\/]+\/\.\.\//, "", "g"); + // Issue 1496, avoid # + url = url.replace(/#.*/,""); + // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they + // don't match up with the URLs we get back from the DOM + url = url.replace(/file:\/([^\/])/g, "file:///$1"); + if (url.indexOf('chrome:')==0) + { + var m = reChromeCase.exec(url); // 1 is package name, 2 is path + if (m) + { + url = "chrome://"+m[1].toLowerCase()+"/"+m[2]; + } + } + } + return url; +}; + +this.denormalizeURL = function(url) +{ + return url.replace(/file:\/\/\//g, "file:/"); +}; + +this.parseURLParams = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedText(search); +}; + +this.parseURLEncodedText = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: ""}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +// TODO: xxxpedro lib. why loops in domplate are requiring array in parameters +// as in response/request headers and get/post parameters in Net module? +this.parseURLParamsArray = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedTextArray(search); +}; + +this.parseURLEncodedTextArray = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: [""]}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +this.reEncodeURL = function(file, text) +{ + var lines = text.split("\n"); + var params = this.parseURLEncodedText(lines[lines.length-1]); + + var args = []; + for (var i = 0; i < params.length; ++i) + args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); + + var url = file.href; + url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); + + return url; +}; + +this.getResource = function(aURL) +{ + try + { + var channel=ioService.newChannel(aURL,null,null); + var input=channel.open(); + return FBL.readFromStream(input); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getResource FAILS for "+aURL, e); + } +}; + +this.parseJSONString = function(jsonString, originURL) +{ + // See if this is a Prototype style *-secure request. + var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/); + var matches = regex.exec(jsonString); + + if (matches) + { + jsonString = matches[1]; + + if (jsonString[0] == "\\" && jsonString[1] == "n") + jsonString = jsonString.substr(2); + + if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") + jsonString = jsonString.substr(0, jsonString.length-2); + } + + if (jsonString.indexOf("&&&START&&&")) + { + regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); + matches = regex.exec(jsonString); + if (matches) + jsonString = matches[1]; + } + + // throw on the extra parentheses + jsonString = "(" + jsonString + ")"; + + ///var s = Components.utils.Sandbox(originURL); + var jsonObject = null; + + try + { + ///jsonObject = Components.utils.evalInSandbox(jsonString, s); + + //jsonObject = Firebug.context.eval(jsonString); + jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;}); + } + catch(e) + { + /*** + if (e.message.indexOf("is not defined")) + { + var parts = e.message.split(" "); + s[parts[0]] = function(str){ return str; }; + try { + jsonObject = Components.utils.evalInSandbox(jsonString, s); + } catch(ex) { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + } + } + else + {/**/ + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + ///} + } + + return jsonObject; +}; + +// ************************************************************************************************ + +this.objectToString = function(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +// Input Caret Position + +this.setSelectionRange = function(input, start, length) +{ + if (input.createTextRange) + { + var range = input.createTextRange(); + range.moveStart("character", start); + range.moveEnd("character", length - input.value.length); + range.select(); + } + else if (input.setSelectionRange) + { + input.setSelectionRange(start, length); + input.focus(); + } +}; + +// ************************************************************************************************ +// Input Selection Start / Caret Position + +this.getInputSelectionStart = function(input) +{ + if (document.selection) + { + var range = input.ownerDocument.selection.createRange(); + var text = range.text; + + //console.log("range", range.text); + + // if there is a selection, find the start position + if (text) + { + return input.value.indexOf(text); + } + // if there is no selection, find the caret position + else + { + range.moveStart("character", -input.value.length); + + return range.text.length; + } + } + else if (typeof input.selectionStart != "undefined") + return input.selectionStart; + + return 0; +}; + +// ************************************************************************************************ +// Opera Tab Fix + +function onOperaTabBlur(e) +{ + if (this.lastKey == 9) + this.focus(); +}; + +function onOperaTabKeyDown(e) +{ + this.lastKey = e.keyCode; +}; + +function onOperaTabFocus(e) +{ + this.lastKey = null; +}; + +this.fixOperaTabKey = function(el) +{ + el.onfocus = onOperaTabFocus; + el.onblur = onOperaTabBlur; + el.onkeydown = onOperaTabKeyDown; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.Property = function(object, name) +{ + this.object = object; + this.name = name; + + this.getObject = function() + { + return object[name]; + }; +}; + +this.ErrorCopy = function(message) +{ + this.message = message; +}; + +function EventCopy(event) +{ + // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to + // represent them long term in the inspector. + for (var name in event) + { + try { + this[name] = event[name]; + } catch (exc) { } + } +} + +this.EventCopy = EventCopy; + + +// ************************************************************************************************ +// Type Checking + +var toString = Object.prototype.toString; +var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; + +this.isArray = function(object) { + return toString.call(object) === '[object Array]'; +}; + +this.isFunction = function(object) { + if (!object) return false; + + return toString.call(object) === "[object Function]" || + this.isIE && typeof object != "string" && reFunction.test(""+object); +}; + + +// ************************************************************************************************ +// Instance Checking + +this.instanceOf = function(object, className) +{ + if (!object || typeof object != "object") + return false; + + // Try to use the native instanceof operator. We can only use it when we know + // exactly the window where the object is located at + if (object.ownerDocument) + { + // find the correct window of the object + var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow; + + // if the class is accessible in the window, uses the native instanceof operator + // if the instanceof evaluates to "true" we can assume it is a instance, but if it + // evaluates to "false" we must continue with the duck type detection below because + // the native object may be extended, thus breaking the instanceof result + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (className in win && object instanceof win[className]) + return true; + } + // If the object doesn't have the ownerDocument property, we'll try to look at + // the current context's window + else + { + // TODO: xxxpedro context + // Since we're not using yet a Firebug.context, we'll just use the top window + // (browser) as a reference + var win = Firebug.browser.window; + if (className in win) + return object instanceof win[className]; + } + + // get the duck type model from the cache + var cache = instanceCheckMap[className]; + if (!cache) + return false; + + // starts the hacky duck type detection + for(var n in cache) + { + var obj = cache[n]; + var type = typeof obj; + obj = type == "object" ? obj : [obj]; + + for(var name in obj) + { + // avoid problems with extended native objects + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (!obj.hasOwnProperty(name)) + continue; + + var value = obj[name]; + + if( n == "property" && !(value in object) || + n == "method" && !this.isFunction(object[value]) || + n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) + return false; + } + } + + return true; +}; + +var instanceCheckMap = +{ + // DuckTypeCheck: + // { + // property: ["window", "document"], + // method: "setTimeout", + // value: {nodeType: 1} + // }, + + Window: + { + property: ["window", "document"], + method: "setTimeout" + }, + + Document: + { + property: ["body", "cookie"], + method: "getElementById" + }, + + Node: + { + property: "ownerDocument", + method: "appendChild" + }, + + Element: + { + property: "tagName", + value: {nodeType: 1} + }, + + Location: + { + property: ["hostname", "protocol"], + method: "assign" + }, + + HTMLImageElement: + { + property: "useMap", + value: + { + nodeType: 1, + tagName: "img" + } + }, + + HTMLAnchorElement: + { + property: "hreflang", + value: + { + nodeType: 1, + tagName: "a" + } + }, + + HTMLInputElement: + { + property: "form", + value: + { + nodeType: 1, + tagName: "input" + } + }, + + HTMLButtonElement: + { + // ? + }, + + HTMLFormElement: + { + method: "submit", + value: + { + nodeType: 1, + tagName: "form" + } + }, + + HTMLBodyElement: + { + + }, + + HTMLHtmlElement: + { + + }, + + CSSStyleRule: + { + property: ["selectorText", "style"] + } + +}; + + +// ************************************************************************************************ +// DOM Constants + +/* + +Problems: + + - IE does not have window.Node, window.Element, etc + - for (var name in Node.prototype) return nothing on FF + +*/ + + +var domMemberMap2 = {}; + +var domMemberMap2Sandbox = null; + +var getDomMemberMap2 = function(name) +{ + if (!domMemberMap2Sandbox) + { + var doc = Firebug.chrome.document; + var frame = doc.createElement("iframe"); + + frame.id = "FirebugSandbox"; + frame.style.display = "none"; + frame.src = "about:blank"; + + doc.body.appendChild(frame); + + domMemberMap2Sandbox = frame.window || frame.contentWindow; + } + + var props = []; + + //var object = domMemberMap2Sandbox[name]; + //object = object.prototype || object; + + var object = null; + + if (name == "Window") + object = domMemberMap2Sandbox.window; + + else if (name == "Document") + object = domMemberMap2Sandbox.document; + + else if (name == "HTMLScriptElement") + object = domMemberMap2Sandbox.document.createElement("script"); + + else if (name == "HTMLAnchorElement") + object = domMemberMap2Sandbox.document.createElement("a"); + + else if (name.indexOf("Element") != -1) + { + object = domMemberMap2Sandbox.document.createElement("div"); + } + + if (object) + { + //object = object.prototype || object; + + //props = 'addEventListener,document,location,navigator,window'.split(','); + + for (var n in object) + props.push(n); + } + /**/ + + return props; + return extendArray(props, domMemberMap[name]); +}; + +// xxxpedro experimental get DOM members +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + FBL.domMemberCache = domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = getDomMemberMap2(name); + var cache = domMemberCache[name] = {}; + + /* + if (name.indexOf("Element") != -1) + { + this.append(cache, this.getDOMMembers("Node")); + this.append(cache, this.getDOMMembers("Element")); + } + /**/ + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument")) + { return domMemberCache.Document; } + else if (this.instanceOf(object, "Location")) + { return domMemberCache.Location; } + else if (this.instanceOf(object, "HTMLImageElement")) + { return domMemberCache.HTMLImageElement; } + else if (this.instanceOf(object, "HTMLAnchorElement")) + { return domMemberCache.HTMLAnchorElement; } + else if (this.instanceOf(object, "HTMLInputElement")) + { return domMemberCache.HTMLInputElement; } + else if (this.instanceOf(object, "HTMLButtonElement")) + { return domMemberCache.HTMLButtonElement; } + else if (this.instanceOf(object, "HTMLFormElement")) + { return domMemberCache.HTMLFormElement; } + else if (this.instanceOf(object, "HTMLBodyElement")) + { return domMemberCache.HTMLBodyElement; } + else if (this.instanceOf(object, "HTMLHtmlElement")) + { return domMemberCache.HTMLHtmlElement; } + else if (this.instanceOf(object, "HTMLScriptElement")) + { return domMemberCache.HTMLScriptElement; } + else if (this.instanceOf(object, "HTMLTableElement")) + { return domMemberCache.HTMLTableElement; } + else if (this.instanceOf(object, "HTMLTableRowElement")) + { return domMemberCache.HTMLTableRowElement; } + else if (this.instanceOf(object, "HTMLTableCellElement")) + { return domMemberCache.HTMLTableCellElement; } + else if (this.instanceOf(object, "HTMLIFrameElement")) + { return domMemberCache.HTMLIFrameElement; } + else if (this.instanceOf(object, "SVGSVGElement")) + { return domMemberCache.SVGSVGElement; } + else if (this.instanceOf(object, "SVGElement")) + { return domMemberCache.SVGElement; } + else if (this.instanceOf(object, "Element")) + { return domMemberCache.Element; } + else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection")) + { return domMemberCache.Text; } + else if (this.instanceOf(object, "Attr")) + { return domMemberCache.Attr; } + else if (this.instanceOf(object, "Node")) + { return domMemberCache.Node; } + else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy")) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getDOMMembers FAILED ", E); + + return {}; + } +}; + + +/* +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = domMemberMap[name]; + var cache = domMemberCache[name] = {}; + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (object instanceof Document || object instanceof XMLDocument) + { return domMemberCache.Document; } + else if (object instanceof Location) + { return domMemberCache.Location; } + else if (object instanceof HTMLImageElement) + { return domMemberCache.HTMLImageElement; } + else if (object instanceof HTMLAnchorElement) + { return domMemberCache.HTMLAnchorElement; } + else if (object instanceof HTMLInputElement) + { return domMemberCache.HTMLInputElement; } + else if (object instanceof HTMLButtonElement) + { return domMemberCache.HTMLButtonElement; } + else if (object instanceof HTMLFormElement) + { return domMemberCache.HTMLFormElement; } + else if (object instanceof HTMLBodyElement) + { return domMemberCache.HTMLBodyElement; } + else if (object instanceof HTMLHtmlElement) + { return domMemberCache.HTMLHtmlElement; } + else if (object instanceof HTMLScriptElement) + { return domMemberCache.HTMLScriptElement; } + else if (object instanceof HTMLTableElement) + { return domMemberCache.HTMLTableElement; } + else if (object instanceof HTMLTableRowElement) + { return domMemberCache.HTMLTableRowElement; } + else if (object instanceof HTMLTableCellElement) + { return domMemberCache.HTMLTableCellElement; } + else if (object instanceof HTMLIFrameElement) + { return domMemberCache.HTMLIFrameElement; } + else if (object instanceof SVGSVGElement) + { return domMemberCache.SVGSVGElement; } + else if (object instanceof SVGElement) + { return domMemberCache.SVGElement; } + else if (object instanceof Element) + { return domMemberCache.Element; } + else if (object instanceof Text || object instanceof CDATASection) + { return domMemberCache.Text; } + else if (object instanceof Attr) + { return domMemberCache.Attr; } + else if (object instanceof Node) + { return domMemberCache.Node; } + else if (object instanceof Event || object instanceof EventCopy) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + return {}; + } +}; +/**/ + +this.isDOMMember = function(object, propName) +{ + var members = this.getDOMMembers(object); + return members && propName in members; +}; + +var domMemberCache = null; +var domMemberMap = {}; + +domMemberMap.Window = +[ + "document", + "frameElement", + + "innerWidth", + "innerHeight", + "outerWidth", + "outerHeight", + "screenX", + "screenY", + "pageXOffset", + "pageYOffset", + "scrollX", + "scrollY", + "scrollMaxX", + "scrollMaxY", + + "status", + "defaultStatus", + + "parent", + "opener", + "top", + "window", + "content", + "self", + + "location", + "history", + "frames", + "navigator", + "screen", + "menubar", + "toolbar", + "locationbar", + "personalbar", + "statusbar", + "directories", + "scrollbars", + "fullScreen", + "netscape", + "java", + "console", + "Components", + "controllers", + "closed", + "crypto", + "pkcs11", + + "name", + "property", + "length", + + "sessionStorage", + "globalStorage", + + "setTimeout", + "setInterval", + "clearTimeout", + "clearInterval", + "addEventListener", + "removeEventListener", + "dispatchEvent", + "getComputedStyle", + "captureEvents", + "releaseEvents", + "routeEvent", + "enableExternalCapture", + "disableExternalCapture", + "moveTo", + "moveBy", + "resizeTo", + "resizeBy", + "scroll", + "scrollTo", + "scrollBy", + "scrollByLines", + "scrollByPages", + "sizeToContent", + "setResizable", + "getSelection", + "open", + "openDialog", + "close", + "alert", + "confirm", + "prompt", + "dump", + "focus", + "blur", + "find", + "back", + "forward", + "home", + "stop", + "print", + "atob", + "btoa", + "updateCommands", + "XPCNativeWrapper", + "GeckoActiveXObject", + "applicationCache" // FF3 +]; + +domMemberMap.Location = +[ + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + + "assign", + "reload", + "replace" +]; + +domMemberMap.Node = +[ + "id", + "className", + + "nodeType", + "tagName", + "nodeName", + "localName", + "prefix", + "namespaceURI", + "nodeValue", + + "ownerDocument", + "parentNode", + "offsetParent", + "nextSibling", + "previousSibling", + "firstChild", + "lastChild", + "childNodes", + "attributes", + + "dir", + "baseURI", + "textContent", + "innerHTML", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]; + +domMemberMap.Document = extendArray(domMemberMap.Node, +[ + "documentElement", + "body", + "title", + "location", + "referrer", + "cookie", + "contentType", + "lastModified", + "characterSet", + "inputEncoding", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "strictErrorChecking", + "documentURI", + "URL", + + "defaultView", + "doctype", + "implementation", + "styleSheets", + "images", + "links", + "forms", + "anchors", + "embeds", + "plugins", + "applets", + + "width", + "height", + + "designMode", + "compatMode", + "async", + "preferredStylesheetSet", + + "alinkColor", + "linkColor", + "vlinkColor", + "bgColor", + "fgColor", + "domain", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "captureEvents", + "releaseEvents", + "routeEvent", + "clear", + "open", + "close", + "execCommand", + "execCommandShowHelp", + "getElementsByName", + "getSelection", + "queryCommandEnabled", + "queryCommandIndeterm", + "queryCommandState", + "queryCommandSupported", + "queryCommandText", + "queryCommandValue", + "write", + "writeln", + "adoptNode", + "appendChild", + "removeChild", + "renameNode", + "cloneNode", + "compareDocumentPosition", + "createAttribute", + "createAttributeNS", + "createCDATASection", + "createComment", + "createDocumentFragment", + "createElement", + "createElementNS", + "createEntityReference", + "createEvent", + "createExpression", + "createNSResolver", + "createNodeIterator", + "createProcessingInstruction", + "createRange", + "createTextNode", + "createTreeWalker", + "domConfig", + "evaluate", + "evaluateFIXptr", + "evaluateXPointer", + "getAnonymousElementByAttribute", + "getAnonymousNodes", + "addBinding", + "removeBinding", + "getBindingParent", + "getBoxObjectFor", + "setBoxObjectFor", + "getElementById", + "getElementsByTagName", + "getElementsByTagNameNS", + "hasAttributes", + "hasChildNodes", + "importNode", + "insertBefore", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "load", + "loadBindingDocument", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "normalizeDocument", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.Element = extendArray(domMemberMap.Node, +[ + "clientWidth", + "clientHeight", + "offsetLeft", + "offsetTop", + "offsetWidth", + "offsetHeight", + "scrollLeft", + "scrollTop", + "scrollWidth", + "scrollHeight", + + "style", + + "tabIndex", + "title", + "lang", + "align", + "spellcheck", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "focus", + "blur", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "getElementsByTagName", + "getElementsByTagNameNS", + "getAttribute", + "getAttributeNS", + "getAttributeNode", + "getAttributeNodeNS", + "setAttribute", + "setAttributeNS", + "setAttributeNode", + "setAttributeNodeNS", + "removeAttribute", + "removeAttributeNS", + "removeAttributeNode", + "hasAttribute", + "hasAttributeNS", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.SVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + "href", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getPresentationAttribute", + "preserveAspectRatio" +]); + +domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + + "viewBox", + "viewport", + "currentView", + "useCurrentView", + "pixelUnitToMillimeterX", + "pixelUnitToMillimeterY", + "screenPixelToMillimeterX", + "screenPixelToMillimeterY", + "currentScale", + "currentTranslate", + "zoomAndPan", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + "contentScriptType", + "contentStyleType", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getEnclosureList", + "getIntersectionList", + "getViewboxToViewportTransform", + "getPresentationAttribute", + "getElementById", + "checkEnclosure", + "checkIntersection", + "createSVGAngle", + "createSVGLength", + "createSVGMatrix", + "createSVGNumber", + "createSVGPoint", + "createSVGRect", + "createSVGString", + "createSVGTransform", + "createSVGTransformFromMatrix", + "deSelectAll", + "preserveAspectRatio", + "forceRedraw", + "suspendRedraw", + "unsuspendRedraw", + "unsuspendRedrawAll", + "getCurrentTime", + "setCurrentTime", + "animationsPaused", + "pauseAnimations", + "unpauseAnimations" +]); + +domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element, +[ + "src", + "naturalWidth", + "naturalHeight", + "width", + "height", + "x", + "y", + "name", + "alt", + "longDesc", + "lowsrc", + "border", + "complete", + "hspace", + "vspace", + "isMap", + "useMap" +]); + +domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element, +[ + "name", + "target", + "accessKey", + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + "hreflang", + "coords", + "shape", + "text", + "type", + "rel", + "rev", + "charset" +]); + +domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element, +[ + "contentDocument", + "contentWindow", + "frameBorder", + "height", + "longDesc", + "marginHeight", + "marginWidth", + "name", + "scrolling", + "src", + "width" +]); + +domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "border", + "caption", + "cellPadding", + "cellSpacing", + "frame", + "rows", + "rules", + "summary", + "tBodies", + "tFoot", + "tHead", + "width", + + "createCaption", + "createTFoot", + "createTHead", + "deleteCaption", + "deleteRow", + "deleteTFoot", + "deleteTHead", + "insertRow" +]); + +domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "cells", + "ch", + "chOff", + "rowIndex", + "sectionRowIndex", + "vAlign", + + "deleteCell", + "insertCell" +]); + +domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element, +[ + "abbr", + "axis", + "bgColor", + "cellIndex", + "ch", + "chOff", + "colSpan", + "headers", + "height", + "noWrap", + "rowSpan", + "scope", + "vAlign", + "width" + +]); + +domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element, +[ + "src" +]); + +domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element, +[ + "accessKey", + "disabled", + "form", + "name", + "type", + "value", + + "click" +]); + +domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element, +[ + "type", + "value", + "checked", + "accept", + "accessKey", + "alt", + "controllers", + "defaultChecked", + "defaultValue", + "disabled", + "form", + "maxLength", + "name", + "readOnly", + "selectionEnd", + "selectionStart", + "size", + "src", + "textLength", + "useMap", + + "click", + "select", + "setSelectionRange" +]); + +domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element, +[ + "acceptCharset", + "action", + "author", + "elements", + "encoding", + "enctype", + "entry_id", + "length", + "method", + "name", + "post", + "target", + "text", + "url", + + "reset", + "submit" +]); + +domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element, +[ + "aLink", + "background", + "bgColor", + "link", + "text", + "vLink" +]); + +domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element, +[ + "version" +]); + +domMemberMap.Text = extendArray(domMemberMap.Node, +[ + "data", + "length", + + "appendData", + "deleteData", + "insertData", + "replaceData", + "splitText", + "substringData" +]); + +domMemberMap.Attr = extendArray(domMemberMap.Node, +[ + "name", + "value", + "specified", + "ownerElement" +]); + +domMemberMap.Event = +[ + "type", + "target", + "currentTarget", + "originalTarget", + "explicitOriginalTarget", + "relatedTarget", + "rangeParent", + "rangeOffset", + "view", + + "keyCode", + "charCode", + "screenX", + "screenY", + "clientX", + "clientY", + "layerX", + "layerY", + "pageX", + "pageY", + + "detail", + "button", + "which", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + + "eventPhase", + "timeStamp", + "bubbles", + "cancelable", + "cancelBubble", + + "isTrusted", + "isChar", + + "getPreventDefault", + "initEvent", + "initMouseEvent", + "initKeyEvent", + "initUIEvent", + "preventBubble", + "preventCapture", + "preventDefault", + "stopPropagation" +]; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.domConstantMap = +{ + "ELEMENT_NODE": 1, + "ATTRIBUTE_NODE": 1, + "TEXT_NODE": 1, + "CDATA_SECTION_NODE": 1, + "ENTITY_REFERENCE_NODE": 1, + "ENTITY_NODE": 1, + "PROCESSING_INSTRUCTION_NODE": 1, + "COMMENT_NODE": 1, + "DOCUMENT_NODE": 1, + "DOCUMENT_TYPE_NODE": 1, + "DOCUMENT_FRAGMENT_NODE": 1, + "NOTATION_NODE": 1, + + "DOCUMENT_POSITION_DISCONNECTED": 1, + "DOCUMENT_POSITION_PRECEDING": 1, + "DOCUMENT_POSITION_FOLLOWING": 1, + "DOCUMENT_POSITION_CONTAINS": 1, + "DOCUMENT_POSITION_CONTAINED_BY": 1, + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1, + + "UNKNOWN_RULE": 1, + "STYLE_RULE": 1, + "CHARSET_RULE": 1, + "IMPORT_RULE": 1, + "MEDIA_RULE": 1, + "FONT_FACE_RULE": 1, + "PAGE_RULE": 1, + + "CAPTURING_PHASE": 1, + "AT_TARGET": 1, + "BUBBLING_PHASE": 1, + + "SCROLL_PAGE_UP": 1, + "SCROLL_PAGE_DOWN": 1, + + "MOUSEUP": 1, + "MOUSEDOWN": 1, + "MOUSEOVER": 1, + "MOUSEOUT": 1, + "MOUSEMOVE": 1, + "MOUSEDRAG": 1, + "CLICK": 1, + "DBLCLICK": 1, + "KEYDOWN": 1, + "KEYUP": 1, + "KEYPRESS": 1, + "DRAGDROP": 1, + "FOCUS": 1, + "BLUR": 1, + "SELECT": 1, + "CHANGE": 1, + "RESET": 1, + "SUBMIT": 1, + "SCROLL": 1, + "LOAD": 1, + "UNLOAD": 1, + "XFER_DONE": 1, + "ABORT": 1, + "ERROR": 1, + "LOCATE": 1, + "MOVE": 1, + "RESIZE": 1, + "FORWARD": 1, + "HELP": 1, + "BACK": 1, + "TEXT": 1, + + "ALT_MASK": 1, + "CONTROL_MASK": 1, + "SHIFT_MASK": 1, + "META_MASK": 1, + + "DOM_VK_TAB": 1, + "DOM_VK_PAGE_UP": 1, + "DOM_VK_PAGE_DOWN": 1, + "DOM_VK_UP": 1, + "DOM_VK_DOWN": 1, + "DOM_VK_LEFT": 1, + "DOM_VK_RIGHT": 1, + "DOM_VK_CANCEL": 1, + "DOM_VK_HELP": 1, + "DOM_VK_BACK_SPACE": 1, + "DOM_VK_CLEAR": 1, + "DOM_VK_RETURN": 1, + "DOM_VK_ENTER": 1, + "DOM_VK_SHIFT": 1, + "DOM_VK_CONTROL": 1, + "DOM_VK_ALT": 1, + "DOM_VK_PAUSE": 1, + "DOM_VK_CAPS_LOCK": 1, + "DOM_VK_ESCAPE": 1, + "DOM_VK_SPACE": 1, + "DOM_VK_END": 1, + "DOM_VK_HOME": 1, + "DOM_VK_PRINTSCREEN": 1, + "DOM_VK_INSERT": 1, + "DOM_VK_DELETE": 1, + "DOM_VK_0": 1, + "DOM_VK_1": 1, + "DOM_VK_2": 1, + "DOM_VK_3": 1, + "DOM_VK_4": 1, + "DOM_VK_5": 1, + "DOM_VK_6": 1, + "DOM_VK_7": 1, + "DOM_VK_8": 1, + "DOM_VK_9": 1, + "DOM_VK_SEMICOLON": 1, + "DOM_VK_EQUALS": 1, + "DOM_VK_A": 1, + "DOM_VK_B": 1, + "DOM_VK_C": 1, + "DOM_VK_D": 1, + "DOM_VK_E": 1, + "DOM_VK_F": 1, + "DOM_VK_G": 1, + "DOM_VK_H": 1, + "DOM_VK_I": 1, + "DOM_VK_J": 1, + "DOM_VK_K": 1, + "DOM_VK_L": 1, + "DOM_VK_M": 1, + "DOM_VK_N": 1, + "DOM_VK_O": 1, + "DOM_VK_P": 1, + "DOM_VK_Q": 1, + "DOM_VK_R": 1, + "DOM_VK_S": 1, + "DOM_VK_T": 1, + "DOM_VK_U": 1, + "DOM_VK_V": 1, + "DOM_VK_W": 1, + "DOM_VK_X": 1, + "DOM_VK_Y": 1, + "DOM_VK_Z": 1, + "DOM_VK_CONTEXT_MENU": 1, + "DOM_VK_NUMPAD0": 1, + "DOM_VK_NUMPAD1": 1, + "DOM_VK_NUMPAD2": 1, + "DOM_VK_NUMPAD3": 1, + "DOM_VK_NUMPAD4": 1, + "DOM_VK_NUMPAD5": 1, + "DOM_VK_NUMPAD6": 1, + "DOM_VK_NUMPAD7": 1, + "DOM_VK_NUMPAD8": 1, + "DOM_VK_NUMPAD9": 1, + "DOM_VK_MULTIPLY": 1, + "DOM_VK_ADD": 1, + "DOM_VK_SEPARATOR": 1, + "DOM_VK_SUBTRACT": 1, + "DOM_VK_DECIMAL": 1, + "DOM_VK_DIVIDE": 1, + "DOM_VK_F1": 1, + "DOM_VK_F2": 1, + "DOM_VK_F3": 1, + "DOM_VK_F4": 1, + "DOM_VK_F5": 1, + "DOM_VK_F6": 1, + "DOM_VK_F7": 1, + "DOM_VK_F8": 1, + "DOM_VK_F9": 1, + "DOM_VK_F10": 1, + "DOM_VK_F11": 1, + "DOM_VK_F12": 1, + "DOM_VK_F13": 1, + "DOM_VK_F14": 1, + "DOM_VK_F15": 1, + "DOM_VK_F16": 1, + "DOM_VK_F17": 1, + "DOM_VK_F18": 1, + "DOM_VK_F19": 1, + "DOM_VK_F20": 1, + "DOM_VK_F21": 1, + "DOM_VK_F22": 1, + "DOM_VK_F23": 1, + "DOM_VK_F24": 1, + "DOM_VK_NUM_LOCK": 1, + "DOM_VK_SCROLL_LOCK": 1, + "DOM_VK_COMMA": 1, + "DOM_VK_PERIOD": 1, + "DOM_VK_SLASH": 1, + "DOM_VK_BACK_QUOTE": 1, + "DOM_VK_OPEN_BRACKET": 1, + "DOM_VK_BACK_SLASH": 1, + "DOM_VK_CLOSE_BRACKET": 1, + "DOM_VK_QUOTE": 1, + "DOM_VK_META": 1, + + "SVG_ZOOMANDPAN_DISABLE": 1, + "SVG_ZOOMANDPAN_MAGNIFY": 1, + "SVG_ZOOMANDPAN_UNKNOWN": 1 +}; + +this.cssInfo = +{ + "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"], + "background-attachment": ["bgAttachment"], + "background-color": ["color", "systemColor"], + "background-image": ["none"], + "background-position": ["bgPosition"], + "background-repeat": ["bgRepeat"], + + "border": ["borderStyle", "thickness", "color", "systemColor", "none"], + "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-collapse": ["borderCollapse"], + "border-color": ["color", "systemColor"], + "border-top-color": ["color", "systemColor"], + "border-right-color": ["color", "systemColor"], + "border-bottom-color": ["color", "systemColor"], + "border-left-color": ["color", "systemColor"], + "border-spacing": [], + "border-style": ["borderStyle"], + "border-top-style": ["borderStyle"], + "border-right-style": ["borderStyle"], + "border-bottom-style": ["borderStyle"], + "border-left-style": ["borderStyle"], + "border-width": ["thickness"], + "border-top-width": ["thickness"], + "border-right-width": ["thickness"], + "border-bottom-width": ["thickness"], + "border-left-width": ["thickness"], + + "bottom": ["auto"], + "caption-side": ["captionSide"], + "clear": ["clear", "none"], + "clip": ["auto"], + "color": ["color", "systemColor"], + "content": ["content"], + "counter-increment": ["none"], + "counter-reset": ["none"], + "cursor": ["cursor", "none"], + "direction": ["direction"], + "display": ["display", "none"], + "empty-cells": [], + "float": ["float", "none"], + "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"], + + "font-family": ["fontFamily"], + "font-size": ["fontSize"], + "font-size-adjust": [], + "font-stretch": [], + "font-style": ["fontStyle"], + "font-variant": ["fontVariant"], + "font-weight": ["fontWeight"], + + "height": ["auto"], + "left": ["auto"], + "letter-spacing": [], + "line-height": [], + + "list-style": ["listStyleType", "listStylePosition", "none"], + "list-style-image": ["none"], + "list-style-position": ["listStylePosition"], + "list-style-type": ["listStyleType", "none"], + + "margin": [], + "margin-top": [], + "margin-right": [], + "margin-bottom": [], + "margin-left": [], + + "marker-offset": ["auto"], + "min-height": ["none"], + "max-height": ["none"], + "min-width": ["none"], + "max-width": ["none"], + + "outline": ["borderStyle", "color", "systemColor", "none"], + "outline-color": ["color", "systemColor"], + "outline-style": ["borderStyle"], + "outline-width": [], + + "overflow": ["overflow", "auto"], + "overflow-x": ["overflow", "auto"], + "overflow-y": ["overflow", "auto"], + + "padding": [], + "padding-top": [], + "padding-right": [], + "padding-bottom": [], + "padding-left": [], + + "position": ["position"], + "quotes": ["none"], + "right": ["auto"], + "table-layout": ["tableLayout", "auto"], + "text-align": ["textAlign"], + "text-decoration": ["textDecoration", "none"], + "text-indent": [], + "text-shadow": [], + "text-transform": ["textTransform", "none"], + "top": ["auto"], + "unicode-bidi": [], + "vertical-align": ["verticalAlign"], + "white-space": ["whiteSpace"], + "width": ["auto"], + "word-spacing": [], + "z-index": [], + + "-moz-appearance": ["mozAppearance"], + "-moz-border-radius": [], + "-moz-border-radius-bottomleft": [], + "-moz-border-radius-bottomright": [], + "-moz-border-radius-topleft": [], + "-moz-border-radius-topright": [], + "-moz-border-top-colors": ["color", "systemColor"], + "-moz-border-right-colors": ["color", "systemColor"], + "-moz-border-bottom-colors": ["color", "systemColor"], + "-moz-border-left-colors": ["color", "systemColor"], + "-moz-box-align": ["mozBoxAlign"], + "-moz-box-direction": ["mozBoxDirection"], + "-moz-box-flex": [], + "-moz-box-ordinal-group": [], + "-moz-box-orient": ["mozBoxOrient"], + "-moz-box-pack": ["mozBoxPack"], + "-moz-box-sizing": ["mozBoxSizing"], + "-moz-opacity": [], + "-moz-user-focus": ["userFocus", "none"], + "-moz-user-input": ["userInput"], + "-moz-user-modify": [], + "-moz-user-select": ["userSelect", "none"], + "-moz-background-clip": [], + "-moz-background-inline-policy": [], + "-moz-background-origin": [], + "-moz-binding": [], + "-moz-column-count": [], + "-moz-column-gap": [], + "-moz-column-width": [], + "-moz-image-region": [] +}; + +this.inheritedStyleNames = +{ + "border-collapse": 1, + "border-spacing": 1, + "border-style": 1, + "caption-side": 1, + "color": 1, + "cursor": 1, + "direction": 1, + "empty-cells": 1, + "font": 1, + "font-family": 1, + "font-size-adjust": 1, + "font-size": 1, + "font-style": 1, + "font-variant": 1, + "font-weight": 1, + "letter-spacing": 1, + "line-height": 1, + "list-style": 1, + "list-style-image": 1, + "list-style-position": 1, + "list-style-type": 1, + "quotes": 1, + "text-align": 1, + "text-decoration": 1, + "text-indent": 1, + "text-shadow": 1, + "text-transform": 1, + "white-space": 1, + "word-spacing": 1 +}; + +this.cssKeywords = +{ + "appearance": + [ + "button", + "button-small", + "checkbox", + "checkbox-container", + "checkbox-small", + "dialog", + "listbox", + "menuitem", + "menulist", + "menulist-button", + "menulist-textfield", + "menupopup", + "progressbar", + "radio", + "radio-container", + "radio-small", + "resizer", + "scrollbar", + "scrollbarbutton-down", + "scrollbarbutton-left", + "scrollbarbutton-right", + "scrollbarbutton-up", + "scrollbartrack-horizontal", + "scrollbartrack-vertical", + "separator", + "statusbar", + "tab", + "tab-left-edge", + "tabpanels", + "textfield", + "toolbar", + "toolbarbutton", + "toolbox", + "tooltip", + "treeheadercell", + "treeheadersortarrow", + "treeitem", + "treetwisty", + "treetwistyopen", + "treeview", + "window" + ], + + "systemColor": + [ + "ActiveBorder", + "ActiveCaption", + "AppWorkspace", + "Background", + "ButtonFace", + "ButtonHighlight", + "ButtonShadow", + "ButtonText", + "CaptionText", + "GrayText", + "Highlight", + "HighlightText", + "InactiveBorder", + "InactiveCaption", + "InactiveCaptionText", + "InfoBackground", + "InfoText", + "Menu", + "MenuText", + "Scrollbar", + "ThreeDDarkShadow", + "ThreeDFace", + "ThreeDHighlight", + "ThreeDLightShadow", + "ThreeDShadow", + "Window", + "WindowFrame", + "WindowText", + "-moz-field", + "-moz-fieldtext", + "-moz-workspace", + "-moz-visitedhyperlinktext", + "-moz-use-text-color" + ], + + "color": + [ + "AliceBlue", + "AntiqueWhite", + "Aqua", + "Aquamarine", + "Azure", + "Beige", + "Bisque", + "Black", + "BlanchedAlmond", + "Blue", + "BlueViolet", + "Brown", + "BurlyWood", + "CadetBlue", + "Chartreuse", + "Chocolate", + "Coral", + "CornflowerBlue", + "Cornsilk", + "Crimson", + "Cyan", + "DarkBlue", + "DarkCyan", + "DarkGoldenRod", + "DarkGray", + "DarkGreen", + "DarkKhaki", + "DarkMagenta", + "DarkOliveGreen", + "DarkOrange", + "DarkOrchid", + "DarkRed", + "DarkSalmon", + "DarkSeaGreen", + "DarkSlateBlue", + "DarkSlateGray", + "DarkTurquoise", + "DarkViolet", + "DeepPink", + "DarkSkyBlue", + "DimGray", + "DodgerBlue", + "Feldspar", + "FireBrick", + "FloralWhite", + "ForestGreen", + "Fuchsia", + "Gainsboro", + "GhostWhite", + "Gold", + "GoldenRod", + "Gray", + "Green", + "GreenYellow", + "HoneyDew", + "HotPink", + "IndianRed", + "Indigo", + "Ivory", + "Khaki", + "Lavender", + "LavenderBlush", + "LawnGreen", + "LemonChiffon", + "LightBlue", + "LightCoral", + "LightCyan", + "LightGoldenRodYellow", + "LightGrey", + "LightGreen", + "LightPink", + "LightSalmon", + "LightSeaGreen", + "LightSkyBlue", + "LightSlateBlue", + "LightSlateGray", + "LightSteelBlue", + "LightYellow", + "Lime", + "LimeGreen", + "Linen", + "Magenta", + "Maroon", + "MediumAquaMarine", + "MediumBlue", + "MediumOrchid", + "MediumPurple", + "MediumSeaGreen", + "MediumSlateBlue", + "MediumSpringGreen", + "MediumTurquoise", + "MediumVioletRed", + "MidnightBlue", + "MintCream", + "MistyRose", + "Moccasin", + "NavajoWhite", + "Navy", + "OldLace", + "Olive", + "OliveDrab", + "Orange", + "OrangeRed", + "Orchid", + "PaleGoldenRod", + "PaleGreen", + "PaleTurquoise", + "PaleVioletRed", + "PapayaWhip", + "PeachPuff", + "Peru", + "Pink", + "Plum", + "PowderBlue", + "Purple", + "Red", + "RosyBrown", + "RoyalBlue", + "SaddleBrown", + "Salmon", + "SandyBrown", + "SeaGreen", + "SeaShell", + "Sienna", + "Silver", + "SkyBlue", + "SlateBlue", + "SlateGray", + "Snow", + "SpringGreen", + "SteelBlue", + "Tan", + "Teal", + "Thistle", + "Tomato", + "Turquoise", + "Violet", + "VioletRed", + "Wheat", + "White", + "WhiteSmoke", + "Yellow", + "YellowGreen", + "transparent", + "invert" + ], + + "auto": + [ + "auto" + ], + + "none": + [ + "none" + ], + + "captionSide": + [ + "top", + "bottom", + "left", + "right" + ], + + "clear": + [ + "left", + "right", + "both" + ], + + "cursor": + [ + "auto", + "cell", + "context-menu", + "crosshair", + "default", + "help", + "pointer", + "progress", + "move", + "e-resize", + "all-scroll", + "ne-resize", + "nw-resize", + "n-resize", + "se-resize", + "sw-resize", + "s-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "text", + "vertical-text", + "wait", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "-moz-alias", + "-moz-cell", + "-moz-copy", + "-moz-grab", + "-moz-grabbing", + "-moz-contextmenu", + "-moz-zoom-in", + "-moz-zoom-out", + "-moz-spinning" + ], + + "direction": + [ + "ltr", + "rtl" + ], + + "bgAttachment": + [ + "scroll", + "fixed" + ], + + "bgPosition": + [ + "top", + "center", + "bottom", + "left", + "right" + ], + + "bgRepeat": + [ + "repeat", + "repeat-x", + "repeat-y", + "no-repeat" + ], + + "borderStyle": + [ + "hidden", + "dotted", + "dashed", + "solid", + "double", + "groove", + "ridge", + "inset", + "outset", + "-moz-bg-inset", + "-moz-bg-outset", + "-moz-bg-solid" + ], + + "borderCollapse": + [ + "collapse", + "separate" + ], + + "overflow": + [ + "visible", + "hidden", + "scroll", + "-moz-scrollbars-horizontal", + "-moz-scrollbars-none", + "-moz-scrollbars-vertical" + ], + + "listStyleType": + [ + "disc", + "circle", + "square", + "decimal", + "decimal-leading-zero", + "lower-roman", + "upper-roman", + "lower-greek", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "hebrew", + "armenian", + "georgian", + "cjk-ideographic", + "hiragana", + "katakana", + "hiragana-iroha", + "katakana-iroha", + "inherit" + ], + + "listStylePosition": + [ + "inside", + "outside" + ], + + "content": + [ + "open-quote", + "close-quote", + "no-open-quote", + "no-close-quote", + "inherit" + ], + + "fontStyle": + [ + "normal", + "italic", + "oblique", + "inherit" + ], + + "fontVariant": + [ + "normal", + "small-caps", + "inherit" + ], + + "fontWeight": + [ + "normal", + "bold", + "bolder", + "lighter", + "inherit" + ], + + "fontSize": + [ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger" + ], + + "fontFamily": + [ + "Arial", + "Comic Sans MS", + "Georgia", + "Tahoma", + "Verdana", + "Times New Roman", + "Trebuchet MS", + "Lucida Grande", + "Helvetica", + "serif", + "sans-serif", + "cursive", + "fantasy", + "monospace", + "caption", + "icon", + "menu", + "message-box", + "small-caption", + "status-bar", + "inherit" + ], + + "display": + [ + "block", + "inline", + "inline-block", + "list-item", + "marker", + "run-in", + "compact", + "table", + "inline-table", + "table-row-group", + "table-column", + "table-column-group", + "table-header-group", + "table-footer-group", + "table-row", + "table-cell", + "table-caption", + "-moz-box", + "-moz-compact", + "-moz-deck", + "-moz-grid", + "-moz-grid-group", + "-moz-grid-line", + "-moz-groupbox", + "-moz-inline-block", + "-moz-inline-box", + "-moz-inline-grid", + "-moz-inline-stack", + "-moz-inline-table", + "-moz-marker", + "-moz-popup", + "-moz-runin", + "-moz-stack" + ], + + "position": + [ + "static", + "relative", + "absolute", + "fixed", + "inherit" + ], + + "float": + [ + "left", + "right" + ], + + "textAlign": + [ + "left", + "right", + "center", + "justify" + ], + + "tableLayout": + [ + "fixed" + ], + + "textDecoration": + [ + "underline", + "overline", + "line-through", + "blink" + ], + + "textTransform": + [ + "capitalize", + "lowercase", + "uppercase", + "inherit" + ], + + "unicodeBidi": + [ + "normal", + "embed", + "bidi-override" + ], + + "whiteSpace": + [ + "normal", + "pre", + "nowrap" + ], + + "verticalAlign": + [ + "baseline", + "sub", + "super", + "top", + "text-top", + "middle", + "bottom", + "text-bottom", + "inherit" + ], + + "thickness": + [ + "thin", + "medium", + "thick" + ], + + "userFocus": + [ + "ignore", + "normal" + ], + + "userInput": + [ + "disabled", + "enabled" + ], + + "userSelect": + [ + "normal" + ], + + "mozBoxSizing": + [ + "content-box", + "padding-box", + "border-box" + ], + + "mozBoxAlign": + [ + "start", + "center", + "end", + "baseline", + "stretch" + ], + + "mozBoxDirection": + [ + "normal", + "reverse" + ], + + "mozBoxOrient": + [ + "horizontal", + "vertical" + ], + + "mozBoxPack": + [ + "start", + "center", + "end" + ] +}; + +this.nonEditableTags = +{ + "HTML": 1, + "HEAD": 1, + "html": 1, + "head": 1 +}; + +this.innerEditableTags = +{ + "BODY": 1, + "body": 1 +}; + +this.selfClosingTags = +{ // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML + "meta": 1, + "link": 1, + "area": 1, + "base": 1, + "col": 1, + "input": 1, + "img": 1, + "br": 1, + "hr": 1, + "param":1, + "embed":1 +}; + +var invisibleTags = this.invisibleTags = +{ + "HTML": 1, + "HEAD": 1, + "TITLE": 1, + "META": 1, + "LINK": 1, + "STYLE": 1, + "SCRIPT": 1, + "NOSCRIPT": 1, + "BR": 1, + "PARAM": 1, + "COL": 1, + + "html": 1, + "head": 1, + "title": 1, + "meta": 1, + "link": 1, + "style": 1, + "script": 1, + "noscript": 1, + "br": 1, + "param": 1, + "col": 1 + /* + "window": 1, + "browser": 1, + "frame": 1, + "tabbrowser": 1, + "WINDOW": 1, + "BROWSER": 1, + "FRAME": 1, + "TABBROWSER": 1, + */ +}; + + +if (typeof KeyEvent == "undefined") { + this.KeyEvent = { + DOM_VK_CANCEL: 3, + DOM_VK_HELP: 6, + DOM_VK_BACK_SPACE: 8, + DOM_VK_TAB: 9, + DOM_VK_CLEAR: 12, + DOM_VK_RETURN: 13, + DOM_VK_ENTER: 14, + DOM_VK_SHIFT: 16, + DOM_VK_CONTROL: 17, + DOM_VK_ALT: 18, + DOM_VK_PAUSE: 19, + DOM_VK_CAPS_LOCK: 20, + DOM_VK_ESCAPE: 27, + DOM_VK_SPACE: 32, + DOM_VK_PAGE_UP: 33, + DOM_VK_PAGE_DOWN: 34, + DOM_VK_END: 35, + DOM_VK_HOME: 36, + DOM_VK_LEFT: 37, + DOM_VK_UP: 38, + DOM_VK_RIGHT: 39, + DOM_VK_DOWN: 40, + DOM_VK_PRINTSCREEN: 44, + DOM_VK_INSERT: 45, + DOM_VK_DELETE: 46, + DOM_VK_0: 48, + DOM_VK_1: 49, + DOM_VK_2: 50, + DOM_VK_3: 51, + DOM_VK_4: 52, + DOM_VK_5: 53, + DOM_VK_6: 54, + DOM_VK_7: 55, + DOM_VK_8: 56, + DOM_VK_9: 57, + DOM_VK_SEMICOLON: 59, + DOM_VK_EQUALS: 61, + DOM_VK_A: 65, + DOM_VK_B: 66, + DOM_VK_C: 67, + DOM_VK_D: 68, + DOM_VK_E: 69, + DOM_VK_F: 70, + DOM_VK_G: 71, + DOM_VK_H: 72, + DOM_VK_I: 73, + DOM_VK_J: 74, + DOM_VK_K: 75, + DOM_VK_L: 76, + DOM_VK_M: 77, + DOM_VK_N: 78, + DOM_VK_O: 79, + DOM_VK_P: 80, + DOM_VK_Q: 81, + DOM_VK_R: 82, + DOM_VK_S: 83, + DOM_VK_T: 84, + DOM_VK_U: 85, + DOM_VK_V: 86, + DOM_VK_W: 87, + DOM_VK_X: 88, + DOM_VK_Y: 89, + DOM_VK_Z: 90, + DOM_VK_CONTEXT_MENU: 93, + DOM_VK_NUMPAD0: 96, + DOM_VK_NUMPAD1: 97, + DOM_VK_NUMPAD2: 98, + DOM_VK_NUMPAD3: 99, + DOM_VK_NUMPAD4: 100, + DOM_VK_NUMPAD5: 101, + DOM_VK_NUMPAD6: 102, + DOM_VK_NUMPAD7: 103, + DOM_VK_NUMPAD8: 104, + DOM_VK_NUMPAD9: 105, + DOM_VK_MULTIPLY: 106, + DOM_VK_ADD: 107, + DOM_VK_SEPARATOR: 108, + DOM_VK_SUBTRACT: 109, + DOM_VK_DECIMAL: 110, + DOM_VK_DIVIDE: 111, + DOM_VK_F1: 112, + DOM_VK_F2: 113, + DOM_VK_F3: 114, + DOM_VK_F4: 115, + DOM_VK_F5: 116, + DOM_VK_F6: 117, + DOM_VK_F7: 118, + DOM_VK_F8: 119, + DOM_VK_F9: 120, + DOM_VK_F10: 121, + DOM_VK_F11: 122, + DOM_VK_F12: 123, + DOM_VK_F13: 124, + DOM_VK_F14: 125, + DOM_VK_F15: 126, + DOM_VK_F16: 127, + DOM_VK_F17: 128, + DOM_VK_F18: 129, + DOM_VK_F19: 130, + DOM_VK_F20: 131, + DOM_VK_F21: 132, + DOM_VK_F22: 133, + DOM_VK_F23: 134, + DOM_VK_F24: 135, + DOM_VK_NUM_LOCK: 144, + DOM_VK_SCROLL_LOCK: 145, + DOM_VK_COMMA: 188, + DOM_VK_PERIOD: 190, + DOM_VK_SLASH: 191, + DOM_VK_BACK_QUOTE: 192, + DOM_VK_OPEN_BRACKET: 219, + DOM_VK_BACK_SLASH: 220, + DOM_VK_CLOSE_BRACKET: 221, + DOM_VK_QUOTE: 222, + DOM_VK_META: 224 + }; +} + + +// ************************************************************************************************ +// Ajax + +/** + * @namespace + */ +this.Ajax = +{ + + requests: [], + transport: null, + states: ["Uninitialized","Loading","Loaded","Interactive","Complete"], + + initialize: function() + { + this.transport = this.getXHRObject(); + }, + + getXHRObject: function() + { + var xhrObj = false; + try + { + xhrObj = new XMLHttpRequest(); + } + catch(e) + { + var progid = [ + "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" + ]; + + for ( var i=0; i < progid.length; ++i ) { + try + { + xhrObj = new ActiveXObject(progid[i]); + } + catch(e) + { + continue; + } + break; + } + } + finally + { + return xhrObj; + } + }, + + + /** + * Create a AJAX request. + * + * @name request + * @param {Object} options request options + * @param {String} options.url URL to be requested + * @param {String} options.type Request type ("get" ou "post"). Default is "get". + * @param {Boolean} options.async Asynchronous flag. Default is "true". + * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text". + * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded". + * @param {Function} options.onLoading onLoading callback + * @param {Function} options.onLoaded onLoaded callback + * @param {Function} options.onInteractive onInteractive callback + * @param {Function} options.onComplete onComplete callback + * @param {Function} options.onUpdate onUpdate callback + * @param {Function} options.onSuccess onSuccess callback + * @param {Function} options.onFailure onFailure callback + */ + request: function(options) + { + // process options + var o = FBL.extend( + { + // default values + type: "get", + async: true, + dataType: "text", + contentType: "application/x-www-form-urlencoded" + }, + options || {} + ); + + this.requests.push(o); + + var s = this.getState(); + if (s == "Uninitialized" || s == "Complete" || s == "Loaded") + this.sendRequest(); + }, + + serialize: function(data) + { + var r = [""], rl = 0; + if (data) { + if (typeof data == "string") r[rl++] = data; + + else if (data.innerHTML && data.elements) { + for (var i=0,el,l=(el=data.elements).length; i < l; i++) + if (el[i].name) { + r[rl++] = encodeURIComponent(el[i].name); + r[rl++] = "="; + r[rl++] = encodeURIComponent(el[i].value); + r[rl++] = "&"; + } + + } else + for(var param in data) { + r[rl++] = encodeURIComponent(param); + r[rl++] = "="; + r[rl++] = encodeURIComponent(data[param]); + r[rl++] = "&"; + } + } + return r.join("").replace(/&$/, ""); + }, + + sendRequest: function() + { + var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; + + // open XHR object + t.open(r.type, r.url, r.async); + + //setRequestHeaders(); + + // indicates that it is a XHR request to the server + t.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // if data is being sent, sets the appropriate content-type + if (data = FBL.Ajax.serialize(r.data)) + t.setRequestHeader("Content-Type", r.contentType); + + /** @ignore */ + // onreadystatechange handler + t.onreadystatechange = function() + { + FBL.Ajax.onStateChange(r); + }; + + // send the request + t.send(data); + }, + + /** + * Handles the state change + */ + onStateChange: function(options) + { + var fn, o = options, t = this.transport; + var state = this.getState(t); + + if (fn = o["on" + state]) fn(this.getResponse(o), o); + + if (state == "Complete") + { + var success = t.status == 200, response = this.getResponse(o); + + if (fn = o["onUpdate"]) + fn(response, o); + + if (fn = o["on" + (success ? "Success" : "Failure")]) + fn(response, o); + + t.onreadystatechange = FBL.emptyFn; + + if (this.requests.length > 0) + setTimeout(this.sendRequest, 10); + } + }, + + /** + * gets the appropriate response value according the type + */ + getResponse: function(options) + { + var t = this.transport, type = options.dataType; + + if (t.status != 200) return t.statusText; + else if (type == "text") return t.responseText; + else if (type == "html") return t.responseText; + else if (type == "xml") return t.responseXML; + else if (type == "json") return eval("(" + t.responseText + ")"); + }, + + /** + * returns the current state of the XHR object + */ + getState: function() + { + return this.states[this.transport.readyState]; + } + +}; + + +// ************************************************************************************************ +// Cookie, from http://www.quirksmode.org/js/cookies.html + +this.createCookie = function(name,value,days) +{ + if ('cookie' in document) + { + if (days) + { + var date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + var expires = "; expires="+date.toGMTString(); + } + else + var expires = ""; + + document.cookie = name+"="+value+expires+"; path=/"; + } +}; + +this.readCookie = function (name) +{ + if ('cookie' in document) + { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + + for(var i=0; i < ca.length; i++) + { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + } + + return null; +}; + +this.removeCookie = function(name) +{ + this.createCookie(name, "", -1); +}; + + +// ************************************************************************************************ +// http://www.mister-pixel.com/#Content__state=is_that_simple +var fixIE6BackgroundImageCache = function(doc) +{ + doc = doc || document; + try + { + doc.execCommand("BackgroundImageCache", false, true); + } + catch(E) + { + + } +}; + +// ************************************************************************************************ +// calculatePixelsPerInch + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; + +var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body) +{ + var inch = FBL.createGlobalElement("div"); + inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;"; + body.appendChild(inch); + + FBL.pixelsPerInch = { + x: inch.offsetWidth, + y: inch.offsetHeight + }; + + body.removeChild(inch); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceLink = function(url, line, type, object, instance) +{ + this.href = url; + this.instance = instance; + this.line = line; + this.type = type; + this.object = object; +}; + +this.SourceLink.prototype = +{ + toString: function() + { + return this.href; + }, + toJSON: function() // until 3.1... + { + return "{\"href\":\""+this.href+"\", "+ + (this.line?("\"line\":"+this.line+","):"")+ + (this.type?(" \"type\":\""+this.type+"\","):"")+ + "}"; + } + +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceText = function(lines, owner) +{ + this.lines = lines; + this.owner = owner; +}; + +this.SourceText.getLineAsHTML = function(lineNo) +{ + return escapeForSourceLine(this.lines[lineNo-1]); +}; + + +// ************************************************************************************************ +}).apply(FBL); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-i18n */ function() { with (FBL) { +// ************************************************************************************************ + +// TODO: xxxpedro localization +var oSTR = +{ + "NoMembersWarning": "There are no properties to show for this object.", + + "EmptyStyleSheet": "There are no rules in this stylesheet.", + "EmptyElementCSS": "This element has no style rules.", + "AccessRestricted": "Access to restricted URI denied.", + + "net.label.Parameters": "Parameters", + "net.label.Source": "Source", + "URLParameters": "Params", + + "EditStyle": "Edit Element Style...", + "NewRule": "New Rule...", + + "NewProp": "New Property...", + "EditProp": 'Edit "%s"', + "DeleteProp": 'Delete "%s"', + "DisableProp": 'Disable "%s"' +}; + +// ************************************************************************************************ + +FBL.$STR = function(name) +{ + return oSTR.hasOwnProperty(name) ? oSTR[name] : name; +}; + +FBL.$STRF = function(name, args) +{ + if (!oSTR.hasOwnProperty(name)) return name; + + var format = oSTR[name]; + var objIndex = 0; + + var parts = parseFormat(format); + var trialIndex = objIndex; + var objects = args; + + for (var i= 0; i < parts.length; i++) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + + var result = []; + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + result.push(""+args.shift()); + } + else + result.push(part); + } + + return result.join(""); +}; + +// ************************************************************************************************ + +var parseFormat = function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-firebug */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; +var reps = []; + +var parentPanelMap = {}; + + +// ************************************************************************************************ +// Firebug + +/** + * @namespace describe Firebug + * @exports window.Firebug as Firebug + */ +window.Firebug = FBL.Firebug = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + version: "Firebug Lite 1.3.2", + revision: "$Revision: 9759 $", + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + modules: modules, + panelTypes: panelTypes, + panelTypeMap: panelTypeMap, + reps: reps, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Initialization + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); + + Firebug.browser = new Context(Env.browser); + Firebug.context = Firebug.browser; + + // Document must be cached before chrome initialization + cacheDocument(); + + if (Firebug.Inspector) + Firebug.Inspector.create(); + + if (FBL.processAllStyleSheets) + processAllStyleSheets(Firebug.browser.document); + + FirebugChrome.initialize(); + + dispatch(modules, "initialize", []); + + if (Env.onLoad) + { + var onLoad = Env.onLoad; + delete Env.onLoad; + + setTimeout(onLoad, 200); + } + }, + + shutdown: function() + { + if (Firebug.Inspector) + Firebug.Inspector.destroy(); + + dispatch(modules, "shutdown", []); + + var chromeMap = FirebugChrome.chromeMap; + + for (var name in chromeMap) + { + if (chromeMap.hasOwnProperty(name)) + { + chromeMap[name].destroy(); + } + } + + Firebug.Lite.Cache.Element.clear(); + Firebug.Lite.Cache.StyleSheet.clear(); + + Firebug.browser = null; + Firebug.context = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + modules.push.apply(modules, arguments); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + panelTypeMap[panelType.prototype.name] = arguments[i]; + + if (panelType.prototype.parentPanel) + parentPanelMap[panelType.prototype.parentPanel] = 1; + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + }, + + registerRep: function() + { + reps.push.apply(reps, arguments); + }, + + unregisterRep: function() + { + for (var i = 0; i < arguments.length; ++i) + remove(reps, arguments[i]); + }, + + setDefaultReps: function(funcRep, rep) + { + FBL.defaultRep = rep; + FBL.defaultFuncRep = funcRep; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Reps + + getRep: function(object) + { + var type = typeof object; + if (isIE && isFunction(object)) + type = "function"; + + for (var i = 0; i < reps.length; ++i) + { + var rep = reps[i]; + try + { + if (rep.supportsObject(object, type)) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("getRep type: "+type+" object: "+object, rep); + return rep; + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc); + FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className); + // TODO: xxxpedro add trace to FBTrace logs like in Firebug + //firebug.trace(); + } + } + } + + return (type == 'function') ? defaultFuncRep : defaultRep; + }, + + getRepObject: function(node) + { + var target = null; + for (var child = node; child; child = child.parentNode) + { + if (hasClass(child, "repTarget")) + target = child; + + if (child.repObject) + { + if (!target && hasClass(child, "repIgnore")) + break; + else + return child.repObject; + } + } + }, + + getRepNode: function(node) + { + for (var child = node; child; child = child.parentNode) + { + if (child.repObject) + return child; + } + }, + + getElementByRepObject: function(element, object) + { + for (var child = element.firstChild; child; child = child.nextSibling) + { + if (child.repObject == object) + return child; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Preferences + + getPref: function(name) + { + return Firebug[name]; + }, + + setPref: function(name, value) + { + Firebug[name] = value; + + this.savePrefs(); + }, + + setPrefs: function(prefs) + { + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + + this.savePrefs(); + }, + + restorePrefs: function() + { + var Options = Env.Options; + + for (var name in Options) + { + Firebug[name] = Options[name]; + } + }, + + loadPrefs: function(prefs) + { + this.restorePrefs(); + + prefs = prefs || eval("(" + readCookie("FirebugLite") + ")"); + + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + }, + + savePrefs: function() + { + var json = ['{'], jl = 0; + var Options = Env.Options; + + for (var name in Options) + { + if (Options.hasOwnProperty(name)) + { + var value = Firebug[name]; + + json[++jl] = '"'; + json[++jl] = name; + + var type = typeof value; + if (type == "boolean" || type == "number") + { + json[++jl] = '":'; + json[++jl] = value; + json[++jl] = ','; + } + else + { + json[++jl] = '":"'; + json[++jl] = value; + json[++jl] = '",'; + } + } + } + + json.length = jl--; + json[++jl] = '}'; + + createCookie("FirebugLite", json.join("")); + }, + + erasePrefs: function() + { + removeCookie("FirebugLite"); + } +}; + +Firebug.restorePrefs(); + +if (!Env.Options.enablePersistent || + Env.Options.enablePersistent && Env.isChromeContext || + Env.isDebugMode) + Env.browser.window.Firebug = FBL.Firebug; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Other methods + +FBL.cacheDocument = function cacheDocument() +{ + var ElementCache = Firebug.Lite.Cache.Element; + var els = Firebug.browser.document.getElementsByTagName("*"); + for (var i=0, l=els.length, el; iFirebug.registerModule method. There is always one instance of a module object + * per browser window. + * @extends Firebug.Listener + */ +Firebug.Module = extend(new Firebug.Listener(), +/** @extend Firebug.Module */ +{ + /** + * Called when the window is opened. + */ + initialize: function() + { + }, + + /** + * Called when the window is closed. + */ + shutdown: function() + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Called when a new context is created but before the page is loaded. + */ + initContext: function(context) + { + }, + + /** + * Called after a context is detached to a separate window; + */ + reattachContext: function(browser, context) + { + }, + + /** + * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. + */ + destroyContext: function(context, persistedState) + { + }, + + // Called when a FF tab is create or activated (user changes FF tab) + // Called after context is created or with context == null (to abort?) + showContext: function(browser, context) + { + }, + + /** + * Called after a context's page gets DOMContentLoaded + */ + loadedContext: function(context) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + showPanel: function(browser, panel) + { + }, + + showSidePanel: function(browser, panel) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateOption: function(name, value) + { + }, + + getObjectByURL: function(context, url) + { + } +}); + +// ************************************************************************************************ +// Panel + +/** + * @panel Base class for all panels. Every derived panel must define a constructor and + * register with "Firebug.registerPanel" method. An instance of the panel + * object is created by the framework for each browser tab where Firebug is activated. + */ +Firebug.Panel = +{ + name: "HelloWorld", + title: "Hello World!", + + parentPanel: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + options: { + hasCommandLine: false, + hasStatusBar: false, + hasToolButtons: false, + + // Pre-rendered panels are those included in the skin file (firebug.html) + isPreRendered: false, + innerHTMLSync: false + + /* + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // To be used by external extensions + panelHTML: "", + panelCSS: "", + + toolButtonsHTML: "" + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + tabNode: null, + panelNode: null, + sidePanelNode: null, + statusBarNode: null, + toolButtonsNode: null, + + panelBarNode: null, + + sidePanelBarBoxNode: null, + sidePanelBarNode: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + sidePanelBar: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + searchable: false, + editable: true, + order: 2147483647, + statusSeparator: "<", + + create: function(context, doc) + { + this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name); + + this.panelBarNode = $("fbPanelBar1"); + this.sidePanelBarBoxNode = $("fbPanelBar2"); + + if (this.hasSidePanel) + { + this.sidePanelBar = extend({}, PanelBar); + this.sidePanelBar.create(this); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + if (options.isPreRendered) + { + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + } + else + { + var containerSufix = this.parentPanel ? "2" : "1"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel + var panelNode = this.panelNode = createElement("div", { + id: panelId, + className: "fbPanel" + }); + + $("fbPanel" + containerSufix).appendChild(panelNode); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel Tab + var tabHTML = '' + + this.title + ''; + + var tabNode = this.tabNode = createElement("a", { + id: panelId + "Tab", + className: "fbTab fbHover", + innerHTML: tabHTML + }); + + if (isIE6) + { + tabNode.href = "javascript:void(0)"; + } + + var panelBarNode = this.parentPanel ? + Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode : + this.panelBarNode; + + panelBarNode.appendChild(tabNode); + tabNode.style.display = "block"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create ToolButtons + if (options.hasToolButtons) + { + this.toolButtonsNode = createElement("span", { + id: panelId + "Buttons", + className: "fbToolbarButtons" + }); + + $("fbToolbarButtons").appendChild(this.toolButtonsNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create StatusBar + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + + this.statusBarNode = createElement("span", { + id: panelId + "StatusBar", + className: "fbToolbarButtons fbStatusBar" + }); + + this.statusBarBox.appendChild(this.statusBarNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create SidePanel + } + + this.containerNode = this.panelNode.parentNode; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name); + + // xxxpedro contextMenu + this.onContextMenu = bind(this.onContextMenu, this); + + /* + this.context = context; + this.document = doc; + + this.panelNode = doc.createElement("div"); + this.panelNode.ownerPanel = this; + + setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); + doc.body.appendChild(this.panelNode); + + if (FBTrace.DBG_INITIALIZE) + FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); + + this.initializeNode(this.panelNode); + /**/ + }, + + destroy: function(state) // Panel may store info on state + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name); + + if (this.hasSidePanel) + { + this.sidePanelBar.destroy(); + this.sidePanelBar = null; + } + + this.options = null; + this.name = null; + this.parentPanel = null; + + this.tabNode = null; + this.panelNode = null; + this.containerNode = null; + + this.toolButtonsNode = null; + this.statusBarBox = null; + this.statusBarNode = null; + + //if (this.panelNode) + // delete this.panelNode.ownerPanel; + + //this.destroyNode(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + this.sidePanelBar.initialize(); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + this.containerNode = this.panelNode.parentNode; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // restore persistent state + this.containerNode.scrollTop = this.lastScrollTop; + + // xxxpedro contextMenu + addEvent(this.containerNode, "contextmenu", this.onContextMenu); + + + /// TODO: xxxpedro infoTip Hack + Firebug.chrome.currentPanel = + Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ? + Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel : + Firebug.chrome.selectedPanel; + + Firebug.showInfoTips = true; + Firebug.InfoTip.initializeBrowser(Firebug.chrome); + }, + + shutdown: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); + + /// TODO: xxxpedro infoTip Hack + Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); + + if (Firebug.chrome.largeCommandLineVisible) + Firebug.chrome.hideLargeCommandLine(); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + // TODO: xxxpedro firebug1.3a6 + // new PanelBar mechanism will need to call shutdown to hide the panels (so it + // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement + // a "remember selected panel" feature in the sidePanelBar + //this.sidePanelBar.shutdown(); + } + + // store persistent state + this.lastScrollTop = this.containerNode.scrollTop; + + // xxxpedro contextMenu + removeEvent(this.containerNode, "contextmenu", this.onContextMenu); + }, + + detach: function(oldChrome, newChrome) + { + if (oldChrome.selectedPanel.name == this.name) + this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop; + }, + + reattach: function(doc) + { + if (this.options.innerHTMLSync) + this.synchronizeUI(); + }, + + synchronizeUI: function() + { + this.containerNode.scrollTop = this.lastScrollTop || 0; + }, + + show: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "inline"; + this.statusBarNode.style.display = "inline"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "inline"; + } + + this.panelNode.style.display = "block"; + + this.visible = true; + + if (!this.parentPanel) + Firebug.chrome.layout(this); + }, + + hide: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "none"; + this.statusBarNode.style.display = "none"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "none"; + } + + this.panelNode.style.display = "none"; + + this.visible = false; + }, + + watchWindow: function(win) + { + }, + + unwatchWindow: function(win) + { + }, + + updateOption: function(name, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Toolbar helpers + */ + showToolbarButtons: function(buttonsId, show) + { + try + { + if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext. + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this); + + return; + } + var buttons = this.context.browser.chrome.$(buttonsId); + if (buttons) + collapse(buttons, show ? "false" : "true"); + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc); + if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser"); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Returns a number indicating the view's ability to inspect the object. + * + * Zero means not supported, and higher numbers indicate specificity. + */ + supportsObject: function(object) + { + return 0; + }, + + hasObject: function(object) // beyond type testing, is this object selectable? + { + return false; + }, + + select: function(object, forceUpdate) + { + if (!object) + object = this.getDefaultSelection(this.context); + + if(FBTrace.DBG_PANELS) + FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); + + if (forceUpdate || object != this.selection) + { + this.selection = object; + this.updateSelection(object); + + // TODO: xxxpedro + // XXXjoe This is kind of cheating, but, feh. + //Firebug.chrome.onPanelSelect(object, this); + //if (uiListeners.length > 0) + // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener + } + }, + + updateSelection: function(object) + { + }, + + markChange: function(skipSelf) + { + if (this.dependents) + { + if (skipSelf) + { + for (var i = 0; i < this.dependents.length; ++i) + { + var panelName = this.dependents[i]; + if (panelName != this.name) + this.context.invalidatePanels(panelName); + } + } + else + this.context.invalidatePanels.apply(this.context, this.dependents); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + startInspecting: function() + { + }, + + stopInspecting: function(object, cancelled) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + search: function(text, reverse) + { + }, + + /** + * Retrieves the search options that this modules supports. + * This is used by the search UI to present the proper options. + */ + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive") + ]; + }, + + /** + * Navigates to the next document whose match parameter returns true. + */ + navigateToNextDocument: function(match, reverse) + { + // This is an approximation of the UI that is displayed by the location + // selector. This should be close enough, although it may be better + // to simply generate the sorted list within the module, rather than + // sorting within the UI. + var self = this; + function compare(a, b) { + var locA = self.getObjectDescription(a); + var locB = self.getObjectDescription(b); + if(locA.path > locB.path) + return 1; + if(locA.path < locB.path) + return -1; + if(locA.name > locB.name) + return 1; + if(locA.name < locB.name) + return -1; + return 0; + } + var allLocs = this.getLocationList().sort(compare); + for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++); + + function transformIndex(index) { + if (reverse) { + // For the reverse case we need to implement wrap around. + var intermediate = curPos - index - 1; + return (intermediate < 0 ? allLocs.length : 0) + intermediate; + } else { + return (curPos + index + 1) % allLocs.length; + } + }; + + for (var next = 0; next < allLocs.length - 1; next++) + { + var object = allLocs[transformIndex(next)]; + + if (match(object)) + { + this.navigate(object); + return object; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // Called when "Options" clicked. Return array of + // {label: 'name', nol10n: true, type: "checkbox", checked: , command:function to set } + getOptionsMenuItems: function() + { + return null; + }, + + /* + * Called by chrome.onContextMenu to build the context menu when this panel has focus. + * See also FirebugRep for a similar function also called by onContextMenu + * Extensions may monkey patch and chain off this call + * @param object: the 'realObject', a model value, eg a DOM property + * @param target: the HTML element clicked on. + * @return an array of menu items. + */ + getContextMenuItems: function(object, target) + { + return []; + }, + + getBreakOnMenuItems: function() + { + return []; + }, + + getEditor: function(target, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getDefaultSelection: function() + { + return null; + }, + + browseObject: function(object) + { + }, + + getPopupObject: function(target) + { + return Firebug.getRepObject(target); + }, + + getTooltipObject: function(target) + { + return Firebug.getRepObject(target); + }, + + showInfoTip: function(infoTip, x, y) + { + + }, + + getObjectPath: function(object) + { + return null; + }, + + // An array of objects that can be passed to getObjectLocation. + // The list of things a panel can show, eg sourceFiles. + // Only shown if panel.location defined and supportsObject true + getLocationList: function() + { + return null; + }, + + getDefaultLocation: function() + { + return null; + }, + + getObjectLocation: function(object) + { + return ""; + }, + + // Text for the location list menu eg script panel source file list + // return.path: group/category label, return.name: item label + getObjectDescription: function(object) + { + var url = this.getObjectLocation(object); + return FBL.splitURLBase(url); + }, + + /* + * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint + * @param: show boolean, true turns on. + */ + highlight: function(show) + { + var tab = this.getTab(); + if (!tab) + return; + + if (show) + tab.setAttribute("highlight", "true"); + else + tab.removeAttribute("highlight"); + }, + + getTab: function() + { + var chrome = Firebug.chrome; + + var tab = chrome.$("fbPanelBar2").getTab(this.name); + if (!tab) + tab = chrome.$("fbPanelBar1").getTab(this.name); + return tab; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for Break On Next + + /** + * Called by the framework when the user clicks on the Break On Next button. + * @param {Boolean} armed Set to true if the Break On Next feature is + * to be armed for action and set to false if the Break On Next should be disarmed. + * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|. + */ + breakOnNext: function(armed) + { + }, + + /** + * Called when a panel is selected/displayed. The method should return true + * if the Break On Next feature is currently armed for this panel. + */ + shouldBreakOnNext: function() + { + return false; + }, + + /** + * Returns labels for Break On Next tooltip (one for enabled and one for disabled state). + * @param {Boolean} enabled Set to true if the Break On Next feature is + * currently activated for this panel. + */ + getBreakOnNextTooltip: function(enabled) + { + return null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // xxxpedro contextMenu + onContextMenu: function(event) + { + if (!this.getContextMenuItems) + return; + + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + var menu = this.getContextMenuItems(this.selection, target); + if (!menu) + return; + + var contextMenu = new Menu( + { + id: "fbPanelContextMenu", + + items: menu + }); + + contextMenu.show(event.clientX, event.clientY); + + return true; + + /* + // TODO: xxxpedro move code to somewhere. code to get cross-browser + // window to screen coordinates + var box = Firebug.browser.getElementPosition(Firebug.chrome.node); + + var screenY = 0; + + // Firefox + if (typeof window.mozInnerScreenY != "undefined") + { + screenY = window.mozInnerScreenY; + } + // Chrome + else if (typeof window.innerHeight != "undefined") + { + screenY = window.outerHeight - window.innerHeight; + } + // IE + else if (typeof window.screenTop != "undefined") + { + screenY = window.screenTop; + } + + contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top); + /**/ + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * MeasureBox + * To get pixels size.width and size.height: + *
      • this.startMeasuring(view);
      • + *
      • var size = this.measureText(lineNoCharsSpacer);
      • + *
      • this.stopMeasuring();
      • + *
      + * + * @namespace + */ +Firebug.MeasureBox = +{ + startMeasuring: function(target) + { + if (!this.measureBox) + { + this.measureBox = target.ownerDocument.createElement("span"); + this.measureBox.className = "measureBox"; + } + + copyTextStyles(target, this.measureBox); + target.ownerDocument.body.appendChild(this.measureBox); + }, + + getMeasuringElement: function() + { + return this.measureBox; + }, + + measureText: function(value) + { + this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m"; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + measureInputText: function(value) + { + value = value ? escapeForTextNode(value) : "m"; + if (!Firebug.showTextNodesWithWhitespace) + value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m'); + this.measureBox.innerHTML = value; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + getBox: function(target) + { + var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, ""); + var box = getBoxFromStyles(style, this.measureBox); + return box; + }, + + stopMeasuring: function() + { + this.measureBox.parentNode.removeChild(this.measureBox); + } +}; + + +// ************************************************************************************************ +if (FBL.domplate) Firebug.Rep = domplate( +{ + className: "", + inspectable: true, + + supportsObject: function(object, type) + { + return false; + }, + + inspectObject: function(object, context) + { + Firebug.chrome.select(object); + }, + + browseObject: function(object, context) + { + }, + + persistObject: function(object, context) + { + }, + + getRealObject: function(object, context) + { + return object; + }, + + getTitle: function(object) + { + var label = safeToString(object); + + var re = /\[object (.*?)\]/; + var m = re.exec(label); + + ///return m ? m[1] : label; + + // if the label is in the "[object TYPE]" format return its type + if (m) + { + return m[1]; + } + // if it is IE we need to handle some special cases + else if ( + // safeToString() fails to recognize some objects in IE + isIE && + // safeToString() returns "[object]" for some objects like window.Image + (label == "[object]" || + // safeToString() returns undefined for some objects like window.clientInformation + typeof object == "object" && typeof label == "undefined") + ) + { + return "Object"; + } + else + { + return label; + } + }, + + getTooltip: function(object) + { + return null; + }, + + getContextMenuItems: function(object, target, context) + { + return []; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Convenience for domplates + + STR: function(name) + { + return $STR(name); + }, + + cropString: function(text) + { + return cropString(text); + }, + + cropMultipleLines: function(text, limit) + { + return cropMultipleLines(text, limit); + }, + + toLowerCase: function(text) + { + return text ? text.toLowerCase() : text; + }, + + plural: function(n) + { + return n == 1 ? "" : "s"; + } +}); + +// ************************************************************************************************ + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-gui */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Controller + +/**@namespace*/ +FBL.Controller = { + + controllers: null, + controllerContext: null, + + initialize: function(context) + { + this.controllers = []; + this.controllerContext = context || Firebug.chrome; + }, + + shutdown: function() + { + this.removeControllers(); + + //this.controllers = null; + //this.controllerContext = null; + }, + + addController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + // If the first argument is a string, make a selector query + // within the controller node context + if (typeof arg[0] == "string") + { + arg[0] = $$(arg[0], this.controllerContext); + } + + // bind the handler to the proper context + var handler = arg[2]; + arg[2] = bind(handler, this); + // save the original handler as an extra-argument, so we can + // look for it later, when removing a particular controller + arg[3] = handler; + + this.controllers.push(arg); + addEvent.apply(this, arg); + } + }, + + removeController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + for (var j=0, c; c=this.controllers[j]; j++) + { + if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3]) + removeEvent.apply(this, c); + } + } + }, + + removeControllers: function() + { + for (var i=0, c; c=this.controllers[i]; i++) + { + removeEvent.apply(this, c); + } + } +}; + + +// ************************************************************************************************ +// PanelBar + +/**@namespace*/ +FBL.PanelBar = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + panelMap: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + selectedPanel: null, + parentPanelName: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function(ownerPanel) + { + this.panelMap = {}; + this.ownerPanel = ownerPanel; + + if (ownerPanel) + { + ownerPanel.sidePanelBarNode = createElement("span"); + ownerPanel.sidePanelBarNode.style.display = "none"; + ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode); + } + + var panels = Firebug.panelTypes; + for (var i=0, p; p=panels[i]; i++) + { + if ( // normal Panel of the Chrome's PanelBar + !ownerPanel && !p.prototype.parentPanel || + // Child Panel of the current Panel's SidePanelBar + ownerPanel && p.prototype.parentPanel && + ownerPanel.name == p.prototype.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + }, + + destroy: function() + { + PanelBar.shutdown.call(this); + + for (var name in this.panelMap) + { + this.removePanel(name); + + var panel = this.panelMap[name]; + panel.destroy(); + + this.panelMap[name] = null; + delete this.panelMap[name]; + } + + this.panelMap = null; + this.ownerPanel = null; + }, + + initialize: function() + { + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "inline"; + + for(var name in this.panelMap) + { + (function(self, name){ + + // tab click handler + var onTabClick = function onTabClick() + { + self.selectPanel(name); + return false; + }; + + Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]); + + })(this, name); + } + }, + + shutdown: function() + { + var selectedPanel = this.selectedPanel; + + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.hide(); + selectedPanel.shutdown(); + } + + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "none"; + + this.selectedPanel = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + addPanel: function(panelName, parentPanel) + { + var PanelType = Firebug.panelTypeMap[panelName]; + var panel = this.panelMap[panelName] = new PanelType(); + + panel.create(); + }, + + removePanel: function(panelName) + { + var panel = this.panelMap[panelName]; + if (panel.hasOwnProperty(panelName)) + panel.destroy(); + }, + + selectPanel: function(panelName) + { + var selectedPanel = this.selectedPanel; + var panel = this.panelMap[panelName]; + + if (panel && selectedPanel != panel) + { + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.shutdown(); + selectedPanel.hide(); + } + + if (!panel.parentPanel) + FirebugChrome.selectedPanelName = panelName; + + this.selectedPanel = panel; + + setClass(panel.tabNode, "fbSelectedTab"); + panel.show(); + panel.initialize(); + } + }, + + getPanel: function(panelName) + { + var panel = this.panelMap[panelName]; + + return panel; + } + +}; + +//************************************************************************************************ +// Button + +/** + * options.element + * options.caption + * options.title + * + * options.owner + * options.className + * options.pressedClassName + * + * options.onPress + * options.onUnpress + * options.onClick + * + * @class + * @extends FBL.Controller + * + */ + +FBL.Button = function(options) +{ + options = options || {}; + + append(this, options); + + this.state = "unpressed"; + this.display = "unpressed"; + + if (this.element) + { + this.container = this.element.parentNode; + } + else + { + this.shouldDestroy = true; + + this.container = this.owner.getPanel().toolButtonsNode; + + this.element = createElement("a", { + className: this.baseClassName + " " + this.className + " fbHover", + innerHTML: this.caption + }); + + if (this.title) + this.element.title = this.title; + + this.container.appendChild(this.element); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +Button.prototype = extend(Controller, +/**@extend FBL.Button.prototype*/ +{ + type: "normal", + caption: "caption", + title: null, + + className: "", // custom class + baseClassName: "fbButton", // control class + pressedClassName: "fbBtnPressed", // control pressed class + + element: null, + container: null, + owner: null, + + state: null, + display: null, + + destroy: function() + { + this.shutdown(); + + // only remove if it is a dynamically generated button (not pre-rendered) + if (this.shouldDestroy) + this.container.removeChild(this.element); + + this.element = null; + this.container = null; + this.owner = null; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var element = this.element; + + this.addController([element, "mousedown", this.handlePress]); + + if (this.type == "normal") + this.addController( + [element, "mouseup", this.handleUnpress], + [element, "mouseout", this.handleUnpress], + [element, "click", this.handleClick] + ); + }, + + shutdown: function() + { + Controller.shutdown.apply(this); + }, + + restore: function() + { + this.changeState("unpressed"); + }, + + changeState: function(state) + { + this.state = state; + this.changeDisplay(state); + }, + + changeDisplay: function(display) + { + if (display != this.display) + { + if (display == "pressed") + { + setClass(this.element, this.pressedClassName); + } + else if (display == "unpressed") + { + removeClass(this.element, this.pressedClassName); + } + this.display = display; + } + }, + + handlePress: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + this.changeDisplay("pressed"); + this.beforeClick = true; + } + else if (this.type == "toggle") + { + if (this.state == "pressed") + { + this.changeState("unpressed"); + + if (this.onUnpress) + this.onUnpress.apply(this.owner, arguments); + } + else + { + this.changeState("pressed"); + + if (this.onPress) + this.onPress.apply(this.owner, arguments); + } + + if (this.onClick) + this.onClick.apply(this.owner, arguments); + } + + return false; + }, + + handleUnpress: function(event) + { + cancelEvent(event, true); + + if (this.beforeClick) + this.changeDisplay("unpressed"); + + return false; + }, + + handleClick: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + if (this.onClick) + this.onClick.apply(this.owner); + + this.changeState("unpressed"); + } + + this.beforeClick = false; + + return false; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * @class + * @extends FBL.Button + */ +FBL.IconButton = function() +{ + Button.apply(this, arguments); +}; + +IconButton.prototype = extend(Button.prototype, +/**@extend FBL.IconButton.prototype*/ +{ + baseClassName: "fbIconButton", + pressedClassName: "fbIconPressed" +}); + + +//************************************************************************************************ +// Menu + +var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value", + _command: "$item.command"}; + +if (isIE6) + menuItemProps.href = "javascript:void(0)"; + +// Allow GUI to be loaded even when Domplate module is not installed. +if (FBL.domplate) +var MenuPlate = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "fbMenu fbShadow"}, + DIV({"class": "fbMenuContent fbShadowContent"}, + FOR("item", "$object.items|memberIterator", + TAG("$item.tag", {item: "$item"}) + ) + ) + ), + + itemTag: + A(menuItemProps, + "$item.label" + ), + + checkBoxTag: + A(extend(menuItemProps, {checked : "$item.checked"}), + + "$item.label" + ), + + radioButtonTag: + A(extend(menuItemProps, {selected : "$item.selected"}), + + "$item.label" + ), + + groupTag: + A(extend(menuItemProps, {child: "$item.child"}), + "$item.label" + ), + + shortcutTag: + A(menuItemProps, + "$item.label", + SPAN({"class": "fbMenuShortcutKey"}, + "$item.key" + ) + ), + + separatorTag: + SPAN({"class": "fbMenuSeparator"}), + + memberIterator: function(items) + { + var result = []; + + for (var i=0, length=items.length; i width || el.scrollHeight > height)) + { + width = el.scrollWidth; + height = el.scrollHeight; + } + + return {width: width, height: height}; + }, + + getWindowScrollPosition: function() + { + var top=0, left=0, el; + + if(typeof this.window.pageYOffset == "number") + { + top = this.window.pageYOffset; + left = this.window.pageXOffset; + } + else if((el=this.document.body) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + + return {top:top, left:left}; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Element Methods + + getElementFromPoint: function(x, y) + { + if (shouldFixElementFromPoint) + { + var scroll = this.getWindowScrollPosition(); + return this.document.elementFromPoint(x + scroll.left, y + scroll.top); + } + else + return this.document.elementFromPoint(x, y); + }, + + getElementPosition: function(el) + { + var left = 0 + var top = 0; + + do + { + left += el.offsetLeft; + top += el.offsetTop; + } + while (el = el.offsetParent); + + return {left:left, top:top}; + }, + + getElementBox: function(el) + { + var result = {}; + + if (el.getBoundingClientRect) + { + var rect = el.getBoundingClientRect(); + + // fix IE problem with offset when not in fullscreen mode + var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; + + var scroll = this.getWindowScrollPosition(); + + result.top = Math.round(rect.top - offset + scroll.top); + result.left = Math.round(rect.left - offset + scroll.left); + result.height = Math.round(rect.bottom - rect.top); + result.width = Math.round(rect.right - rect.left); + } + else + { + var position = this.getElementPosition(el); + + result.top = position.top; + result.left = position.left; + result.height = el.offsetHeight; + result.width = el.offsetWidth; + } + + return result; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Measurement Methods + + getMeasurement: function(el, name) + { + var result = {value: 0, unit: "px"}; + + var cssValue = this.getStyle(el, name); + + if (!cssValue) return result; + if (cssValue.toLowerCase() == "auto") return result; + + var reMeasure = /(\d+\.?\d*)(.*)/; + var m = cssValue.match(reMeasure); + + if (m) + { + result.value = m[1]-0; + result.unit = m[2].toLowerCase(); + } + + return result; + }, + + getMeasurementInPixels: function(el, name) + { + if (!el) return null; + + var m = this.getMeasurement(el, name); + var value = m.value; + var unit = m.unit; + + if (unit == "px") + return value; + + else if (unit == "pt") + return this.pointsToPixels(name, value); + + if (unit == "em") + return this.emToPixels(el, value); + + else if (unit == "%") + return this.percentToPixels(el, value); + }, + + getMeasurementBox1: function(el, name) + { + var sufixes = ["Top", "Left", "Bottom", "Right"]; + var result = []; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getMeasurementBox: function(el, name) + { + var result = []; + var sufixes = name == "border" ? + ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : + ["Top", "Left", "Bottom", "Right"]; + + if (isIE) + { + var propName, cssValue; + var autoMargin = null; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + { + propName = name + sufix; + + cssValue = el.currentStyle[propName] || el.style[propName]; + + if (cssValue == "auto") + { + if (!autoMargin) + autoMargin = this.getCSSAutoMarginBox(el); + + result[i] = autoMargin[sufix.toLowerCase()]; + } + else + result[i] = this.getMeasurementInPixels(el, propName); + + } + + } + else + { + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = this.getMeasurementInPixels(el, name + sufix); + } + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getCSSAutoMarginBox: function(el) + { + if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + var offsetTop = 0; + if (false && isIEStantandMode) + { + var scrollSize = Firebug.browser.getWindowScrollSize(); + offsetTop = scrollSize.height; + } + + var box = this.document.createElement("div"); + //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;"; + box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;"; + + var clone = el.cloneNode(false); + var text = this.document.createTextNode(" "); + clone.appendChild(text); + + box.appendChild(clone); + + this.document.body.appendChild(box); + + var marginTop = clone.offsetTop - box.offsetTop - 1; + var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; + + var marginLeft = clone.offsetLeft - box.offsetLeft - 1; + var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; + + this.document.body.removeChild(box); + + return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight}; + }, + + getFontSizeInPixels: function(el) + { + var size = this.getMeasurement(el, "fontSize"); + + if (size.unit == "px") return size.value; + + // get font size, the dirty way + var computeDirtyFontSize = function(el, calibration) + { + var div = this.document.createElement("div"); + var divStyle = offscreenStyle; + + if (calibration) + divStyle += " font-size:"+calibration+"px;"; + + div.style.cssText = divStyle; + div.innerHTML = "A"; + el.appendChild(div); + + var value = div.offsetHeight; + el.removeChild(div); + return value; + } + + /* + var calibrationBase = 200; + var calibrationValue = computeDirtyFontSize(el, calibrationBase); + var rate = calibrationBase / calibrationValue; + /**/ + + // the "dirty technique" fails in some environments, so we're using a static value + // based in some tests. + var rate = 200 / 225; + + var value = computeDirtyFontSize(el); + + return value * rate; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Unit Funtions + + pointsToPixels: function(name, value, returnFloat) + { + var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; + + var result = value * pixelsPerInch[axis] / 72; + + return returnFloat ? result : Math.round(result); + }, + + emToPixels: function(el, value) + { + if (!el) return null; + + var fontSize = this.getFontSizeInPixels(el); + + return Math.round(value * fontSize); + }, + + exToPixels: function(el, value) + { + if (!el) return null; + + // get ex value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "ex;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + percentToPixels: function(el, value) + { + if (!el) return null; + + // get % value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "%;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getStyle: isIE ? function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : function(el, name) + { + return this.document.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + } + +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Window Options + +var WindowDefaultOptions = + { + type: "frame", + id: "FirebugUI", + height: 250 + }, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Instantiated objects + + commandLine, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Interface Elements Cache + + fbTop, + fbContent, + fbContentStyle, + fbBottom, + fbBtnInspect, + + fbToolbar, + + fbPanelBox1, + fbPanelBox1Style, + fbPanelBox2, + fbPanelBox2Style, + fbPanelBar2Box, + fbPanelBar2BoxStyle, + + fbHSplitter, + fbVSplitter, + fbVSplitterStyle, + + fbPanel1, + fbPanel1Style, + fbPanel2, + fbPanel2Style, + + fbConsole, + fbConsoleStyle, + fbHTML, + + fbCommandLine, + fbLargeCommandLine, + fbLargeCommandButtons, + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Cached size values + + topHeight, + topPartialHeight, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastSelectedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLineState = 0, + lastFocusedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastHSplitterMouseMove = 0, + onHSplitterMouseMoveBuffer = null, + onHSplitterMouseMoveTimer = null, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastVSplitterMouseMove = 0; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// FirebugChrome + +/**@namespace*/ +FBL.FirebugChrome = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + isOpen: false, + height: 250, + sidePanelWidth: 350, + + selectedPanelName: "Console", + selectedHTMLElementId: null, + + chromeMap: {}, + + htmlSelectionStack: [], + consoleMessageQueue: [], + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); + + createChromeWindow(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); + + if (Env.chrome.type == "frame" || Env.chrome.type == "div") + ChromeMini.create(Env.chrome); + + var chrome = Firebug.chrome = new Chrome(Env.chrome); + FirebugChrome.chromeMap[chrome.type] = chrome; + + addGlobalEvent("keydown", onGlobalKeyDown); + + if (Env.Options.enablePersistent && chrome.type == "popup") + { + // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode + var frame = FirebugChrome.chromeMap.frame; + if (frame) + frame.close(); + + //chrome.reattach(frame, chrome); + //TODO: xxxpedro persist synchronize? + chrome.initialize(); + } + }, + + clone: function(FBChrome) + { + for (var name in FBChrome) + { + var prop = FBChrome[name]; + if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) + { + this[name] = prop; + } + } + } +}; + + + +// ************************************************************************************************ +// Chrome Window Creation + +var createChromeWindow = function(options) +{ + options = extend(WindowDefaultOptions, options || {}); + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Locals + + var chrome = {}, + + context = options.context || Env.browser, + + type = chrome.type = Env.Options.enablePersistent ? + "popup" : + options.type, + + isChromeFrame = type == "frame", + + useLocalSkin = Env.useLocalSkin, + + url = useLocalSkin ? + Env.Location.skin : + "about:blank", + + // document.body not available in XML+XSL documents in Firefox + body = context.document.getElementsByTagName("body")[0], + + formatNode = function(node) + { + if (!Env.isDebugMode) + { + node.firebugIgnore = true; + } + + node.style.border = "0"; + node.style.visibility = "hidden"; + node.style.zIndex = "2147483647"; // MAX z-index = 2147483647 + node.style.position = noFixedPosition ? "absolute" : "fixed"; + node.style.width = "100%"; // "102%"; IE auto margin bug + node.style.left = "0"; + node.style.bottom = noFixedPosition ? "-1px" : "0"; + node.style.height = options.height + "px"; + + // avoid flickering during chrome rendering + if (isFirefox) + node.style.display = "none"; + }, + + createChromeDiv = function() + { + //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed."); + + var node = chrome.node = createGlobalElement("div"), + style = createGlobalElement("style"), + + css = FirebugChrome.Skin.CSS + /* + .replace(/;/g, " !important;") + .replace(/!important\s!important/g, "!important") + .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/, + + // reset some styles to minimize interference from the main page's style + rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" + + // load the chrome styles + css + + // adjust some remaining styles + ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}"; + /* + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + rules += ".fbBody table.fbChrome{position: static !important;}"; + }/**/ + + style.type = "text/css"; + + if (style.styleSheet) + style.styleSheet.cssText = rules; + else + style.appendChild(context.document.createTextNode(rules)); + + document.getElementsByTagName("head")[0].appendChild(style); + + node.className = "fbBody"; + node.style.overflow = "hidden"; + node.innerHTML = getChromeDivTemplate(); + + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + setTimeout(function(){ + node.firstChild.style.height = "1px"; + node.firstChild.style.position = "static"; + },0); + /**/ + } + + formatNode(node); + + body.appendChild(node); + + chrome.window = window; + chrome.document = document; + onChromeLoad(chrome); + }; + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + try + { + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "div" (windowless mode) + if (type == "div") + { + createChromeDiv(); + return; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // cretate the Chrome as an "iframe" + else if (isChromeFrame) + { + // Create the Chrome Frame + var node = chrome.node = createGlobalElement("iframe"); + node.setAttribute("src", url); + node.setAttribute("frameBorder", "0"); + + formatNode(node); + + body.appendChild(node); + + // must set the id after appending to the document, otherwise will cause an + // strange error in IE, making the iframe load the page in which the bookmarklet + // was created (like getfirebug.com), before loading the injected UI HTML, + // generating an "Access Denied" error. + node.id = options.id; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "popup" + else + { + var height = FirebugChrome.height || options.height, + + options = [ + "true,top=", + Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0), + ",left=0,height=", + height, + ",width=", + screen.availWidth-10, // Opera opens popup in a new tab if it's too big! + ",resizable" + ].join(""), + + node = chrome.node = context.window.open( + url, + "popup", + options + ); + + if (node) + { + try + { + node.focus(); + } + catch(E) + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + else + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inject the interface HTML if it is not using the local skin + + if (!useLocalSkin) + { + var tpl = getChromeTemplate(!isChromeFrame), + doc = isChromeFrame ? node.contentWindow.document : node.document; + + doc.write(tpl); + doc.close(); + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Wait the Window to be loaded + + var win, + + waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100, + + waitForWindow = function() + { + if ( // Frame loaded... OR + isChromeFrame && (win=node.contentWindow) && + node.contentWindow.document.getElementById("fbCommandLine") || + + // Popup loaded + !isChromeFrame && (win=node.window) && node.document && + node.document.getElementById("fbCommandLine") ) + { + chrome.window = win.window; + chrome.document = win.document; + + // Prevent getting the wrong chrome height in FF when opening a popup + setTimeout(function(){ + onChromeLoad(chrome); + },0); + } + else + setTimeout(waitForWindow, waitDelay); + }; + + waitForWindow(); + } + catch(e) + { + var msg = e.message || e; + + if (/access/i.test(msg)) + { + // Firebug Lite could not create a window for its Graphical User Interface due to + // a access restriction. This happens in some pages, when loading via bookmarklet. + // In such cases, the only way is to load the GUI in a "windowless mode". + + if (isChromeFrame) + body.removeChild(node); + else if(type == "popup") + node.close(); + + // Load the GUI in a "windowless mode" + createChromeDiv(); + } + else + { + alert("Firebug Error: Firebug GUI could not be created."); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var onChromeLoad = function onChromeLoad(chrome) +{ + Env.chrome = chrome; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded"); + + if (Env.Options.enablePersistent) + { + // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode + Env.FirebugChrome = FirebugChrome; + + chrome.window.Firebug = chrome.window.Firebug || {}; + chrome.window.Firebug.SharedEnv = Env; + + if (Env.isDevelopmentMode) + { + Env.browser.window.FBDev.loadChromeApplication(chrome); + } + else + { + var doc = chrome.document; + var script = doc.createElement("script"); + script.src = Env.Location.app + "#remote,persist"; + doc.getElementsByTagName("head")[0].appendChild(script); + } + } + else + { + if (chrome.type == "frame" || chrome.type == "div") + { + // initialize the chrome application + setTimeout(function(){ + FBL.Firebug.initialize(); + },0); + } + else if (chrome.type == "popup") + { + var oldChrome = FirebugChrome.chromeMap.frame; + + var newChrome = new Chrome(chrome); + + // TODO: xxxpedro sync detach reattach attach + dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); + + if (oldChrome) + oldChrome.close(); + + newChrome.reattach(oldChrome, newChrome); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var getChromeDivTemplate = function() +{ + return FirebugChrome.Skin.HTML; +}; + +var getChromeTemplate = function(isPopup) +{ + var tpl = FirebugChrome.Skin; + var r = [], i = -1; + + r[++i] = ''; + r[++i] = ''; + r[++i] = Firebug.version; + + /* + r[++i] = ''; + /**/ + + r[++i] = ''; + /**/ + + r[++i] = ''; + r[++i] = tpl.HTML; + r[++i] = ''; + + return r.join(""); +}; + + +// ************************************************************************************************ +// Chrome Class + +/**@class*/ +var Chrome = function Chrome(chrome) +{ + var type = chrome.type; + var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; + + append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase) + append(this, chrome); // inherit chrome window properties + append(this, new Context(chrome.window)); // inherit from Context class + + FirebugChrome.chromeMap[type] = this; + Firebug.chrome = this; + Env.chrome = chrome.window; + + this.commandLineVisible = false; + this.sidePanelVisible = false; + + this.create(); + + return this; +}; + +// ************************************************************************************************ +// ChromeBase + +/** + * @namespace + * @extends FBL.Controller + * @extends FBL.PanelBar + **/ +var ChromeBase = {}; +append(ChromeBase, Controller); +append(ChromeBase, PanelBar); +append(ChromeBase, +/**@extend ns-chrome-ChromeBase*/ +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited properties + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from createChrome function + + node: null, + type: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from Context.prototype + + document: null, + window: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // value properties + + sidePanelVisible: false, + commandLineVisible: false, + largeCommandLineVisible: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // object properties + + inspectButton: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + PanelBar.create.call(this); + + if (Firebug.Inspector) + this.inspectButton = new Button({ + type: "toggle", + element: $("fbChrome_btInspect"), + owner: Firebug.Inspector, + + onPress: Firebug.Inspector.startInspecting, + onUnpress: Firebug.Inspector.stopInspecting + }); + }, + + destroy: function() + { + if(Firebug.Inspector) + this.inspectButton.destroy(); + + PanelBar.destroy.call(this); + + this.shutdown(); + }, + + testMenu: function() + { + var firebugMenu = new Menu( + { + id: "fbFirebugMenu", + + items: + [ + { + label: "Open Firebug", + type: "shortcut", + key: isFirefox ? "Shift+F12" : "F12", + checked: true, + command: "toggleChrome" + }, + { + label: "Open Firebug in New Window", + type: "shortcut", + key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12", + command: "openPopup" + }, + { + label: "Inspect Element", + type: "shortcut", + key: "Ctrl+Shift+C", + command: "toggleInspect" + }, + { + label: "Command Line", + type: "shortcut", + key: "Ctrl+Shift+L", + command: "focusCommandLine" + }, + "-", + { + label: "Options", + type: "group", + child: "fbFirebugOptionsMenu" + }, + "-", + { + label: "Firebug Lite Website...", + command: "visitWebsite" + }, + { + label: "Discussion Group...", + command: "visitDiscussionGroup" + }, + { + label: "Issue Tracker...", + command: "visitIssueTracker" + } + ], + + onHide: function() + { + iconButton.restore(); + }, + + toggleChrome: function() + { + Firebug.chrome.toggle(); + }, + + openPopup: function() + { + Firebug.chrome.toggle(true, true); + }, + + toggleInspect: function() + { + Firebug.Inspector.toggleInspect(); + }, + + focusCommandLine: function() + { + Firebug.chrome.focusCommandLine(); + }, + + visitWebsite: function() + { + this.visit("http://getfirebug.com/lite.html"); + }, + + visitDiscussionGroup: function() + { + this.visit("http://groups.google.com/group/firebug"); + }, + + visitIssueTracker: function() + { + this.visit("http://code.google.com/p/fbug/issues/list"); + }, + + visit: function(url) + { + window.open(url); + } + + }); + + /**@private*/ + var firebugOptionsMenu = + { + id: "fbFirebugOptionsMenu", + + getItems: function() + { + var cookiesDisabled = !Firebug.saveCookies; + + return [ + { + label: "Save Options in Cookies", + type: "checkbox", + value: "saveCookies", + checked: Firebug.saveCookies, + command: "saveOptions" + }, + "-", + { + label: "Start Opened", + type: "checkbox", + value: "startOpened", + checked: Firebug.startOpened, + disabled: cookiesDisabled + }, + { + label: "Start in New Window", + type: "checkbox", + value: "startInNewWindow", + checked: Firebug.startInNewWindow, + disabled: cookiesDisabled + }, + { + label: "Show Icon When Hidden", + type: "checkbox", + value: "showIconWhenHidden", + checked: Firebug.showIconWhenHidden, + disabled: cookiesDisabled + }, + { + label: "Override Console Object", + type: "checkbox", + value: "overrideConsole", + checked: Firebug.overrideConsole, + disabled: cookiesDisabled + }, + { + label: "Ignore Firebug Elements", + type: "checkbox", + value: "ignoreFirebugElements", + checked: Firebug.ignoreFirebugElements, + disabled: cookiesDisabled + }, + { + label: "Disable When Firebug Active", + type: "checkbox", + value: "disableWhenFirebugActive", + checked: Firebug.disableWhenFirebugActive, + disabled: cookiesDisabled + }, + { + label: "Disable XHR Listener", + type: "checkbox", + value: "disableXHRListener", + checked: Firebug.disableXHRListener, + disabled: cookiesDisabled + }, + { + label: "Enable Trace Mode", + type: "checkbox", + value: "enableTrace", + checked: Firebug.enableTrace, + disabled: cookiesDisabled + }, + { + label: "Enable Persistent Mode (experimental)", + type: "checkbox", + value: "enablePersistent", + checked: Firebug.enablePersistent, + disabled: cookiesDisabled + }, + "-", + { + label: "Reset All Firebug Options", + command: "restorePrefs", + disabled: cookiesDisabled + } + ]; + }, + + onCheck: function(target, value, checked) + { + Firebug.setPref(value, checked); + }, + + saveOptions: function(target) + { + var saveEnabled = target.getAttribute("checked"); + + if (!saveEnabled) this.restorePrefs(); + + this.updateMenu(target); + + return false; + }, + + restorePrefs: function(target) + { + Firebug.restorePrefs(); + + if(Firebug.saveCookies) + Firebug.savePrefs(); + else + Firebug.erasePrefs(); + + if (target) + this.updateMenu(target); + + return false; + }, + + updateMenu: function(target) + { + var options = getElementsByClass(target.parentNode, "fbMenuOption"); + + var firstOption = options[0]; + var enabled = Firebug.saveCookies; + if (enabled) + Menu.check(firstOption); + else + Menu.uncheck(firstOption); + + if (enabled) + Menu.check(options[0]); + else + Menu.uncheck(options[0]); + + for (var i = 1, length = options.length; i < length; i++) + { + var option = options[i]; + + var value = option.getAttribute("value"); + var pref = Firebug[value]; + + if (pref) + Menu.check(option); + else + Menu.uncheck(option); + + if (enabled) + Menu.enable(option); + else + Menu.disable(option); + } + } + }; + + Menu.register(firebugOptionsMenu); + + var menu = firebugMenu; + + var testMenuClick = function(event) + { + //console.log("testMenuClick"); + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + if (menu.isVisible) + menu.hide(); + else + { + var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position + + chrome = Firebug.chrome, + + box = chrome.getElementBox(target), + + offset = chrome.type == "div" ? + chrome.getElementPosition(chrome.node) : + {top: 0, left: 0}; + + menu.show( + box.left + offsetLeft - offset.left, + box.top + box.height -5 - offset.top + ); + } + + return false; + }; + + var iconButton = new IconButton({ + type: "toggle", + element: $("fbFirebugButton"), + + onClick: testMenuClick + }); + + iconButton.initialize(); + + //addEvent($("fbToolbarIcon"), "click", testMenuClick); + }, + + initialize: function() + { + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Env.bookmarkletOutdated) + Firebug.Console.logFormatted([ + "A new bookmarklet version is available. " + + "Please visit http://getfirebug.com/firebuglite#Install and update it." + ], Firebug.context, "warn"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Firebug.Console) + Firebug.Console.flush(); + + if (Firebug.Trace) + FBTrace.flush(Firebug.Trace); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize inherited classes + Controller.initialize.call(this); + PanelBar.initialize.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the interface elements cache + + fbTop = $("fbTop"); + fbContent = $("fbContent"); + fbContentStyle = fbContent.style; + fbBottom = $("fbBottom"); + fbBtnInspect = $("fbBtnInspect"); + + fbToolbar = $("fbToolbar"); + + fbPanelBox1 = $("fbPanelBox1"); + fbPanelBox1Style = fbPanelBox1.style; + fbPanelBox2 = $("fbPanelBox2"); + fbPanelBox2Style = fbPanelBox2.style; + fbPanelBar2Box = $("fbPanelBar2Box"); + fbPanelBar2BoxStyle = fbPanelBar2Box.style; + + fbHSplitter = $("fbHSplitter"); + fbVSplitter = $("fbVSplitter"); + fbVSplitterStyle = fbVSplitter.style; + + fbPanel1 = $("fbPanel1"); + fbPanel1Style = fbPanel1.style; + fbPanel2 = $("fbPanel2"); + fbPanel2Style = fbPanel2.style; + + fbConsole = $("fbConsole"); + fbConsoleStyle = fbConsole.style; + fbHTML = $("fbHTML"); + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + topHeight = fbTop.offsetHeight; + topPartialHeight = fbToolbar.offsetHeight; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + disableTextSelection($("fbToolbar")); + disableTextSelection($("fbPanelBarBox")); + disableTextSelection($("fbPanelBar1")); + disableTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6 + if (isIE6 && Firebug.Selector) + { + // TODO: xxxpedro change to getElementsByClass + var as = $$(".fbHover"); + for (var i=0, a; a=as[i]; i++) + { + a.setAttribute("href", "javascript:void(0)"); + } + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize all panels + /* + var panelMap = Firebug.panelTypes; + for (var i=0, p; p=panelMap[i]; i++) + { + if (!p.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + /**/ + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.initialize(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + this.addController( + [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine] + ); + + // ************************************************************************************************ + + // Select the first registered panel + // TODO: BUG IE7 + var self = this; + setTimeout(function(){ + self.selectPanel(FirebugChrome.selectedPanelName); + + if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine) + Firebug.chrome.focusCommandLine(); + },0); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + //this.draw(); + + + + + + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + var onPanelMouseDown = function onPanelMouseDown(event) + { + //console.log("onPanelMouseDown", event.target || event.srcElement, event); + + var target = event.target || event.srcElement; + + if (FBL.isLeftClick(event)) + { + var editable = FBL.getAncestorByClass(target, "editable"); + + // if an editable element has been clicked then start editing + if (editable) + { + Firebug.Editor.startEditing(editable); + FBL.cancelEvent(event); + } + // if any other element has been clicked then stop editing + else + { + if (!hasClass(target, "textEditorInner")) + Firebug.Editor.stopEditing(); + } + } + else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target)) + { + // Prevent auto-scroll when middle-clicking a rep object + FBL.cancelEvent(event); + } + }; + + Firebug.getElementPanel = function(element) + { + var panelNode = getAncestorByClass(element, "fbPanel"); + var id = panelNode.id.substr(2); + + var panel = Firebug.chrome.panelMap[id]; + + if (!panel) + { + if (Firebug.chrome.selectedPanel.sidePanelBar) + panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; + } + + return panel; + }; + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // TODO: xxxpedro port to Firebug + + // Improved window key code event listener. Only one "keydown" event will be attached + // to the window, and the onKeyCodeListen() function will delegate which listeners + // should be called according to the event.keyCode fired. + var onKeyCodeListenersMap = []; + var onKeyCodeListen = function(event) + { + for (var keyCode in onKeyCodeListenersMap) + { + var listeners = onKeyCodeListenersMap[keyCode]; + + for (var i = 0, listener; listener = listeners[i]; i++) + { + var filter = listener.filter || FBL.noKeyModifiers; + + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener.listener(); + FBL.cancelEvent(event, true); + return false; + } + } + } + }; + + addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); + + /** + * @name keyCodeListen + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + var keyCode = KeyEvent["DOM_VK_"+key]; + + if (!onKeyCodeListenersMap[keyCode]) + onKeyCodeListenersMap[keyCode] = []; + + onKeyCodeListenersMap[keyCode].push({ + filter: filter, + listener: listener + }); + + return keyCode; + }; + + /** + * @name keyIgnore + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyIgnore = function(keyCode) + { + onKeyCodeListenersMap[keyCode] = null; + delete onKeyCodeListenersMap[keyCode]; + }; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /**/ + // move to shutdown + //removeEvent(Firebug.chrome.document, "keydown", listener[0]); + + + /* + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + if (!filter) + filter = FBL.noKeyModifiers; + + var keyCode = KeyEvent["DOM_VK_"+key]; + + var fn = function fn(event) + { + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener(); + FBL.cancelEvent(event, true); + return false; + } + } + + addEvent(Firebug.chrome.document, "keydown", fn); + + return [fn, capture]; + }; + + Firebug.chrome.keyIgnore = function(listener) + { + removeEvent(Firebug.chrome.document, "keydown", listener[0]); + }; + /**/ + + + this.addController( + [fbPanel1, "mousedown", onPanelMouseDown], + [fbPanel2, "mousedown", onPanelMouseDown] + ); +/**/ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + + // menus can be used without domplate + if (FBL.domplate) + this.testMenu(); + /**/ + + //test XHR + /* + setTimeout(function(){ + + FBL.Ajax.request({url: "../content/firebug/boot.js"}); + FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); + + },1000); + /**/ + }, + + shutdown: function() + { + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.shutdown(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // remove disableTextSelection event handlers + restoreTextSelection($("fbToolbar")); + restoreTextSelection($("fbPanelBarBox")); + restoreTextSelection($("fbPanelBar1")); + restoreTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // shutdown inherited classes + Controller.shutdown.call(this); + PanelBar.shutdown.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Remove the interface elements cache (this must happen after calling + // the shutdown method of all dependent components to avoid errors) + + fbTop = null; + fbContent = null; + fbContentStyle = null; + fbBottom = null; + fbBtnInspect = null; + + fbToolbar = null; + + fbPanelBox1 = null; + fbPanelBox1Style = null; + fbPanelBox2 = null; + fbPanelBox2Style = null; + fbPanelBar2Box = null; + fbPanelBar2BoxStyle = null; + + fbHSplitter = null; + fbVSplitter = null; + fbVSplitterStyle = null; + + fbPanel1 = null; + fbPanel1Style = null; + fbPanel2 = null; + + fbConsole = null; + fbConsoleStyle = null; + fbHTML = null; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + + topHeight = null; + topPartialHeight = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + toggle: function(forceOpen, popup) + { + if(popup) + { + this.detach(); + } + else + { + if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) + { + var frame = FirebugChrome.chromeMap.frame; + frame.reattach(); + + FirebugChrome.chromeMap.popup = null; + + frame.open(); + + return; + } + + // If the context is a popup, ignores the toggle process + if (Firebug.chrome.type == "popup") return; + + var shouldOpen = forceOpen || !FirebugChrome.isOpen; + + if(shouldOpen) + this.open(); + else + this.close(); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + detach: function() + { + if(!FirebugChrome.chromeMap.popup) + { + createChromeWindow({type: "popup"}); + } + }, + + reattach: function(oldChrome, newChrome) + { + Firebug.browser.window.Firebug = Firebug; + + // chrome synchronization + var newPanelMap = newChrome.panelMap; + var oldPanelMap = oldChrome.panelMap; + + var panel; + for(var name in newPanelMap) + { + // TODO: xxxpedro innerHTML + panel = newPanelMap[name]; + if (panel.options.innerHTMLSync) + panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; + } + + Firebug.chrome = newChrome; + + // TODO: xxxpedro sync detach reattach attach + //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); + + if (newChrome.type == "popup") + { + newChrome.initialize(); + //dispatch(Firebug.modules, "initialize", []); + } + else + { + // TODO: xxxpedro only needed in persistent + // should use FirebugChrome.clone, but popup FBChrome + // isn't acessible + FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name; + } + + dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + draw: function() + { + var size = this.getSize(); + + // Height related values + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, + + y = Math.max(size.height /* chrome height */, topHeight), + + heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), + + height = heightValue + "px", + + // Width related values + sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0, + + width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Height related rendering + fbPanelBox1Style.height = height; + fbPanel1Style.height = height; + + if (isIE || isOpera) + { + // Fix IE and Opera problems with auto resizing the verticall splitter + fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px"; + } + //xxxpedro FF2 only? + /* + else if (isFirefox) + { + // Fix Firefox problem with table rows with 100% height (fit height) + fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px"; + }/**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Width related rendering + fbPanelBox1Style.width = width; + fbPanel1Style.width = width; + + // SidePanel rendering + if (Firebug.chrome.sidePanelVisible) + { + sideWidthValue = Math.max(sideWidthValue - 6, 0); + + var sideWidth = sideWidthValue + "px"; + + fbPanelBox2Style.width = sideWidth; + + fbVSplitterStyle.right = sideWidth; + + if (Firebug.chrome.largeCommandLineVisible) + { + fbLargeCommandLine = $("fbLargeCommandLine"); + + fbLargeCommandLine.style.height = heightValue - 4 + "px"; + fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; + + fbLargeCommandButtons = $("fbLargeCommandButtons"); + fbLargeCommandButtons.style.width = sideWidth; + } + else + { + fbPanel2Style.height = height; + fbPanel2Style.width = sideWidth; + + fbPanelBar2BoxStyle.width = sideWidth; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getSize: function() + { + return this.type == "div" ? + { + height: this.node.offsetHeight, + width: this.node.offsetWidth + } + : + this.getWindowSize(); + }, + + resize: function() + { + var self = this; + + // avoid partial resize when maximizing window + setTimeout(function(){ + self.draw(); + + if (noFixedPosition && (self.type == "frame" || self.type == "div")) + self.fixIEPosition(); + }, 0); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + layout: function(panel) + { + if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); + + var options = panel.options; + + changeCommandLineVisibility(options.hasCommandLine); + changeSidePanelVisibility(panel.hasSidePanel); + + Firebug.chrome.draw(); + }, + + showLargeCommandLine: function(hideToggleIcon) + { + var chrome = Firebug.chrome; + + if (!chrome.largeCommandLineVisible) + { + chrome.largeCommandLineVisible = true; + + if (chrome.selectedPanel.options.hasCommandLine) + { + if (Firebug.CommandLine) + Firebug.CommandLine.blur(); + + changeCommandLineVisibility(false); + } + + changeSidePanelVisibility(true); + + fbLargeCommandLine.style.display = "block"; + fbLargeCommandButtons.style.display = "block"; + + fbPanel2Style.display = "none"; + fbPanelBar2BoxStyle.display = "none"; + + chrome.draw(); + + fbLargeCommandLine.focus(); + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(true); + } + }, + + hideLargeCommandLine: function() + { + if (Firebug.chrome.largeCommandLineVisible) + { + Firebug.chrome.largeCommandLineVisible = false; + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(false); + + fbLargeCommandLine.blur(); + + fbPanel2Style.display = "block"; + fbPanelBar2BoxStyle.display = "block"; + + fbLargeCommandLine.style.display = "none"; + fbLargeCommandButtons.style.display = "none"; + + changeSidePanelVisibility(false); + + if (Firebug.chrome.selectedPanel.options.hasCommandLine) + changeCommandLineVisibility(true); + + Firebug.chrome.draw(); + + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLine: function() + { + var selectedPanelName = this.selectedPanel.name, panelToSelect; + + if (focusCommandLineState == 0 || selectedPanelName != "Console") + { + focusCommandLineState = 0; + lastFocusedPanelName = selectedPanelName; + + panelToSelect = "Console"; + } + if (focusCommandLineState == 1) + { + panelToSelect = lastFocusedPanelName; + } + + this.selectPanel(panelToSelect); + + try + { + if (Firebug.CommandLine) + { + if (panelToSelect == "Console") + Firebug.CommandLine.focus(); + else + Firebug.CommandLine.blur(); + } + } + catch(e) + { + //TODO: xxxpedro trace error + } + + focusCommandLineState = ++focusCommandLineState % 2; + } + +}); + +// ************************************************************************************************ +// ChromeFrameBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromeFrameBase = extend(ChromeBase, +/**@extend ns-chrome-ChromeFrameBase*/ +{ + create: function() + { + ChromeBase.create.call(this); + + // restore display for the anti-flicker trick + if (isFirefox) + this.node.style.display = "block"; + + if (Env.Options.startInNewWindow) + { + this.close(); + this.toggle(true, true); + return; + } + + if (Env.Options.startOpened) + this.open(); + else + this.close(); + }, + + destroy: function() + { + removeGlobalEvent("keydown", onGlobalKeyDown); + + ChromeBase.destroy.call(this); + + this.document = null; + delete this.document; + + this.window = null; + delete this.window; + + this.node.parentNode.removeChild(this.node); + this.node = null; + delete this.node; + }, + + initialize: function() + { + //FBTrace.sysout("Frame", "initialize();") + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.browser.window, "resize", this.resize], + [$("fbWindow_btClose"), "click", this.close], + [$("fbWindow_btDetach"), "click", this.detach], + [$("fbWindow_btDeactivate"), "click", this.deactivate] + ); + + if (!Env.Options.enablePersistent) + this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + fbVSplitter.onmousedown = onVSplitterMouseDown; + fbHSplitter.onmousedown = onHSplitterMouseDown; + + this.isInitialized = true; + }, + + shutdown: function() + { + fbVSplitter.onmousedown = null; + fbHSplitter.onmousedown = null; + + ChromeBase.shutdown.apply(this); + + this.isInitialized = false; + }, + + reattach: function() + { + var frame = FirebugChrome.chromeMap.frame; + + ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); + }, + + open: function() + { + if (!FirebugChrome.isOpen) + { + FirebugChrome.isOpen = true; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,1"); + + var node = this.node; + + node.style.visibility = "hidden"; // Avoid flickering + + if (Firebug.showIconWhenHidden) + { + if (ChromeMini.isInitialized) + { + ChromeMini.shutdown(); + } + + } + else + node.style.display = "block"; + + var main = $("fbChrome"); + + // IE6 throws an error when setting this property! why? + //main.style.display = "table"; + main.style.display = ""; + + var self = this; + setTimeout(function(){ + node.style.visibility = "visible"; + + //dispatch(Firebug.modules, "initialize", []); + self.initialize(); + + if (noFixedPosition) + self.fixIEPosition(); + + self.draw(); + + }, 10); + } + }, + + close: function() + { + if (FirebugChrome.isOpen || !this.isInitialized) + { + if (this.isInitialized) + { + //dispatch(Firebug.modules, "shutdown", []); + this.shutdown(); + } + + FirebugChrome.isOpen = false; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,0"); + + var node = this.node; + + if (Firebug.showIconWhenHidden) + { + node.style.visibility = "hidden"; // Avoid flickering + + // TODO: xxxpedro - persist IE fixed? + var main = $("fbChrome", FirebugChrome.chromeMap.frame.document); + main.style.display = "none"; + + ChromeMini.initialize(); + + node.style.visibility = "visible"; + } + else + node.style.display = "none"; + } + }, + + deactivate: function() + { + // if it is running as a Chrome extension, dispatch a message to the extension signaling + // that Firebug should be deactivated for the current tab + if (Env.isChromeExtension) + { + localStorage.removeItem("Firebug"); + Firebug.GoogleChrome.dispatch("FB_deactivate"); + + // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole + // app, otherwise it won't be able to be reactivated without reloading the page. + // but we need to stop listening global keys, otherwise the key activation won't work. + Firebug.chrome.close(); + } + else + { + Firebug.shutdown(); + } + }, + + fixIEPosition: function() + { + // fix IE problem with offset when not in fullscreen mode + var doc = this.document; + var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0; + + var size = Firebug.browser.getWindowSize(); + var scroll = Firebug.browser.getWindowScrollPosition(); + var maxHeight = size.height; + var height = this.node.offsetHeight; + + var bodyStyle = doc.body.currentStyle; + + this.node.style.top = maxHeight - height + scroll.top + "px"; + + if ((this.type == "frame" || this.type == "div") && + (bodyStyle.marginLeft || bodyStyle.marginRight)) + { + this.node.style.width = size.width + "px"; + } + + if (fbVSplitterStyle) + fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px"; + + this.draw(); + } + +}); + + +// ************************************************************************************************ +// ChromeMini + +/** + * @namespace + * @extends FBL.Controller + */ +var ChromeMini = extend(Controller, +/**@extend ns-chrome-ChromeMini*/ +{ + create: function(chrome) + { + append(this, chrome); + this.type = "mini"; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "block"; + + var miniIcon = $("fbMiniIcon", doc); + var width = miniIcon.offsetWidth + 10; + miniIcon.title = "Open " + Firebug.version; + + var errors = $("fbMiniErrors", doc); + if (errors.offsetWidth) + width += errors.offsetWidth + 10; + + var node = this.node; + node.style.height = "27px"; + node.style.width = width + "px"; + node.style.left = ""; + node.style.right = 0; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "true"); + this.document.body.style.backgroundColor = "transparent"; + } + else + node.style.background = "transparent"; + + if (noFixedPosition) + this.fixIEPosition(); + + this.addController( + [$("fbMiniIcon", doc), "click", onMiniIconClick] + ); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + this.isInitialized = true; + }, + + shutdown: function() + { + var node = this.node; + node.style.height = FirebugChrome.height + "px"; + node.style.width = "100%"; + node.style.left = 0; + node.style.right = ""; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "false"); + this.document.body.style.backgroundColor = "#fff"; + } + else + node.style.background = "#fff"; + + if (noFixedPosition) + this.fixIEPosition(); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "none"; + + Controller.shutdown.apply(this); + + this.isInitialized = false; + }, + + draw: function() + { + + }, + + fixIEPosition: ChromeFrameBase.fixIEPosition + +}); + + +// ************************************************************************************************ +// ChromePopupBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromePopupBase = extend(ChromeBase, +/**@extend ns-chrome-ChromePopupBase*/ +{ + + initialize: function() + { + setClass(this.document.body, "FirebugPopup"); + + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.chrome.window, "resize", this.resize], + [Firebug.chrome.window, "unload", this.destroy] + ); + + if (Env.Options.enablePersistent) + { + this.persist = bind(this.persist, this); + addEvent(Firebug.browser.window, "unload", this.persist); + } + else + this.addController( + [Firebug.browser.window, "unload", this.close] + ); + + fbVSplitter.onmousedown = onVSplitterMouseDown; + }, + + destroy: function() + { + // TODO: xxxpedro sync detach reattach attach + var frame = FirebugChrome.chromeMap.frame; + + if(frame) + { + dispatch(frame.panelMap, "detach", [this, frame]); + + frame.reattach(this, frame); + } + + if (Env.Options.enablePersistent) + { + removeEvent(Firebug.browser.window, "unload", this.persist); + } + + ChromeBase.destroy.apply(this); + + FirebugChrome.chromeMap.popup = null; + + this.node.close(); + }, + + persist: function() + { + persistTimeStart = new Date().getTime(); + + removeEvent(Firebug.browser.window, "unload", this.persist); + + Firebug.Inspector.destroy(); + Firebug.browser.window.FirebugOldBrowser = true; + + var persistTimeStart = new Date().getTime(); + + var waitMainWindow = function() + { + var doc, head; + + try + { + if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && + doc.documentElement && (head = doc.documentElement.firstChild)*/) + { + + try + { + // exposes the FBL to the global namespace when in debug mode + if (Env.isDebugMode) + { + window.FBL = FBL; + } + + window.Firebug = Firebug; + window.opener.Firebug = Firebug; + + Env.browser = window.opener; + Firebug.browser = Firebug.context = new Context(Env.browser); + + registerConsole(); + + // the delay time should be calculated right after registering the + // console, once right after the console registration, call log messages + // will be properly handled + var persistDelay = new Date().getTime() - persistTimeStart; + + var chrome = Firebug.chrome; + addEvent(Firebug.browser.window, "unload", chrome.persist); + + FBL.cacheDocument(); + Firebug.Inspector.create(); + + var htmlPanel = chrome.getPanel("HTML"); + htmlPanel.createUI(); + + Firebug.Console.logFormatted( + ["Firebug could not capture console calls during " + + persistDelay + "ms"], + Firebug.context, + "info" + ); + } + catch(pE) + { + alert("persist error: " + (pE.message || pE)); + } + + } + else + { + window.setTimeout(waitMainWindow, 0); + } + + } catch (E) { + window.close(); + } + }; + + waitMainWindow(); + }, + + close: function() + { + this.destroy(); + } + +}); + + +//************************************************************************************************ +// UI helpers + +var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) +{ + var last = Firebug.chrome.commandLineVisible; + var visible = Firebug.chrome.commandLineVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; + + if (visible != last) + { + if (visible) + { + fbBottom.className = ""; + + if (Firebug.CommandLine) + Firebug.CommandLine.activate(); + } + else + { + if (Firebug.CommandLine) + Firebug.CommandLine.deactivate(); + + fbBottom.className = "hide"; + } + } +}; + +var changeSidePanelVisibility = function changeSidePanelVisibility(visibility) +{ + var last = Firebug.chrome.sidePanelVisible; + Firebug.chrome.sidePanelVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible; + + if (Firebug.chrome.sidePanelVisible != last) + { + fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + } +}; + + +// ************************************************************************************************ +// F12 Handler + +var onGlobalKeyDown = function onGlobalKeyDown(event) +{ + var keyCode = event.keyCode; + var shiftKey = event.shiftKey; + var ctrlKey = event.ctrlKey; + + if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox)) + { + Firebug.chrome.toggle(false, ctrlKey); + cancelEvent(event, true); + + // TODO: xxxpedro replace with a better solution. we're doing this + // to allow reactivating with the F12 key after being deactivated + if (Env.isChromeExtension) + { + Firebug.GoogleChrome.dispatch("FB_enableIcon"); + } + } + else if (keyCode == 67 /* C */ && ctrlKey && shiftKey) + { + Firebug.Inspector.toggleInspect(); + cancelEvent(event, true); + } + else if (keyCode == 76 /* L */ && ctrlKey && shiftKey) + { + Firebug.chrome.focusCommandLine(); + cancelEvent(event, true); + } +}; + +var onMiniIconClick = function onMiniIconClick(event) +{ + Firebug.chrome.toggle(false, event.ctrlKey); + cancelEvent(event, true); +}; + + +// ************************************************************************************************ +// Horizontal Splitter Handling + +var onHSplitterMouseDown = function onHSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onHSplitterMouseMove); + addGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = "fbOnMovingHSplitter"; + + return false; +}; + +var onHSplitterMouseMove = function onHSplitterMouseMove(event) +{ + cancelEvent(event, true); + + var clientY = event.clientY; + var win = isIE + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument && event.target.ownerDocument.defaultView; + + if (!win) + return; + + if (win != win.parent) + { + var frameElement = win.frameElement; + if (frameElement) + { + var framePos = Firebug.browser.getElementPosition(frameElement).top; + clientY += framePos; + + if (frameElement.style.position != "fixed") + clientY -= Firebug.browser.getWindowScrollPosition().top; + } + } + + if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI") + { + clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY; + } + /* + console.log( + typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome", + //win.frameElement.id, + event.target, + clientY + );/**/ + + onHSplitterMouseMoveBuffer = clientY; // buffer + + if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + lastHSplitterMouseMove = new Date().getTime(); + handleHSplitterMouseMove(); + } + else + if (!onHSplitterMouseMoveTimer) + onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate); + + // improving the resizing performance by canceling the mouse event. + // canceling events will prevent the page to receive such events, which would imply + // in more processing being expended. + cancelEvent(event, true); + return false; +}; + +var handleHSplitterMouseMove = function() +{ + if (onHSplitterMouseMoveTimer) + { + clearTimeout(onHSplitterMouseMoveTimer); + onHSplitterMouseMoveTimer = null; + } + + var clientY = onHSplitterMouseMoveBuffer; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + + // compute chrome fixed size (top bar and command line) + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0; + var fixedHeight = topHeight + commandLineHeight; + var chromeNode = Firebug.chrome.node; + + var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; + + //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; + var height = windowSize.height; + + // compute the min and max size of the chrome + var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight); + chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize); + + FirebugChrome.height = chromeHeight; + chromeNode.style.height = chromeHeight + "px"; + + if (noFixedPosition) + Firebug.chrome.fixIEPosition(); + + Firebug.chrome.draw(); +}; + +var onHSplitterMouseUp = function onHSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onHSplitterMouseMove); + removeGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = ""; + + Firebug.chrome.draw(); + + // avoid text selection in IE when returning to the document + // after the mouse leaves the document during the resizing + return false; +}; + + +// ************************************************************************************************ +// Vertical Splitter Handling + +var onVSplitterMouseDown = function onVSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onVSplitterMouseMove); + addGlobalEvent("mouseup", onVSplitterMouseUp); + + return false; +}; + +var onVSplitterMouseMove = function onVSplitterMouseMove(event) +{ + if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + var target = event.target || event.srcElement; + if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome + { + var clientX = event.clientX; + var win = document.all + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument.defaultView; + + if (win != win.parent) + clientX += win.frameElement ? win.frameElement.offsetLeft : 0; + + var size = Firebug.chrome.getSize(); + var x = Math.max(size.width - clientX + 3, 6); + + FirebugChrome.sidePanelWidth = x; + Firebug.chrome.draw(); + } + + lastVSplitterMouseMove = new Date().getTime(); + } + + cancelEvent(event, true); + return false; +}; + +var onVSplitterMouseUp = function onVSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onVSplitterMouseMove); + removeGlobalEvent("mouseup", onVSplitterMouseUp); + + Firebug.chrome.draw(); +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Browser = function(window) +{ + this.contentWindow = window; + this.contentDocument = window.document; + this.currentURI = + { + spec: window.location.href + }; +}; + +Firebug.Lite.Browser.prototype = +{ + toString: function() + { + return "Firebug.Lite.Browser"; + } +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Cache = +{ + ID: "firebug" + new Date().getTime() +}; + +// ************************************************************************************************ + +/** + * TODO: if a cached element is cloned, the expando property will be cloned too in IE + * which will result in a bug. Firebug Lite will think the new cloned node is the old + * one. + * + * TODO: Investigate a possibility of cache validation, to be customized by each + * kind of cache. For ElementCache it should validate if the element still is + * inserted at the DOM. + */ +var cacheUID = 0; +var createCache = function() +{ + var map = {}; + var CID = Firebug.Lite.Cache.ID; + + // better detection + var supportsDeleteExpando = !document.all; + + var cacheFunction = function(element) + { + return cacheAPI.set(element); + }; + + var cacheAPI = + { + get: function(key) + { + return map.hasOwnProperty(key) ? + map[key] : + null; + }, + + set: function(element) + { + var id = element[CID]; + + if (!id) + { + id = ++cacheUID; + element[CID] = id; + } + + if (!map.hasOwnProperty(id)) + { + map[id] = element; + } + + return id; + }, + + unset: function(element) + { + var id = element[CID]; + + if (supportsDeleteExpando) + { + delete element[CID]; + } + else if (element.removeAttribute) + { + element.removeAttribute(CID); + } + + delete map[id]; + + }, + + key: function(element) + { + return element[CID]; + }, + + has: function(element) + { + return map.hasOwnProperty(element[CID]); + }, + + clear: function() + { + for (var id in map) + { + var element = map[id]; + cacheAPI.unset(element); + } + } + }; + + FBL.append(cacheFunction, cacheAPI); + + return cacheFunction; +}; + +// ************************************************************************************************ + +// TODO: xxxpedro : check if we need really this on FBL scope +Firebug.Lite.Cache.StyleSheet = createCache(); +Firebug.Lite.Cache.Element = createCache(); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Proxy = +{ + // jsonp callbacks + _callbacks: {}, + + /** + * Load a resource, either locally (directly) or externally (via proxy) using + * synchronous XHR calls. Loading external resources requires the proxy plugin to + * be installed and configured (see /plugin/proxy/proxy.php). + */ + load: function(url) + { + var resourceDomain = getDomain(url); + var isLocalResource = + // empty domain means local URL + !resourceDomain || + // same domain means local too + resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context + + return isLocalResource ? fetchResource(url) : fetchProxyResource(url); + }, + + /** + * Load a resource using JSONP technique. + */ + loadJSONP: function(url, callback) + { + var script = createGlobalElement("script"), + doc = Firebug.context.document, + + uid = "" + new Date().getTime(), + callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, + + jsonpURL = url.indexOf("?") != -1 ? + url + "&" + callbackName : + url + "?" + callbackName; + + Firebug.Lite.Proxy._callbacks[uid] = function(data) + { + if (callback) + callback(data); + + script.parentNode.removeChild(script); + delete Firebug.Lite.Proxy._callbacks[uid]; + }; + + script.src = jsonpURL; + + if (doc.documentElement) + doc.documentElement.appendChild(script); + }, + + /** + * Load a resource using YQL (not reliable). + */ + YQL: function(url, callback) + { + var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + + encodeURIComponent(url) + "%22&format=xml"; + + this.loadJSONP(yql, function(data) + { + var source = data.results[0]; + + // clean up YQL bogus elements + var match = /\s+

      ([\s\S]+)<\/p>\s+<\/body>$/.exec(source); + if (match) + source = match[1]; + + console.log(source); + }); + } +}; + +// ************************************************************************************************ + +var fetchResource = function(url) +{ + var xhr = FBL.Ajax.getXHRObject(); + xhr.open("get", url, false); + xhr.send(); + + return xhr.responseText; +}; + +var fetchProxyResource = function(url) +{ + var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); + var response = fetchResource(proxyURL); + + try + { + var data = eval("(" + response + ")"); + } + catch(E) + { + return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; + } + + return data ? data.contents : ""; +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Script = function(window) +{ + this.fileName = null; + this.isValid = null; + this.baseLineNumber = null; + this.lineExtent = null; + this.tag = null; + + this.functionName = null; + this.functionSource = null; +}; + +Firebug.Lite.Script.prototype = +{ + isLineExecutable: function(){}, + pcToLine: function(){}, + lineToPc: function(){}, + + toString: function() + { + return "Firebug.Lite.Script"; + } +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Style = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-selector*/ function() { with (FBL) { +// ************************************************************************************************ + +/* + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +/** + * @name Firebug.Selector + * @namespace + */ + +/** + * @exports Sizzle as Firebug.Selector + */ +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +/**#@+ @ignore */ +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + if ( div.getElementsByClassName("e").length === 0 ) + return; + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE + +Firebug.Selector = Sizzle; + +/**#@-*/ + +// ************************************************************************************************ +}}); + +// Problems in IE +// FIXED - eval return +// FIXED - addEventListener problem in IE +// FIXED doc.createRange? +// +// class reserved word +// test all honza examples in IE6 and IE7 + + +/* See license.txt for terms of usage */ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function DomplateTag(tagName) +{ + this.tagName = tagName; +} + +function DomplateEmbed() +{ +} + +function DomplateLoop() +{ +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +( /** @scope ns-domplate */ function() { + +var womb = null; + +var domplate = FBL.domplate = function() +{ + var lastSubject; + for (var i = 0; i < arguments.length; ++i) + lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i]; + + for (var name in lastSubject) + { + var val = lastSubject[name]; + if (isTag(val)) + val.tag.subject = lastSubject; + } + + return lastSubject; +}; + +domplate.context = function(context, fn) +{ + var lastContext = domplate.lastContext; + domplate.topContext = context; + fn.apply(context); + domplate.topContext = lastContext; +}; + +FBL.TAG = function() +{ + var embed = new DomplateEmbed(); + return embed.merge(arguments); +}; + +FBL.FOR = function() +{ + var loop = new DomplateLoop(); + return loop.merge(arguments); +}; + +DomplateTag.prototype = +{ + merge: function(args, oldTag) + { + if (oldTag) + this.tagName = oldTag.tagName; + + this.context = oldTag ? oldTag.context : null; + this.subject = oldTag ? oldTag.subject : null; + this.attrs = oldTag ? copyObject(oldTag.attrs) : {}; + this.classes = oldTag ? copyObject(oldTag.classes) : {}; + this.props = oldTag ? copyObject(oldTag.props) : null; + this.listeners = oldTag ? copyArray(oldTag.listeners) : null; + this.children = oldTag ? copyArray(oldTag.children) : []; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args.length ? args[0] : null; + var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); + + this.children = []; + + if (domplate.topContext) + this.context = domplate.topContext; + + if (args.length) + parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); + + if (hasAttrs) + this.parseAttrs(attrs); + + return creator(this, DomplateTag); + }, + + parseAttrs: function(args) + { + for (var name in args) + { + var val = parseValue(args[name]); + readPartNames(val, this.vars); + + if (name.indexOf("on") == 0) + { + var eventName = name.substr(2); + if (!this.listeners) + this.listeners = []; + this.listeners.push(eventName, val); + } + else if (name.indexOf("_") == 0) + { + var propName = name.substr(1); + if (!this.props) + this.props = {}; + this.props[propName] = val; + } + else if (name.indexOf("$") == 0) + { + var className = name.substr(1); + if (!this.classes) + this.classes = {}; + this.classes[className] = val; + } + else + { + if (name == "class" && this.attrs.hasOwnProperty(name) ) + this.attrs[name] += " " + val; + else + this.attrs[name] = val; + } + } + }, + + compile: function() + { + if (this.renderMarkup) + return; + + this.compileMarkup(); + this.compileDOM(); + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs); + }, + + compileMarkup: function() + { + this.markupArgs = []; + var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; + + this.generateMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + + var fnBlock = ['r=(function (__code__, __context__, __in__, __out__']; + for (var i = 0; i < info.argIndex; ++i) + fnBlock.push(', s', i); + fnBlock.push(') {'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (__context__) {'); + fnBlock.push('with (__in__) {'); + + fnBlock.push.apply(fnBlock, blocks); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('}})'); + + function __link__(tag, code, outputs, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var tagOutputs = []; + var markupArgs = [code, tag.tag.context, args, tagOutputs]; + markupArgs.push.apply(markupArgs, tag.tag.markupArgs); + tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs); + + outputs.push(tag); + outputs.push(tagOutputs); + } + + function __escape__(value) + { + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); + } + + function __loop__(iter, outputs, fn) + { + var iterOuts = []; + outputs.push(iterOuts); + + if (iter instanceof Array) + iter = new ArrayIterator(iter); + + try + { + while (1) + { + var value = iter.next(); + var itemOuts = [0,0]; + iterOuts.push(itemOuts); + fn.apply(this, [value, itemOuts]); + } + } + catch (exc) + { + if (exc != StopIteration) + throw exc; + } + } + + var js = fnBlock.join(""); + var r = null; + eval(js); + this.renderMarkup = r; + }, + + getVarNames: function(args) + { + if (this.vars) + args.push.apply(args, this.vars); + + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.getVarNames(args); + else if (child instanceof Parts) + { + for (var i = 0; i < child.parts.length; ++i) + { + if (child.parts[i] instanceof Variable) + { + var name = child.parts[i].name; + var names = name.split("."); + args.push(names[0]); + } + } + } + } + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + topBlock.push(',"<', this.tagName, '"'); + + for (var name in this.attrs) + { + if (name != "class") + { + var val = this.attrs[name]; + topBlock.push(', " ', name, '=\\""'); + addParts(val, ',', topBlock, info, true); + topBlock.push(', "\\""'); + } + } + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + readPartNames(this.listeners[i+1], topOuts); + } + + if (this.props) + { + for (var name in this.props) + readPartNames(this.props[name], topOuts); + } + + if ( this.attrs.hasOwnProperty("class") || this.classes) + { + topBlock.push(', " class=\\""'); + if (this.attrs.hasOwnProperty("class")) + addParts(this.attrs["class"], ',', topBlock, info, true); + topBlock.push(', " "'); + for (var name in this.classes) + { + topBlock.push(', ('); + addParts(this.classes[name], '', topBlock, info); + topBlock.push(' ? "', name, '" + " " : "")'); + } + topBlock.push(', "\\""'); + } + topBlock.push(',">"'); + + this.generateChildMarkup(topBlock, topOuts, blocks, info); + topBlock.push(',""'); + }, + + generateChildMarkup: function(topBlock, topOuts, blocks, info) + { + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.generateMarkup(topBlock, topOuts, blocks, info); + else + addParts(child, ',', topBlock, info, true); + } + }, + + addCode: function(topBlock, topOuts, blocks) + { + if (topBlock.length) + blocks.push('__code__.push(""', topBlock.join(""), ');'); + if (topOuts.length) + blocks.push('__out__.push(', topOuts.join(","), ');'); + topBlock.splice(0, topBlock.length); + topOuts.splice(0, topOuts.length); + }, + + addLocals: function(blocks) + { + var varNames = []; + this.getVarNames(varNames); + + var map = {}; + for (var i = 0; i < varNames.length; ++i) + { + var name = varNames[i]; + if ( map.hasOwnProperty(name) ) + continue; + + map[name] = 1; + var names = name.split("."); + blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); + } + }, + + compileDOM: function() + { + var path = []; + var blocks = []; + this.domArgs = []; + path.embedIndex = 0; + path.loopIndex = 0; + path.staticIndex = 0; + path.renderIndex = 0; + var nodeCount = this.generateDOM(path, blocks, this.domArgs); + + var fnBlock = ['r=(function (root, context, o']; + + for (var i = 0; i < path.staticIndex; ++i) + fnBlock.push(', ', 's'+i); + + for (var i = 0; i < path.renderIndex; ++i) + fnBlock.push(', ', 'd'+i); + + fnBlock.push(') {'); + for (var i = 0; i < path.loopIndex; ++i) + fnBlock.push('var l', i, ' = 0;'); + for (var i = 0; i < path.embedIndex; ++i) + fnBlock.push('var e', i, ' = 0;'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (context) {'); + + fnBlock.push(blocks.join("")); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('return ', nodeCount, ';'); + fnBlock.push('})'); + + function __bind__(object, fn) + { + return function(event) { return fn.apply(object, [event]); }; + } + + function __link__(node, tag, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var domArgs = [node, tag.tag.context, 0]; + domArgs.push.apply(domArgs, tag.tag.domArgs); + domArgs.push.apply(domArgs, args); + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs); + return tag.tag.renderDOM.apply(tag.tag.subject, domArgs); + } + + var self = this; + function __loop__(iter, fn) + { + var nodeCount = 0; + for (var i = 0; i < iter.length; ++i) + { + iter[i][0] = i; + iter[i][1] = nodeCount; + nodeCount += fn.apply(this, iter[i]); + //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount); + } + return nodeCount; + } + + function __path__(parent, offset) + { + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); + var root = parent; + + for (var i = 2; i < arguments.length; ++i) + { + var index = arguments[i]; + if (i == 3) + index += offset; + + if (index == -1) + parent = parent.parentNode; + else + parent = parent.childNodes[index]; + } + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); + return parent; + } + + var js = fnBlock.join(""); + //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); + var r = null; + eval(js); + this.renderDOM = r; + }, + + generateDOM: function(path, blocks, args) + { + if (this.listeners || this.props) + this.generateNodePath(path, blocks); + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + { + var val = this.listeners[i+1]; + var arg = generateArg(val, path, args); + //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + } + } + + if (this.props) + { + for (var name in this.props) + { + var val = this.props[name]; + var arg = generateArg(val, path, args); + blocks.push('node.', name, ' = ', arg, ';'); + } + } + + this.generateChildDOM(path, blocks, args); + return 1; + }, + + generateNodePath: function(path, blocks) + { + blocks.push("var node = __path__(root, o"); + for (var i = 0; i < path.length; ++i) + blocks.push(",", path[i]); + blocks.push(");"); + }, + + generateChildDOM: function(path, blocks, args) + { + path.push(0); + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args); + else + path[path.length-1] += '+1'; + } + path.pop(); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateEmbed.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.value = oldTag ? oldTag.value : parseValue(args[0]); + this.attrs = oldTag ? oldTag.attrs : {}; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args[1]; + for (var name in attrs) + { + var val = parseValue(attrs[name]); + this.attrs[name] = val; + readPartNames(val, this.vars); + } + + return creator(this, DomplateEmbed); + }, + + getVarNames: function(names) + { + if (this.value instanceof Parts) + names.push(this.value.parts[0].name); + + if (this.vars) + names.push.apply(names, this.vars); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + blocks.push('__link__('); + addParts(this.value, '', blocks, info); + blocks.push(', __code__, __out__, {'); + + var lastName = null; + for (var name in this.attrs) + { + if (lastName) + blocks.push(','); + lastName = name; + + var val = this.attrs[name]; + blocks.push('"', name, '":'); + addParts(val, '', blocks, info); + } + + blocks.push('});'); + //this.generateChildMarkup(topBlock, topOuts, blocks, info); + }, + + generateDOM: function(path, blocks, args) + { + var embedName = 'e'+path.embedIndex++; + + this.generateNodePath(path, blocks); + + var valueName = 'd' + path.renderIndex++; + var argsName = 'd' + path.renderIndex++; + blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); + + return embedName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateLoop.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.varName = oldTag ? oldTag.varName : args[0]; + this.iter = oldTag ? oldTag.iter : parseValue(args[1]); + this.vars = []; + + this.children = oldTag ? copyArray(oldTag.children) : []; + + var offset = Math.min(args.length, 2); + parseChildren(args, offset, this.vars, this.children); + + return creator(this, DomplateLoop); + }, + + getVarNames: function(names) + { + if (this.iter instanceof Parts) + names.push(this.iter.parts[0].name); + + DomplateTag.prototype.getVarNames.apply(this, [names]); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + var iterName; + if (this.iter instanceof Parts) + { + var part = this.iter.parts[0]; + iterName = part.name; + + if (part.format) + { + for (var i = 0; i < part.format.length; ++i) + iterName = part.format[i] + "(" + iterName + ")"; + } + } + else + iterName = this.iter; + + blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {'); + this.generateChildMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + blocks.push('}]);'); + }, + + generateDOM: function(path, blocks, args) + { + var iterName = 'd'+path.renderIndex++; + var counterName = 'i'+path.loopIndex; + var loopName = 'l'+path.loopIndex++; + + if (!path.length) + path.push(-1, 0); + + var preIndex = path.renderIndex; + path.renderIndex = 0; + + var nodeCount = 0; + + var subBlocks = []; + var basePath = path[path.length-1]; + for (var i = 0; i < this.children.length; ++i) + { + path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount; + + var child = this.children[i]; + if (isTag(child)) + nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args); + else + nodeCount += '+1'; + } + + path[path.length-1] = basePath+'+'+loopName; + + blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName); + for (var i = 0; i < path.renderIndex; ++i) + blocks.push(',d'+i); + blocks.push(') {'); + blocks.push(subBlocks.join("")); + blocks.push('return ', nodeCount, ';'); + blocks.push('}]);'); + + path.renderIndex = preIndex; + + return loopName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function Variable(name, format) +{ + this.name = name; + this.format = format; +} + +function Parts(parts) +{ + this.parts = parts; +} + +// ************************************************************************************************ + +function parseParts(str) +{ + var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g; + var index = 0; + var parts = []; + + var m; + while (m = re.exec(str)) + { + var pre = str.substr(index, (re.lastIndex-m[0].length)-index); + if (pre) + parts.push(pre); + + var expr = m[1].split("|"); + parts.push(new Variable(expr[0], expr.slice(1))); + index = re.lastIndex; + } + + if (!index) + return str; + + var post = str.substr(index); + if (post) + parts.push(post); + + return new Parts(parts); +} + +function parseValue(val) +{ + return typeof(val) == 'string' ? parseParts(val) : val; +} + +function parseChildren(args, offset, vars, children) +{ + for (var i = offset; i < args.length; ++i) + { + var val = parseValue(args[i]); + children.push(val); + readPartNames(val, vars); + } +} + +function readPartNames(val, vars) +{ + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + vars.push(part.name); + } + } +} + +function generateArg(val, path, args) +{ + if (val instanceof Parts) + { + var vals = []; + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var varName = 'd'+path.renderIndex++; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + varName = part.format[j] + '(' + varName + ')'; + } + + vals.push(varName); + } + else + vals.push('"'+part.replace(/"/g, '\\"')+'"'); + } + + return vals.join('+'); + } + else + { + args.push(val); + return 's' + path.staticIndex++; + } +} + +function addParts(val, delim, block, info, escapeIt) +{ + var vals = []; + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var partName = part.name; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + partName = part.format[j] + "(" + partName + ")"; + } + + if (escapeIt) + vals.push("__escape__(" + partName + ")"); + else + vals.push(partName); + } + else + vals.push('"'+ part + '"'); + } + } + else if (isTag(val)) + { + info.args.push(val); + vals.push('s'+info.argIndex++); + } + else + vals.push('"'+ val + '"'); + + var parts = vals.join(delim); + if (parts) + block.push(delim, parts); +} + +function isTag(obj) +{ + return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag; +} + +function creator(tag, cons) +{ + var fn = new Function( + "var tag = arguments.callee.tag;" + + "var cons = arguments.callee.cons;" + + "var newTag = new cons();" + + "return newTag.merge(arguments, tag);"); + + fn.tag = tag; + fn.cons = cons; + extend(fn, Renderer); + + return fn; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function copyArray(oldArray) +{ + var ary = []; + if (oldArray) + for (var i = 0; i < oldArray.length; ++i) + ary.push(oldArray[i]); + return ary; +} + +function copyObject(l, r) +{ + var m = {}; + extend(m, l); + extend(m, r); + return m; +} + +function extend(l, r) +{ + for (var n in r) + l[n] = r[n]; +} + +function addEvent(object, name, handler) +{ + if (document.all) + object.attachEvent("on"+name, handler); + else + object.addEventListener(name, handler, false); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function ArrayIterator(array) +{ + var index = -1; + + this.next = function() + { + if (++index >= array.length) + throw StopIteration; + + return array[index]; + }; +} + +function StopIteration() {} + +FBL.$break = function() +{ + throw StopIteration; +}; + +// ************************************************************************************************ + +var Renderer = +{ + renderHTML: function(args, outputs, self) + { + var code = []; + var markupArgs = [code, this.tag.context, args, outputs]; + markupArgs.push.apply(markupArgs, this.tag.markupArgs); + this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs); + return code.join(""); + }, + + insertRows: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + var div = doc.createElement("div"); + div.innerHTML = ""+html+"
      "; + + var tbody = div.firstChild.firstChild; + var parent = before.tagName == "TR" ? before.parentNode : before; + var after = before.tagName == "TR" ? before.nextSibling : null; + + var firstRow = tbody.firstChild, lastRow; + while (tbody.firstChild) + { + lastRow = tbody.firstChild; + if (after) + parent.insertBefore(lastRow, after); + else + parent.appendChild(lastRow); + } + + var offset = 0; + if (before.tagName == "TR") + { + var node = firstRow.parentNode.firstChild; + for (; node && node != firstRow; node = node.nextSibling) + ++offset; + } + + var domArgs = [firstRow, this.tag.context, offset]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + return [firstRow, lastRow]; + }, + + insertBefore: function(args, before, self) + { + return this.insertNode(args, before.ownerDocument, before, false, self); + }, + + insertAfter: function(args, after, self) + { + return this.insertNode(args, after.ownerDocument, after, true, self); + }, + + insertNode: function(args, doc, element, isAfter, self) + { + if (!args) + args = {}; + + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode html: "+html+"\n"); + + var doc = element.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + if (isAfter) + { + while (womb.firstChild) + if (element.nextSibling) + element.parentNode.insertBefore(womb.firstChild, element.nextSibling); + else + element.parentNode.appendChild(womb.firstChild); + } + else + { + while (womb.lastChild) + element.parentNode.insertBefore(womb.lastChild, element); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + /**/ + + /* + insertAfter: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + while (womb.firstChild) + if (before.nextSibling) + before.parentNode.insertBefore(womb.firstChild, before.nextSibling); + else + before.parentNode.appendChild(womb.firstChild); + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), + domArgs); + + return root; + }, + /**/ + + replace: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var root; + if (parent.nodeType == 1) + { + parent.innerHTML = html; + root = parent.firstChild; + } + else + { + if (!parent || parent.nodeType != 9) + parent = document; + + if (!womb || womb.ownerDocument != parent) + womb = parent.createElement("div"); + womb.innerHTML = html; + + root = womb.firstChild; + //womb.removeChild(root); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + + append: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n"); + + if (!womb || womb.ownerDocument != parent.ownerDocument) + womb = parent.ownerDocument.createElement("div"); + womb.innerHTML = html; + + // TODO: xxxpedro domplate port to Firebug + var root = womb.firstChild; + while (womb.firstChild) + parent.appendChild(womb.firstChild); + + // clearing element reference to avoid reference error in IE8 when switching contexts + womb = null; + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + } +}; + +// ************************************************************************************************ + +function defineTags() +{ + for (var i = 0; i < arguments.length; ++i) + { + var tagName = arguments[i]; + var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);"); + fn.DomplateTag = DomplateTag; + + var fnName = tagName.toUpperCase(); + FBL[fnName] = fn; + } +} + +defineTags( + "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr", + "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select", + "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe" +); + +})(); + + +/* See license.txt for terms of usage */ + +var FirebugReps = FBL.ns(function() { with (FBL) { + + +// ************************************************************************************************ +// Common Tags + +var OBJECTBOX = this.OBJECTBOX = + SPAN({"class": "objectBox objectBox-$className"}); + +var OBJECTBLOCK = this.OBJECTBLOCK = + DIV({"class": "objectBox objectBox-$className"}); + +var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation + A({ + "class": "objectLink objectLink-$className a11yFocus", + href: "javascript:void(0)", + _repObject: "$object" + }) + : // Other browsers + A({ + "class": "objectLink objectLink-$className a11yFocus", + _repObject: "$object" + }); + + +// ************************************************************************************************ + +this.Undefined = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("undefined"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "undefined", + + supportsObject: function(object, type) + { + return type == "undefined"; + } +}); + +// ************************************************************************************************ + +this.Null = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("null"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "null", + + supportsObject: function(object, type) + { + return object == null; + } +}); + +// ************************************************************************************************ + +this.Nada = domplate(Firebug.Rep, +{ + tag: SPAN(""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "nada" +}); + +// ************************************************************************************************ + +this.Number = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "number", + + supportsObject: function(object, type) + { + return type == "boolean" || type == "number"; + } +}); + +// ************************************************************************************************ + +this.String = domplate(Firebug.Rep, +{ + tag: OBJECTBOX(""$object""), + + shortTag: OBJECTBOX(""$object|cropString""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "string", + + supportsObject: function(object, type) + { + return type == "string"; + } +}); + +// ************************************************************************************************ + +this.Text = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + shortTag: OBJECTBOX("$object|cropString"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "text" +}); + +// ************************************************************************************************ + +this.Caption = domplate(Firebug.Rep, +{ + tag: SPAN({"class": "caption"}, "$object") +}); + +// ************************************************************************************************ + +this.Warning = domplate(Firebug.Rep, +{ + tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR") +}); + +// ************************************************************************************************ + +this.Func = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("$object|summarizeFunction"), + + summarizeFunction: function(fn) + { + var fnRegex = /function ([^(]+\([^)]*\)) \{/; + var fnText = safeToString(fn); + + var m = fnRegex.exec(fnText); + return m ? m[1] : "function()"; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copySource: function(fn) + { + copyToClipboard(safeToString(fn)); + }, + + monitor: function(fn, script, monitored) + { + if (monitored) + Firebug.Debugger.unmonitorScript(fn, script, "monitor"); + else + Firebug.Debugger.monitorScript(fn, script, "monitor"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "function", + + supportsObject: function(object, type) + { + return isFunction(object); + }, + + inspectObject: function(fn, context) + { + var sourceLink = findSourceForFunction(fn, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + if (FBTrace.DBG_FUNCTION_NAME) + FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink); + }, + + getTooltip: function(fn, context) + { + var script = findScriptForFunctionInContext(context, fn); + if (script) + return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]); + else + if (fn.toString) + return fn.toString(); + }, + + getTitle: function(fn, context) + { + var name = fn.name ? fn.name : "function"; + return name + "()"; + }, + + getContextMenuItems: function(fn, target, context, script) + { + if (!script) + script = findScriptForFunctionInContext(context, fn); + if (!script) + return; + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = script ? getFunctionName(script, context) : fn.name; + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, fn) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); + +// ************************************************************************************************ +/* +this.jsdScript = domplate(Firebug.Rep, +{ + copySource: function(script) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.copySource(fn); + }, + + monitor: function(fn, script, monitored) + { + fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.monitor(fn, script, monitored); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "jsdScript", + inspectable: false, + + supportsObject: function(object, type) + { + return object instanceof jsdIScript; + }, + + inspectObject: function(script, context) + { + var sourceLink = getSourceLinkForScript(script, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + }, + + getRealObject: function(script, context) + { + return script; + }, + + getTooltip: function(script) + { + return $STRF("jsdIScript", [script.tag]); + }, + + getTitle: function(script, context) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.getTitle(fn, context); + }, + + getContextMenuItems: function(script, target, context) + { + var fn = script.functionObject.getWrappedValue(); + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = getFunctionName(script, context); + + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, script) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); +/**/ +//************************************************************************************************ + +this.Obj = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + SPAN({"class": "objectTitle"}, "$object|getTitle "), + + SPAN({"class": "objectProps"}, + SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"), + FOR("prop", "$object|propIterator", + SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"), + SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"), + TAG("$prop.tag", {object: "$prop.object"}), + SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim") + ), + SPAN({"class": "objectRightBrace"}, "}") + ) + ), + + propNumberTag: + SPAN({"class": "objectProp-number"}, "$object"), + + propStringTag: + SPAN({"class": "objectProp-string"}, ""$object""), + + propObjectTag: + SPAN({"class": "objectProp-object"}, "$object"), + + propIterator: function (object) + { + ///Firebug.ObjectShortIteratorMax; + var maxLength = 55; // default max length for long representation + + if (!object) + return []; + + var props = []; + var length = 0; + + var numProperties = 0; + var numPropertiesShown = 0; + var maxLengthReached = false; + + var lib = this; + + var propRepsMap = + { + "boolean": this.propNumberTag, + "number": this.propNumberTag, + "string": this.propStringTag, + "object": this.propObjectTag + }; + + try + { + var title = Firebug.Rep.getTitle(object); + length += title.length; + + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var type = typeof(value); + if (type == "boolean" || + type == "number" || + (type == "string" && value) || + (type == "object" && value && value.toString)) + { + var tag = propRepsMap[type]; + + var value = (type == "object") ? + Firebug.getRep(value).getTitle(value) : + value + ""; + + length += name.length + value.length + 4; + + if (length <= maxLength) + { + props.push({ + tag: tag, + name: name, + object: value, + equal: "=", + delim: ", " + }); + + numPropertiesShown++; + } + else + maxLengthReached = true; + + } + + numProperties++; + + if (maxLengthReached && numProperties > numPropertiesShown) + break; + } + + if (numProperties > numPropertiesShown) + { + props.push({ + object: "...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }); + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + fb_1_6_propIterator: function (object, max) + { + max = max || 3; + if (!object) + return []; + + var props = []; + var len = 0, count = 0; + + try + { + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof(value); + if (t == "boolean" || t == "number" || (t == "string" && value) + || (t == "object" && value && value.toString)) + { + var rep = Firebug.getRep(value); + var tag = rep.shortTag || rep.tag; + if (t == "object") + { + value = rep.getTitle(value); + tag = rep.titleTag; + } + count++; + if (count <= max) + props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "}); + else + break; + } + } + if (count > max) + { + props[Math.max(1,max-1)] = { + object: "more...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }; + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + /* + propIterator: function (object) + { + if (!object) + return []; + + var props = []; + var len = 0; + + try + { + for (var name in object) + { + var val; + try + { + val = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof val; + if (t == "boolean" || t == "number" || (t == "string" && val) + || (t == "object" && !isFunction(val) && val && val.toString)) + { + var title = (t == "object") + ? Firebug.getRep(val).getTitle(val) + : val+""; + + len += name.length + title.length + 1; + if (len < 50) + props.push({name: name, value: title}); + else + break; + } + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + + return props; + }, + /**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object, type) + { + return true; + } +}); + + +// ************************************************************************************************ + +this.Arr = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|arrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + SPAN({"class": "arrayRightBracket", role : "presentation"}, "]") + ), + + shortTag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|shortArrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + // TODO: xxxpedro - confirm this on Firebug + //FOR("prop", "$object|shortPropIterator", + // " $prop.name=", + // SPAN({"class": "objectPropValue"}, "$prop.value|cropString") + //), + SPAN({"class": "arrayRightBracket"}, "]") + ), + + arrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + return items; + }, + + shortArrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length && i < 3; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + if (array.length > 3) + items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""}); + + return items; + }, + + shortPropIterator: this.Obj.propIterator, + + getItemIndex: function(child) + { + var arrayIndex = 0; + for (child = child.previousSibling; child; child = child.previousSibling) + { + if (child.repObject) + ++arrayIndex; + } + return arrayIndex; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "array", + + supportsObject: function(object) + { + return this.isArray(object); + }, + + // http://code.google.com/p/fbug/issues/detail?id=874 + // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007 + isArray: function(obj) { + try { + if (!obj) + return false; + else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8) + return true; + else if (isFinite(obj.length) && isFunction(obj.splice)) + return true; + else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments + return true; + else if (instanceOf(obj, "HTMLCollection")) + return true; + else if (instanceOf(obj, "NodeList")) + return true; + else + return false; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */ + FBTrace.sysout("isArray Fails on obj", obj); + } + } + + return false; + }, + // END Yahoo BSD SOURCE See license below. + + getTitle: function(object, context) + { + return "[" + object.length + "]"; + } +}); + +// ************************************************************************************************ + +this.Property = domplate(Firebug.Rep, +{ + supportsObject: function(object) + { + return object instanceof Property; + }, + + getRealObject: function(prop, context) + { + return prop.object[prop.name]; + }, + + getTitle: function(prop, context) + { + return prop.name; + } +}); + +// ************************************************************************************************ + +this.NetFile = domplate(this.Obj, +{ + supportsObject: function(object) + { + return object instanceof Firebug.NetFile; + }, + + browseObject: function(file, context) + { + openNewTab(file.href); + return true; + }, + + getRealObject: function(file, context) + { + return null; + } +}); + +// ************************************************************************************************ + +this.Except = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, "$object.message"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "exception", + + supportsObject: function(object) + { + return object instanceof ErrorCopy; + } +}); + + +// ************************************************************************************************ + +this.Element = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), + FOR("attr", "$object|attrIterator", + " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ + ), + ">" + ), + + shortTag: + OBJECTLINK( + SPAN({"class": "$object|getVisible"}, + SPAN({"class": "selectorTag"}, "$object|getSelectorTag"), + SPAN({"class": "selectorId"}, "$object|getSelectorId"), + SPAN({"class": "selectorClass"}, "$object|getSelectorClass"), + SPAN({"class": "selectorValue"}, "$object|getValue") + ) + ), + + getVisible: function(elt) + { + return isVisible(elt) ? "" : "selectorHidden"; + }, + + getSelectorTag: function(elt) + { + return elt.nodeName.toLowerCase(); + }, + + getSelectorId: function(elt) + { + return elt.id ? "#" + elt.id : ""; + }, + + getSelectorClass: function(elt) + { + return elt.className ? "." + elt.className.split(" ")[0] : ""; + }, + + getValue: function(elt) + { + // TODO: xxxpedro + return ""; + var value; + if (elt instanceof HTMLImageElement) + value = getFileName(elt.src); + else if (elt instanceof HTMLAnchorElement) + value = getFileName(elt.href); + else if (elt instanceof HTMLInputElement) + value = elt.value; + else if (elt instanceof HTMLFormElement) + value = getFileName(elt.action); + else if (elt instanceof HTMLScriptElement) + value = getFileName(elt.src); + + return value ? " " + cropString(value, 20) : ""; + }, + + attrIterator: function(elt) + { + var attrs = []; + var idAttr, classAttr; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName && attr.nodeName.indexOf("firebug-") != -1) + continue; + else if (attr.nodeName == "id") + idAttr = attr; + else if (attr.nodeName == "class") + classAttr = attr; + else + attrs.push(attr); + } + } + if (classAttr) + attrs.splice(0, 0, classAttr); + if (idAttr) + attrs.splice(0, 0, idAttr); + + return attrs; + }, + + shortAttrIterator: function(elt) + { + var attrs = []; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName == "id" || attr.nodeName == "class") + attrs.push(attr); + } + } + + return attrs; + }, + + getHidden: function(elt) + { + return isVisible(elt) ? "" : "nodeHidden"; + }, + + getXPath: function(elt) + { + return getElementTreeXPath(elt); + }, + + // TODO: xxxpedro remove this? + getNodeText: function(element) + { + var text = element.textContent; + if (Firebug.showFullTextNodes) + return text; + else + return cropString(text, 50); + }, + /**/ + + getNodeTextGroups: function(element) + { + var text = element.textContent; + if (!Firebug.showFullTextNodes) + { + text=cropString(text,50); + } + + var escapeGroups=[]; + + if (Firebug.showTextNodesWithWhitespace) + escapeGroups.push({ + 'group': 'whitespace', + 'class': 'nodeWhiteSpace', + 'extra': { + '\t': '_Tab', + '\n': '_Para', + ' ' : '_Space' + } + }); + if (Firebug.showTextNodesWithEntities) + escapeGroups.push({ + 'group':'text', + 'class':'nodeTextEntity', + 'extra':{} + }); + + if (escapeGroups.length) + return escapeGroupsForEntities(text, escapeGroups); + else + return [{str:text,'class':'',extra:''}]; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyHTML: function(elt) + { + var html = getElementXML(elt); + copyToClipboard(html); + }, + + copyInnerHTML: function(elt) + { + copyToClipboard(elt.innerHTML); + }, + + copyXPath: function(elt) + { + var xpath = getElementXPath(elt); + copyToClipboard(xpath); + }, + + persistor: function(context, xpath) + { + var elts = xpath + ? getElementsByXPath(context.window.document, xpath) + : null; + + return elts && elts.length ? elts[0] : null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "element", + + supportsObject: function(object) + { + //return object instanceof Element || object.nodeType == 1 && typeof object.nodeName == "string"; + return instanceOf(object, "Element"); + }, + + browseObject: function(elt, context) + { + var tag = elt.nodeName.toLowerCase(); + if (tag == "script") + openNewTab(elt.src); + else if (tag == "link") + openNewTab(elt.href); + else if (tag == "a") + openNewTab(elt.href); + else if (tag == "img") + openNewTab(elt.src); + + return true; + }, + + persistObject: function(elt, context) + { + var xpath = getElementXPath(elt); + + return bind(this.persistor, top, xpath); + }, + + getTitle: function(element, context) + { + return getElementCSSSelector(element); + }, + + getTooltip: function(elt) + { + return this.getXPath(elt); + }, + + getContextMenuItems: function(elt, target, context) + { + var monitored = areEventsMonitored(elt, null, context); + + return [ + {label: "CopyHTML", command: bindFixed(this.copyHTML, this, elt) }, + {label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) }, + {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) }, + "-", + {label: "ShowEventsInConsole", type: "checkbox", checked: monitored, + command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) }, + "-", + {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) } + ]; + } +}); + +// ************************************************************************************************ + +this.TextNode = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "TextNode"), + " textContent="", SPAN({"class": "nodeValue"}, "$object.textContent|cropString"), """, + ">" + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "textNode", + + supportsObject: function(object) + { + return object instanceof Text; + } +}); + +// ************************************************************************************************ + +this.Document = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(doc) + { + return doc.location ? getFileName(doc.location.href) : ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Document || object instanceof XMLDocument; + return instanceOf(object, "Document"); + }, + + browseObject: function(doc, context) + { + openNewTab(doc.location.href); + return true; + }, + + persistObject: function(doc, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window.document; + }, + + getTitle: function(win, context) + { + return "document"; + }, + + getTooltip: function(doc) + { + return doc.location.href; + } +}); + +// ************************************************************************************************ + +this.StyleSheet = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(styleSheet) + { + return getFileName(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(styleSheet) + { + copyToClipboard(styleSheet.href); + }, + + openInTab: function(styleSheet) + { + openNewTab(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof CSSStyleSheet; + return instanceOf(object, "CSSStyleSheet"); + }, + + browseObject: function(styleSheet, context) + { + openNewTab(styleSheet.href); + return true; + }, + + persistObject: function(styleSheet, context) + { + return bind(this.persistor, top, styleSheet.href); + }, + + getTooltip: function(styleSheet) + { + return styleSheet.href; + }, + + getContextMenuItems: function(styleSheet, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) } + ]; + }, + + persistor: function(context, href) + { + return getStyleSheetByHref(href, context); + } +}); + +// ************************************************************************************************ + +this.Window = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(win) + { + try + { + return (win && win.location && !win.closed) ? getFileName(win.location.href) : ""; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.Window window closed?"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + return instanceOf(object, "Window"); + }, + + browseObject: function(win, context) + { + openNewTab(win.location.href); + return true; + }, + + persistObject: function(win, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window; + }, + + getTitle: function(win, context) + { + return "window"; + }, + + getTooltip: function(win) + { + if (win && !win.closed) + return win.location.href; + } +}); + +// ************************************************************************************************ + +this.Event = domplate(Firebug.Rep, +{ + tag: TAG("$copyEventTag", {object: "$object|copyEvent"}), + + copyEventTag: + OBJECTLINK("$object|summarizeEvent"), + + summarizeEvent: function(event) + { + var info = [event.type, ' ']; + + var eventFamily = getEventFamily(event.type); + if (eventFamily == "mouse") + info.push("clientX=", event.clientX, ", clientY=", event.clientY); + else if (eventFamily == "key") + info.push("charCode=", event.charCode, ", keyCode=", event.keyCode); + + return info.join(""); + }, + + copyEvent: function(event) + { + return new EventCopy(event); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Event || object instanceof EventCopy; + return instanceOf(object, "Event") || instanceOf(object, "EventCopy"); + }, + + getTitle: function(event, context) + { + return "Event " + event.type; + } +}); + +// ************************************************************************************************ + +this.SourceLink = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + hideSourceLink: function(sourceLink) + { + return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true; + }, + + getSourceLinkTitle: function(sourceLink) + { + if (!sourceLink) + return ""; + + try + { + var fileName = getFileName(sourceLink.href); + fileName = decodeURIComponent(fileName); + fileName = cropString(fileName, 17); + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'"+fileName+"\': "+exc, exc); + } + + return typeof sourceLink.line == "number" ? + fileName + " (line " + sourceLink.line + ")" : + fileName; + + // TODO: xxxpedro + //return $STRF("Line", [fileName, sourceLink.line]); + }, + + copyLink: function(sourceLink) + { + copyToClipboard(sourceLink.href); + }, + + openInTab: function(sourceLink) + { + openNewTab(sourceLink.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceLink", + + supportsObject: function(object) + { + return object instanceof SourceLink; + }, + + getTooltip: function(sourceLink) + { + return decodeURI(sourceLink.href); + }, + + inspectObject: function(sourceLink, context) + { + if (sourceLink.type == "js") + { + var scriptFile = getSourceFileByHref(sourceLink.href, context); + if (scriptFile) + return Firebug.chrome.select(sourceLink); + } + else if (sourceLink.type == "css") + { + // If an object is defined, treat it as the highest priority for + // inspect actions + if (sourceLink.object) { + Firebug.chrome.select(sourceLink.object); + return; + } + + var stylesheet = getStyleSheetByHref(sourceLink.href, context); + if (stylesheet) + { + var ownerNode = stylesheet.ownerNode; + if (ownerNode) + { + Firebug.chrome.select(sourceLink, "html"); + return; + } + + var panel = context.getPanel("stylesheet"); + if (panel && panel.getRuleByLine(stylesheet, sourceLink.line)) + return Firebug.chrome.select(sourceLink); + } + } + + // Fallback is to just open the view-source window on the file + viewSource(sourceLink.href, sourceLink.line); + }, + + browseObject: function(sourceLink, context) + { + openNewTab(sourceLink.href); + return true; + }, + + getContextMenuItems: function(sourceLink, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceFile = domplate(this.SourceLink, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + persistor: function(context, href) + { + return getSourceFileByHref(href, context); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceFile", + + supportsObject: function(object) + { + return object instanceof SourceFile; + }, + + persistObject: function(sourceFile) + { + return bind(this.persistor, top, sourceFile.href); + }, + + browseObject: function(sourceLink, context) + { + }, + + getTooltip: function(sourceFile) + { + return sourceFile.href; + } +}); + +// ************************************************************************************************ + +this.StackFrame = domplate(Firebug.Rep, // XXXjjb Since the repObject is fn the stack does not have correct line numbers +{ + tag: + OBJECTBLOCK( + A({"class": "objectLink objectLink-function focusRow a11yFocus", _repObject: "$object.fn"}, "$object|getCallName"), + " ( ", + FOR("arg", "$object|argIterator", + TAG("$arg.tag", {object: "$arg.value"}), + SPAN({"class": "arrayComma"}, "$arg.delim") + ), + " )", + SPAN({"class": "objectLink-sourceLink objectLink"}, "$object|getSourceLinkTitle") + ), + + getCallName: function(frame) + { + //TODO: xxxpedro reps StackFrame + return frame.name || "anonymous"; + + //return getFunctionName(frame.script, frame.context); + }, + + getSourceLinkTitle: function(frame) + { + //TODO: xxxpedro reps StackFrame + var fileName = cropString(getFileName(frame.href), 20); + return fileName + (frame.lineNo ? " (line " + frame.lineNo + ")" : ""); + + var fileName = cropString(getFileName(frame.href), 17); + return $STRF("Line", [fileName, frame.lineNo]); + }, + + argIterator: function(frame) + { + if (!frame.args) + return []; + + var items = []; + + for (var i = 0; i < frame.args.length; ++i) + { + var arg = frame.args[i]; + + if (!arg) + break; + + var rep = Firebug.getRep(arg.value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var delim = (i == frame.args.length-1 ? "" : ", "); + + items.push({name: arg.name, value: arg.value, tag: tag, delim: delim}); + } + + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackFrame", + + supportsObject: function(object) + { + return object instanceof StackFrame; + }, + + inspectObject: function(stackFrame, context) + { + var sourceLink = new SourceLink(stackFrame.href, stackFrame.lineNo, "js"); + Firebug.chrome.select(sourceLink); + }, + + getTooltip: function(stackFrame, context) + { + return $STRF("Line", [stackFrame.href, stackFrame.lineNo]); + } + +}); + +// ************************************************************************************************ + +this.StackTrace = domplate(Firebug.Rep, +{ + tag: + FOR("frame", "$object.frames focusRow", + TAG(this.StackFrame.tag, {object: "$frame"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackTrace", + + supportsObject: function(object) + { + return object instanceof StackTrace; + } +}); + +// ************************************************************************************************ + +this.jsdStackFrame = domplate(Firebug.Rep, +{ + inspectable: false, + + supportsObject: function(object) + { + return (object instanceof jsdIStackFrame) && (object.isValid); + }, + + getTitle: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + return getFunctionName(frame.script, context); + }, + + getTooltip: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + var sourceInfo = FBL.getSourceFileAndLineByScript(context, frame.script, frame); + if (sourceInfo) + return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]); + else + return $STRF("Line", [frame.script.fileName, frame.line]); + }, + + getContextMenuItems: function(frame, target, context) + { + var fn = frame.script.functionObject.getWrappedValue(); + return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script); + } +}); + +// ************************************************************************************************ + +this.ErrorMessage = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({ + $hasTwisty: "$object|hasStackTrace", + $hasBreakSwitch: "$object|hasBreakSwitch", + $breakForError: "$object|hasErrorBreak", + _repObject: "$object", + _stackTrace: "$object|getLastErrorStackTrace", + onclick: "$onToggleError"}, + + DIV({"class": "errorTitle a11yFocus", role : 'checkbox', 'aria-checked' : 'false'}, + "$object.message|getMessage" + ), + DIV({"class": "errorTrace"}), + DIV({"class": "errorSourceBox errorSource-$object|getSourceType"}, + IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':'false', title: "Break on this error"}), + A({"class": "errorSource a11yFocus"}, "$object|getLine") + ), + TAG(this.SourceLink.tag, {object: "$object|getSourceLink"}) + ), + + getLastErrorStackTrace: function(error) + { + return error.trace; + }, + + hasStackTrace: function(error) + { + var url = error.href.toString(); + var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1); + return !fromCommandLine && error.trace; + }, + + hasBreakSwitch: function(error) + { + return error.href && error.lineNo > 0; + }, + + hasErrorBreak: function(error) + { + return fbs.hasErrorBreakpoint(error.href, error.lineNo); + }, + + getMessage: function(message) + { + var re = /\[Exception... "(.*?)" nsresult:/; + var m = re.exec(message); + return m ? m[1] : message; + }, + + getLine: function(error) + { + if (error.category == "js") + { + if (error.source) + return cropString(error.source, 80); + else if (error.href && error.href.indexOf("XPCSafeJSObjectWrapper") == -1) + return cropString(error.getSourceLine(), 80); + } + }, + + getSourceLink: function(error) + { + var ext = error.category == "css" ? "css" : "js"; + return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null; + }, + + getSourceType: function(error) + { + // Errors occurring inside of HTML event handlers look like "foo.html (line 1)" + // so let's try to skip those + if (error.source) + return "syntax"; + else if (error.lineNo == 1 && getFileExtension(error.href) != "js") + return "none"; + else if (error.category == "css") + return "none"; + else if (!error.href || !error.lineNo) + return "none"; + else + return "exec"; + }, + + onToggleError: function(event) + { + var target = event.currentTarget; + if (hasClass(event.target, "errorBreak")) + { + this.breakOnThisError(target.repObject); + } + else if (hasClass(event.target, "errorSource")) + { + var panel = Firebug.getElementPanel(event.target); + this.inspectObject(target.repObject, panel.context); + } + else if (hasClass(event.target, "errorTitle")) + { + var traceBox = target.childNodes[1]; + toggleClass(target, "opened"); + event.target.setAttribute('aria-checked', hasClass(target, "opened")); + if (hasClass(target, "opened")) + { + if (target.stackTrace) + var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox); + if (Firebug.A11yModel.enabled) + { + var panel = Firebug.getElementPanel(event.target); + dispatch([Firebug.A11yModel], "onLogRowContentCreated", [panel , traceBox]); + } + } + else + clearNode(traceBox); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyError: function(error) + { + var message = [ + this.getMessage(error.message), + error.href, + "Line " + error.lineNo + ]; + copyToClipboard(message.join("\n")); + }, + + breakOnThisError: function(error) + { + if (this.hasErrorBreak(error)) + Firebug.Debugger.clearErrorBreakpoint(error.href, error.lineNo); + else + Firebug.Debugger.setErrorBreakpoint(error.href, error.lineNo); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "errorMessage", + inspectable: false, + + supportsObject: function(object) + { + return object instanceof ErrorMessage; + }, + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + FirebugReps.SourceLink.inspectObject(sourceLink, context); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + var items = [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) } + ]; + + if (error.category == "css") + { + items.push( + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + + optionMenu("BreakOnAllErrors", "breakOnErrors") + ); + } + + return items; + } +}); + +// ************************************************************************************************ + +this.Assert = domplate(Firebug.Rep, +{ + tag: + DIV( + DIV({"class": "errorTitle"}), + DIV({"class": "assertDescription"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "assert", + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + Firebug.chrome.select(sourceLink); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + return [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) }, + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors, + command: bindFixed(this.breakOnAllErrors, this, error) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceText = domplate(Firebug.Rep, +{ + tag: + DIV( + FOR("line", "$object|lineIterator", + DIV({"class": "sourceRow", role : "presentation"}, + SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"), + SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text") + ) + ) + ), + + lineIterator: function(sourceText) + { + var maxLineNoChars = (sourceText.lines.length + "").length; + var list = []; + + for (var i = 0; i < sourceText.lines.length; ++i) + { + // Make sure all line numbers are the same width (with a fixed-width font) + var lineNo = (i+1) + ""; + while (lineNo.length < maxLineNoChars) + lineNo = " " + lineNo; + + list.push({lineNo: lineNo, text: sourceText.lines[i]}); + } + + return list; + }, + + getHTML: function(sourceText) + { + return getSourceLineRange(sourceText, 1, sourceText.lines.length); + } +}); + +//************************************************************************************************ +this.nsIDOMHistory = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showHistory"}, + OBJECTLINK("$object|summarizeHistory") + ), + + className: "nsIDOMHistory", + + summarizeHistory: function(history) + { + try + { + var items = history.length; + return items + " history entries"; + } + catch(exc) + { + return "object does not support history (nsIDOMHistory)"; + } + }, + + showHistory: function(history) + { + try + { + var items = history.length; // if this throws, then unsupported + Firebug.chrome.select(history); + } + catch (exc) + { + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object, type) + { + return (object instanceof Ci.nsIDOMHistory); + } +}); + +// ************************************************************************************************ +this.ApplicationCache = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showApplicationCache"}, + OBJECTLINK("$object|summarizeCache") + ), + + summarizeCache: function(applicationCache) + { + try + { + return applicationCache.length + " items in offline cache"; + } + catch(exc) + { + return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264"; + } + }, + + showApplicationCache: function(event) + { + openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "applicationCache", + + supportsObject: function(object, type) + { + if (Ci.nsIDOMOfflineResourceList) + return (object instanceof Ci.nsIDOMOfflineResourceList); + } + +}); + +this.Storage = domplate(Firebug.Rep, +{ + tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")), + + summarize: function(storage) + { + return storage.length +" items in Storage"; + }, + show: function(storage) + { + openNewTab("http://dev.w3.org/html5/webstorage/#storage-0"); + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "Storage", + + supportsObject: function(object, type) + { + return (object instanceof Storage); + } + +}); + +// ************************************************************************************************ +Firebug.registerRep( + //this.nsIDOMHistory, // make this early to avoid exceptions + this.Undefined, + this.Null, + this.Number, + this.String, + this.Window, + //this.ApplicationCache, // must come before Arr (array) else exceptions. + //this.ErrorMessage, + this.Element, + //this.TextNode, + this.Document, + this.StyleSheet, + this.Event, + //this.SourceLink, + //this.SourceFile, + //this.StackTrace, + //this.StackFrame, + //this.jsdStackFrame, + //this.jsdScript, + //this.NetFile, + this.Property, + this.Except, + this.Arr +); + +Firebug.setDefaultReps(this.Func, this.Obj); + +}}); + +// ************************************************************************************************ +/* + * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source" + * in only this file reps.js. John J. Barton June 2007. + * +Software License Agreement (BSD License) + +Copyright (c) 2006, Yahoo! Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Yahoo! Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Yahoo! Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * / + */ + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var saveTimeout = 400; +var pageAmount = 10; + +// ************************************************************************************************ +// Globals + +var currentTarget = null; +var currentGroup = null; +var currentPanel = null; +var currentEditor = null; + +var defaultEditor = null; + +var originalClassName = null; + +var originalValue = null; +var defaultValue = null; +var previousValue = null; + +var invalidEditor = false; +var ignoreNextInput = false; + +// ************************************************************************************************ + +Firebug.Editor = extend(Firebug.Module, +{ + supportsStopEvent: true, + + dispatchName: "editor", + tabCharacter: " ", + + startEditing: function(target, value, editor) + { + this.stopEditing(); + + if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter")) + return; + + var panel = Firebug.getElementPanel(target); + if (!panel.editable) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.startEditing " + value, target); + + defaultValue = target.getAttribute("defaultValue"); + if (value == undefined) + { + var textContent = isIE ? "innerText" : "textContent"; + value = target[textContent]; + if (value == defaultValue) + value = ""; + } + + originalValue = previousValue = value; + + invalidEditor = false; + currentTarget = target; + currentPanel = panel; + currentGroup = getAncestorByClass(target, "editGroup"); + + currentPanel.editing = true; + + var panelEditor = currentPanel.getEditor(target, value); + currentEditor = editor ? editor : panelEditor; + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + var inlineParent = getInlineParent(target); + var targetSize = getOffsetSize(inlineParent); + + setClass(panel.panelNode, "editing"); + setClass(target, "editing"); + if (currentGroup) + setClass(currentGroup, "editing"); + + currentEditor.show(target, currentPanel, value, targetSize); + //dispatch(this.fbListeners, "onBeginEditing", [currentPanel, currentEditor, target, value]); + currentEditor.beginEditing(target, value); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Editor start panel "+currentPanel.name); + this.attachListeners(currentEditor, panel.context); + }, + + stopEditing: function(cancel) + { + if (!currentTarget) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.stopEditing cancel:" + cancel+" saveTimeout: "+this.saveTimeout); + + clearTimeout(this.saveTimeout); + delete this.saveTimeout; + + this.detachListeners(currentEditor, currentPanel.context); + + removeClass(currentPanel.panelNode, "editing"); + removeClass(currentTarget, "editing"); + if (currentGroup) + removeClass(currentGroup, "editing"); + + var value = currentEditor.getValue(); + if (value == defaultValue) + value = ""; + + var removeGroup = currentEditor.endEditing(currentTarget, value, cancel); + + try + { + if (cancel) + { + //dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, removeGroup && !originalValue]); + if (value != originalValue) + this.saveEditAndNotifyListeners(currentTarget, originalValue, previousValue); + + if (removeGroup && !originalValue && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else if (!value) + { + this.saveEditAndNotifyListeners(currentTarget, null, previousValue); + + if (removeGroup && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else + this.save(value); + } + catch (exc) + { + //throw exc.message; + //ERROR(exc); + } + + currentEditor.hide(); + currentPanel.editing = false; + + //dispatch(this.fbListeners, "onStopEdit", [currentPanel, currentEditor, currentTarget]); + //if (FBTrace.DBG_EDITOR) + // FBTrace.sysout("Editor stop panel "+currentPanel.name); + + currentTarget = null; + currentGroup = null; + currentPanel = null; + currentEditor = null; + originalValue = null; + invalidEditor = false; + + return value; + }, + + cancelEditing: function() + { + return this.stopEditing(true); + }, + + update: function(saveNow) + { + if (this.saveTimeout) + clearTimeout(this.saveTimeout); + + invalidEditor = true; + + currentEditor.layout(); + + if (saveNow) + this.save(); + else + { + var context = currentPanel.context; + this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.update saveTimeout: "+this.saveTimeout); + } + }, + + save: function(value) + { + if (!invalidEditor) + return; + + if (value == undefined) + value = currentEditor.getValue(); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.save saveTimeout: "+this.saveTimeout+" currentPanel: "+(currentPanel?currentPanel.name:"null")); + try + { + this.saveEditAndNotifyListeners(currentTarget, value, previousValue); + + previousValue = value; + invalidEditor = false; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("editor.save FAILS "+exc, exc); + } + }, + + saveEditAndNotifyListeners: function(currentTarget, value, previousValue) + { + currentEditor.saveEdit(currentTarget, value, previousValue); + //dispatch(this.fbListeners, "onSaveEdit", [currentPanel, currentEditor, currentTarget, value, previousValue]); + }, + + setEditTarget: function(element) + { + if (!element) + { + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, true]); + this.stopEditing(); + } + else if (hasClass(element, "insertBefore")) + this.insertRow(element, "before"); + else if (hasClass(element, "insertAfter")) + this.insertRow(element, "after"); + else + this.startEditing(element); + }, + + tabNextEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var nextEditable = currentTarget; + do + { + nextEditable = !value && currentGroup + ? getNextOutsider(nextEditable, currentGroup) + : getNextByClass(nextEditable, "editable"); + } + while (nextEditable && !nextEditable.offsetHeight); + + this.setEditTarget(nextEditable); + }, + + tabPreviousEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var prevEditable = currentTarget; + do + { + prevEditable = !value && currentGroup + ? getPreviousOutsider(prevEditable, currentGroup) + : getPreviousByClass(prevEditable, "editable"); + } + while (prevEditable && !prevEditable.offsetHeight); + + this.setEditTarget(prevEditable); + }, + + insertRow: function(relative, insertWhere) + { + var group = + relative || getAncestorByClass(currentTarget, "editGroup") || currentTarget; + var value = this.stopEditing(); + + currentPanel = Firebug.getElementPanel(group); + + currentEditor = currentPanel.getEditor(group, value); + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + currentGroup = currentEditor.insertNewRow(group, insertWhere); + if (!currentGroup) + return; + + var editable = hasClass(currentGroup, "editable") + ? currentGroup + : getNextByClass(currentGroup, "editable"); + + if (editable) + this.setEditTarget(editable); + }, + + insertRowForObject: function(relative) + { + var container = getAncestorByClass(relative, "insertInto"); + if (container) + { + relative = getChildByClass(container, "insertBefore"); + if (relative) + this.insertRow(relative, "before"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + attachListeners: function(editor, context) + { + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + addEvent(win, "resize", this.onResize); + addEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + + this.listeners = [ + chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this)) + ]; + + if (editor.arrowCompletion) + { + this.listeners.push( + chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)), + chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)), + chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)), + chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount)) + ); + } + + if (currentEditor.tabNavigation) + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")), + chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this)) + ); + } + else if (currentEditor.multiLine) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, insertTab) + ); + } + else + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this)) + ); + + if (currentEditor.tabCompletion) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)), + chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1)) + ); + } + } + }, + + detachListeners: function(editor, context) + { + if (!this.listeners) + return; + + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + removeEvent(win, "resize", this.onResize); + removeEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + if (chrome) + { + for (var i = 0; i < this.listeners.length; ++i) + chrome.keyIgnore(this.listeners[i]); + } + + delete this.listeners; + }, + + onResize: function(event) + { + currentEditor.layout(true); + }, + + onBlur: function(event) + { + if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box)) + this.stopEditing(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + Firebug.Module.initialize.apply(this, arguments); + + this.onResize = bindFixed(this.onResize, this); + this.onBlur = bind(this.onBlur, this); + }, + + disable: function() + { + this.stopEditing(); + }, + + showContext: function(browser, context) + { + this.stopEditing(); + }, + + showPanel: function(browser, panel) + { + this.stopEditing(); + } +}); + +// ************************************************************************************************ +// BaseEditor + +Firebug.BaseEditor = extend(Firebug.MeasureBox, +{ + getValue: function() + { + }, + + setValue: function(value) + { + }, + + show: function(target, panel, value, textSize, targetSize) + { + }, + + hide: function() + { + }, + + layout: function(forceAll) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for context menus within inline editors. + + getContextMenuItems: function(target) + { + var items = []; + items.push({label: "Cut", commandID: "cmd_cut"}); + items.push({label: "Copy", commandID: "cmd_copy"}); + items.push({label: "Paste", commandID: "cmd_paste"}); + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Editor Module listeners will get "onBeginEditing" just before this call + + beginEditing: function(target, value) + { + }, + + // Editor Module listeners will get "onSaveEdit" just after this call + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + } +}); + +// ************************************************************************************************ +// InlineEditor + +// basic inline editor attributes +var inlineEditorAttributes = { + "class": "textEditorInner", + + type: "text", + spellcheck: "false", + + onkeypress: "$onKeyPress", + + onoverflow: "$onOverflow", + oncontextmenu: "$onContextMenu" +}; + +// IE does not support the oninput event, so we're using the onkeydown to signalize +// the relevant keyboard events, and the onpropertychange to actually handle the +// input event, which should happen after the onkeydown event is fired and after the +// value of the input is updated, but before the onkeyup and before the input (with the +// new value) is rendered +if (isIE) +{ + inlineEditorAttributes.onpropertychange = "$onInput"; + inlineEditorAttributes.onkeydown = "$onKeyDown"; +} +// for other browsers we use the oninput event +else +{ + inlineEditorAttributes.oninput = "$onInput"; +} + +Firebug.InlineEditor = function(doc) +{ + this.initializeInline(doc); +}; + +Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor, +{ + enterOnBlur: true, + outerMargin: 8, + shadowExpand: 7, + + tag: + DIV({"class": "inlineEditor"}, + DIV({"class": "textEditorTop1"}, + DIV({"class": "textEditorTop2"}) + ), + DIV({"class": "textEditorInner1"}, + DIV({"class": "textEditorInner2"}, + INPUT( + inlineEditorAttributes + ) + ) + ), + DIV({"class": "textEditorBottom1"}, + DIV({"class": "textEditorBottom2"}) + ) + ), + + inputTag : + INPUT({"class": "textEditorInner", type: "text", + /*oninput: "$onInput",*/ onkeypress: "$onKeyPress", onoverflow: "$onOverflow"} + ), + + expanderTag: + IMG({"class": "inlineExpander", src: "blank.gif"}), + + initialize: function() + { + this.fixedWidth = false; + this.completeAsYouType = true; + this.tabNavigation = true; + this.multiLine = false; + this.tabCompletion = false; + this.arrowCompletion = true; + this.noWrap = true; + this.numeric = false; + }, + + destroy: function() + { + this.destroyInput(); + }, + + initializeInline: function(doc) + { + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Firebug.InlineEditor initializeInline()"); + + //this.box = this.tag.replace({}, doc, this); + this.box = this.tag.append({}, doc.body, this); + + //this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required + this.input = this.box.getElementsByTagName("input")[0]; + + if (isIElt8) + { + this.input.style.top = "-8px"; + } + + this.expander = this.expanderTag.replace({}, doc, this); + this.initialize(); + }, + + destroyInput: function() + { + // XXXjoe Need to remove input/keypress handlers to avoid leaks + }, + + getValue: function() + { + return this.input.value; + }, + + setValue: function(value) + { + // It's only a one-line editor, so new lines shouldn't be allowed + return this.input.value = stripNewLines(value); + }, + + show: function(target, panel, value, targetSize) + { + //dispatch([Firebug.A11yModel], "onInlineEditorShow", [panel, this]); + this.target = target; + this.panel = panel; + + this.targetSize = targetSize; + + // TODO: xxxpedro editor + //this.targetOffset = getClientOffset(target); + + // Some browsers (IE, Google Chrome and Safari) will have problem trying to get the + // offset values of invisible elements, or empty elements. So, in order to get the + // correct values, we temporary inject a character in the innerHTML of the empty element, + // then we get the offset values, and next, we restore the original innerHTML value. + var innerHTML = target.innerHTML; + var isEmptyElement = !innerHTML; + if (isEmptyElement) + target.innerHTML = "."; + + // Get the position of the target element (that is about to be edited) + this.targetOffset = + { + x: target.offsetLeft, + y: target.offsetTop + }; + + // Restore the original innerHTML value of the empty element + if (isEmptyElement) + target.innerHTML = innerHTML; + + this.originalClassName = this.box.className; + + var classNames = target.className.split(" "); + for (var i = 0; i < classNames.length; ++i) + setClass(this.box, "editor-" + classNames[i]); + + // Make the editor match the target's font style + copyTextStyles(target, this.box); + + this.setValue(value); + + if (this.fixedWidth) + this.updateLayout(true); + else + { + this.startMeasuring(target); + this.textSize = this.measureInputText(value); + + // Correct the height of the box to make the funky CSS drop-shadow line up + var parent = this.input.parentNode; + if (hasClass(parent, "textEditorInner2")) + { + var yDiff = this.textSize.height - this.shadowExpand; + + // IE6 height offset + if (isIE6) + yDiff -= 2; + + parent.style.height = yDiff + "px"; + parent.parentNode.style.height = yDiff + "px"; + } + + this.updateLayout(true); + } + + this.getAutoCompleter().reset(); + + if (isIElt8) + panel.panelNode.appendChild(this.box); + else + target.offsetParent.appendChild(this.box); + + //console.log(target); + //this.input.select(); // it's called bellow, with setTimeout + + if (isIE) + { + // reset input style + this.input.style.fontFamily = "Monospace"; + this.input.style.fontSize = "11px"; + } + + // Insert the "expander" to cover the target element with white space + if (!this.fixedWidth) + { + copyBoxStyles(target, this.expander); + + target.parentNode.replaceChild(this.expander, target); + collapse(target, true); + this.expander.parentNode.insertBefore(target, this.expander); + } + + //TODO: xxxpedro + //scrollIntoCenterView(this.box, null, true); + + // Display the editor after change its size and position to avoid flickering + this.box.style.display = "block"; + + // we need to call input.focus() and input.select() with a timeout, + // otherwise it won't work on all browsers due to timing issues + var self = this; + setTimeout(function(){ + self.input.focus(); + self.input.select(); + },0); + }, + + hide: function() + { + this.box.className = this.originalClassName; + + if (!this.fixedWidth) + { + this.stopMeasuring(); + + collapse(this.target, false); + + if (this.expander.parentNode) + this.expander.parentNode.removeChild(this.expander); + } + + if (this.box.parentNode) + { + ///setSelectionRange(this.input, 0, 0); + this.input.blur(); + + this.box.parentNode.removeChild(this.box); + } + + delete this.target; + delete this.panel; + }, + + layout: function(forceAll) + { + if (!this.fixedWidth) + this.textSize = this.measureInputText(this.input.value); + + if (forceAll) + this.targetOffset = getClientOffset(this.expander); + + this.updateLayout(false, forceAll); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + beginEditing: function(target, value) + { + }, + + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + }, + + advanceToNext: function(target, charCode) + { + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleter: function() + { + if (!this.autoCompleter) + { + this.autoCompleter = new Firebug.AutoCompleter(null, + bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this), + true, false); + } + + return this.autoCompleter; + }, + + completeValue: function(amt) + { + //console.log("completeValue"); + + var selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0); + + if (selectRangeCallback) + { + Firebug.Editor.update(true); + + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + else + this.incrementValue(amt); + }, + + incrementValue: function(amt) + { + var value = this.input.value; + + // TODO: xxxpedro editor + if (isIE) + var start = getInputSelectionStart(this.input), end = start; + else + var start = this.input.selectionStart, end = this.input.selectionEnd; + + //debugger; + var range = this.getAutoCompleteRange(value, start); + if (!range || range.type != "int") + range = {start: 0, end: value.length-1}; + + var expr = value.substr(range.start, range.end-range.start+1); + preExpr = value.substr(0, range.start); + postExpr = value.substr(range.end+1); + + // See if the value is an integer, and if so increment it + var intValue = parseInt(expr); + if (!!intValue || intValue == 0) + { + var m = /\d+/.exec(expr); + var digitPost = expr.substr(m.index+m[0].length); + + var completion = intValue-amt; + this.input.value = preExpr + completion + digitPost + postExpr; + + setSelectionRange(this.input, start, end); + + Firebug.Editor.update(true); + + return true; + } + else + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onKeyPress: function(event) + { + //console.log("onKeyPress", event); + if (event.keyCode == 27 && !this.completeAsYouType) + { + var reverted = this.getAutoCompleter().revert(this.input); + if (reverted) + cancelEvent(event); + } + else if (event.charCode && this.advanceToNext(this.target, event.charCode)) + { + Firebug.Editor.tabNextEditor(); + cancelEvent(event); + } + else + { + if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57) + && event.charCode != 45 && event.charCode != 46) + FBL.cancelEvent(event); + else + { + // If the user backspaces, don't autocomplete after the upcoming input event + this.ignoreNextInput = event.keyCode == 8; + } + } + }, + + onOverflow: function() + { + this.updateLayout(false, false, 3); + }, + + onKeyDown: function(event) + { + //console.log("onKeyDown", event.keyCode); + if (event.keyCode > 46 || event.keyCode == 32 || event.keyCode == 8) + { + this.keyDownPressed = true; + } + }, + + onInput: function(event) + { + //debugger; + + // skip not relevant onpropertychange calls on IE + if (isIE) + { + if (event.propertyName != "value" || !isVisible(this.input) || !this.keyDownPressed) + return; + + this.keyDownPressed = false; + } + + //console.log("onInput", event); + //console.trace(); + + var selectRangeCallback; + + if (this.ignoreNextInput) + { + this.ignoreNextInput = false; + this.getAutoCompleter().reset(); + } + else if (this.completeAsYouType) + selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, false); + else + this.getAutoCompleter().reset(); + + Firebug.Editor.update(); + + if (selectRangeCallback) + { + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + }, + + onContextMenu: function(event) + { + cancelEvent(event); + + var popup = $("fbInlineEditorPopup"); + FBL.eraseNode(popup); + + var target = event.target || event.srcElement; + var menu = this.getContextMenuItems(target); + if (menu) + { + for (var i = 0; i < menu.length; ++i) + FBL.createMenuItem(popup, menu[i]); + } + + if (!popup.firstChild) + return false; + + popup.openPopupAtScreen(event.screenX, event.screenY, true); + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateLayout: function(initial, forceAll, extraWidth) + { + if (this.fixedWidth) + { + this.box.style.left = (this.targetOffset.x) + "px"; + this.box.style.top = (this.targetOffset.y) + "px"; + + var w = this.target.offsetWidth; + var h = this.target.offsetHeight; + this.input.style.width = w + "px"; + this.input.style.height = (h-3) + "px"; + } + else + { + if (initial || forceAll) + { + this.box.style.left = this.targetOffset.x + "px"; + this.box.style.top = this.targetOffset.y + "px"; + } + + var approxTextWidth = this.textSize.width; + var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x) + - this.outerMargin; + + var wrapped = initial + ? this.noWrap && this.targetSize.height > this.textSize.height+3 + : this.noWrap && approxTextWidth > maxWidth; + + if (wrapped) + { + var style = isIE ? + this.target.currentStyle : + this.target.ownerDocument.defaultView.getComputedStyle(this.target, ""); + + targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight); + + // Make the width fit the remaining x-space from the offset to the far right + approxTextWidth = maxWidth - targetMargin; + + this.input.style.width = "100%"; + this.box.style.width = approxTextWidth + "px"; + } + else + { + // Make the input one character wider than the text value so that + // typing does not ever cause the textbox to scroll + var charWidth = this.measureInputText('m').width; + + // Sometimes we need to make the editor a little wider, specifically when + // an overflow happens, otherwise it will scroll off some text on the left + if (extraWidth) + charWidth *= extraWidth; + + var inputWidth = approxTextWidth + charWidth; + + if (initial) + { + if (isIE) + { + // TODO: xxxpedro + var xDiff = 13; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + else + this.box.style.width = "auto"; + } + else + { + // TODO: xxxpedro + var xDiff = isIE ? 13: this.box.scrollWidth - this.input.offsetWidth; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + + this.input.style.width = inputWidth + "px"; + } + + this.expander.style.width = approxTextWidth + "px"; + this.expander.style.height = Math.max(this.textSize.height-3,0) + "px"; + } + + if (forceAll) + scrollIntoCenterView(this.box, null, true); + } +}); + +// ************************************************************************************************ +// Autocompletion + +Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive) +{ + var candidates = null; + var originalValue = null; + var originalOffset = -1; + var lastExpr = null; + var lastOffset = -1; + var exprOffset = 0; + var lastIndex = 0; + var preParsed = null; + var preExpr = null; + var postExpr = null; + + this.revert = function(textBox) + { + if (originalOffset != -1) + { + textBox.value = originalValue; + + setSelectionRange(textBox, originalOffset, originalOffset); + + this.reset(); + return true; + } + else + { + this.reset(); + return false; + } + }; + + this.reset = function() + { + candidates = null; + originalValue = null; + originalOffset = -1; + lastExpr = null; + lastOffset = 0; + exprOffset = 0; + }; + + this.complete = function(context, textBox, cycle, reverse) + { + //console.log("complete", context, textBox, cycle, reverse); + // TODO: xxxpedro important port to firebug (variable leak) + //var value = lastValue = textBox.value; + var value = textBox.value; + + //var offset = textBox.selectionStart; + var offset = getInputSelectionStart(textBox); + + // The result of selectionStart() in Safari/Chrome is 1 unit less than the result + // in Firefox. Therefore, we need to manually adjust the value here. + if (isSafari && !cycle && offset >= 0) offset++; + + if (!selectMode && originalOffset != -1) + offset = originalOffset; + + if (!candidates || !cycle || offset != lastOffset) + { + originalOffset = offset; + originalValue = value; + + // Find the part of the string that will be parsed + var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0; + preParsed = value.substr(0, parseStart); + var parsed = value.substr(parseStart); + + // Find the part of the string that is being completed + var range = getRange ? getRange(parsed, offset-parseStart, context) : null; + if (!range) + range = {start: 0, end: parsed.length-1 }; + + var expr = parsed.substr(range.start, range.end-range.start+1); + preExpr = parsed.substr(0, range.start); + postExpr = parsed.substr(range.end+1); + exprOffset = parseStart + range.start; + + if (!cycle) + { + if (!expr) + return; + else if (lastExpr && lastExpr.indexOf(expr) != 0) + { + candidates = null; + } + else if (lastExpr && lastExpr.length >= expr.length) + { + candidates = null; + lastExpr = expr; + return; + } + } + + lastExpr = expr; + lastOffset = offset; + + var searchExpr; + + // Check if the cursor is at the very right edge of the expression, or + // somewhere in the middle of it + if (expr && offset != parseStart+range.end+1) + { + if (cycle) + { + // We are in the middle of the expression, but we can + // complete by cycling to the next item in the values + // list after the expression + offset = range.start; + searchExpr = expr; + expr = ""; + } + else + { + // We can't complete unless we are at the ridge edge + return; + } + } + + var values = evaluator(preExpr, expr, postExpr, context); + if (!values) + return; + + if (expr) + { + // Filter the list of values to those which begin with expr. We + // will then go on to complete the first value in the resulting list + candidates = []; + + if (caseSensitive) + { + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.indexOf(expr) == 0) + candidates.push(name); + } + } + else + { + var lowerExpr = caseSensitive ? expr : expr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0) + candidates.push(name); + } + } + + lastIndex = reverse ? candidates.length-1 : 0; + } + else if (searchExpr) + { + var searchIndex = -1; + + // Find the first instance of searchExpr in the values list. We + // will then complete the string that is found + if (caseSensitive) + { + searchIndex = values.indexOf(expr); + } + else + { + var lowerExpr = searchExpr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name && name.toLowerCase().indexOf(lowerExpr) == 0) + { + searchIndex = i; + break; + } + } + } + + // Nothing found, so there's nothing to complete to + if (searchIndex == -1) + return this.reset(); + + expr = searchExpr; + candidates = cloneArray(values); + lastIndex = searchIndex; + } + else + { + expr = ""; + candidates = []; + for (var i = 0; i < values.length; ++i) + { + if (values[i].substr) + candidates.push(values[i]); + } + lastIndex = -1; + } + } + + if (cycle) + { + expr = lastExpr; + lastIndex += reverse ? -1 : 1; + } + + if (!candidates.length) + return; + + if (lastIndex >= candidates.length) + lastIndex = 0; + else if (lastIndex < 0) + lastIndex = candidates.length-1; + + var completion = candidates[lastIndex]; + var preCompletion = expr.substr(0, offset-exprOffset); + var postCompletion = completion.substr(offset-exprOffset); + + textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr; + var offsetEnd = preParsed.length + preExpr.length + completion.length; + + // TODO: xxxpedro remove the following commented code, if the lib.setSelectionRange() + // is working well. + /* + if (textBox.setSelectionRange) + { + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + setTimeout(function(){ + if (selectMode) + textBox.setSelectionRange(offset, offsetEnd); + else + textBox.setSelectionRange(offsetEnd, offsetEnd); + },0); + } + /**/ + + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + /* + setTimeout(function(){ + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + },0); + + return true; + /**/ + + // The editor text should be selected only after calling the editor.update() + // in Safari/Chrome, otherwise the text won't be selected. So, we're returning + // a function to be called later (in the proper time for all browsers). + // + // TODO: xxxpedro see if we can move the editor.update() calls to here, and avoid + // returning a closure. the complete() function seems to be called only twice in + // editor.js. See if this function is called anywhere else (like css.js for example). + return function(){ + //console.log("autocomplete ", textBox, offset, offsetEnd); + + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + }; + /**/ + }; +}; + +// ************************************************************************************************ +// Local Helpers + +var getDefaultEditor = function getDefaultEditor(panel) +{ + if (!defaultEditor) + { + var doc = panel.document; + defaultEditor = new Firebug.InlineEditor(doc); + } + + return defaultEditor; +} + +/** + * An outsider is the first element matching the stepper element that + * is not an child of group. Elements tagged with insertBefore or insertAfter + * classes are also excluded from these results unless they are the sibling + * of group, relative to group's parent editGroup. This allows for the proper insertion + * rows when groups are nested. + */ +var getOutsider = function getOutsider(element, group, stepper) +{ + var parentGroup = getAncestorByClass(group.parentNode, "editGroup"); + var next; + do + { + next = stepper(next || element); + } + while (isAncestor(next, group) || isGroupInsert(next, parentGroup)); + + return next; +} + +var isGroupInsert = function isGroupInsert(next, group) +{ + return (!group || isAncestor(next, group)) + && (hasClass(next, "insertBefore") || hasClass(next, "insertAfter")); +} + +var getNextOutsider = function getNextOutsider(element, group) +{ + return getOutsider(element, group, bind(getNextByClass, FBL, "editable")); +} + +var getPreviousOutsider = function getPreviousOutsider(element, group) +{ + return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable")); +} + +var getInlineParent = function getInlineParent(element) +{ + var lastInline = element; + for (; element; element = element.parentNode) + { + //var s = element.ownerDocument.defaultView.getComputedStyle(element, ""); + var s = isIE ? + element.currentStyle : + element.ownerDocument.defaultView.getComputedStyle(element, ""); + + if (s.display != "inline") + return lastInline; + else + lastInline = element; + } + return null; +} + +var insertTab = function insertTab() +{ + insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.Editor); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Inspector Module + +var ElementCache = Firebug.Lite.Cache.Element; + +var inspectorTS, inspectorTimer, isInspecting; + +Firebug.Inspector = +{ + create: function() + { + offlineFragment = Env.browser.document.createDocumentFragment(); + + createBoxModelInspector(); + createOutlineInspector(); + }, + + destroy: function() + { + destroyBoxModelInspector(); + destroyOutlineInspector(); + + offlineFragment = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inspect functions + + toggleInspect: function() + { + if (isInspecting) + { + this.stopInspecting(); + } + else + { + Firebug.chrome.inspectButton.changeState("pressed"); + this.startInspecting(); + } + }, + + startInspecting: function() + { + isInspecting = true; + + Firebug.chrome.selectPanel("HTML"); + + createInspectorFrame(); + + var size = Firebug.browser.getWindowScrollSize(); + + fbInspectFrame.style.width = size.width + "px"; + fbInspectFrame.style.height = size.height + "px"; + + //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody); + + addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + }, + + stopInspecting: function() + { + isInspecting = false; + + if (outlineVisible) this.hideOutline(); + removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + + destroyInspectorFrame(); + + Firebug.chrome.inspectButton.restore(); + + if (Firebug.chrome.type == "popup") + Firebug.chrome.node.focus(); + }, + + onInspectingClick: function(e) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + //Firebug.Console.log(targ); + Firebug.Inspector.stopInspecting(); + }, + + onInspecting: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache(targ)) + { + var target = ""+ElementCache.key(targ); + var lazySelect = function() + { + inspectorTS = new Date().getTime(); + + Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)) + }; + + if (inspectorTimer) + { + clearTimeout(inspectorTimer); + inspectorTimer = null; + } + + if (new Date().getTime() - inspectorTS > 200) + setTimeout(lazySelect, 0) + else + inspectorTimer = setTimeout(lazySelect, 300); + } + + lastInspecting = new Date().getTime(); + } + }, + + // TODO: xxxpedro remove this? + onInspectingBody: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + var targ = e.target; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache.has(targ)) + FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)); + + lastInspecting = new Date().getTime(); + } + }, + + /** + * + * llttttttrr + * llttttttrr + * ll rr + * ll rr + * llbbbbbbrr + * llbbbbbbrr + */ + drawOutline: function(el) + { + var border = 2; + var scrollbarSize = 17; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + var box = Firebug.browser.getElementBox(el); + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width - + (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible + scrollbarSize : 0); + + var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height - + (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible + scrollbarSize : 0); + + var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1; + + var o = outlineElements; + var style; + + style = o.fbOutlineT.style; + style.top = top-border + "px"; + style.left = left + "px"; + style.height = border + "px"; // TODO: on initialize() + style.width = width + "px"; + + style = o.fbOutlineL.style; + style.top = top-border + "px"; + style.left = left-border + "px"; + style.height = height+ numVerticalBorders*border + "px"; + style.width = border + "px"; // TODO: on initialize() + + style = o.fbOutlineB.style; + if (freeVerticalSpace > 0) + { + style.top = top+height + "px"; + style.left = left + "px"; + style.width = width + "px"; + //style.height = border + "px"; // TODO: on initialize() or worst case? + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.width = border + "px"; + //style.height = border + "px"; + } + + style = o.fbOutlineR.style; + if (freeHorizontalSpace > 0) + { + style.top = top-border + "px"; + style.left = left+width + "px"; + style.height = height + numVerticalBorders*border + "px"; + style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px"; + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.height = border + "px"; + style.width = border + "px"; + } + + if (!outlineVisible) this.showOutline(); + }, + + hideOutline: function() + { + if (!outlineVisible) return; + + for (var name in outline) + offlineFragment.appendChild(outlineElements[name]); + + outlineVisible = false; + }, + + showOutline: function() + { + if (outlineVisible) return; + + if (boxModelVisible) this.hideBoxModel(); + + for (var name in outline) + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]); + + outlineVisible = true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Box Model + + drawBoxModel: function(el) + { + // avoid error when the element is not attached a document + if (!el || !el.parentNode) + return; + + var box = Firebug.browser.getElementBox(el); + + var windowSize = Firebug.browser.getWindowSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + // element may be occluded by the chrome, when in frame mode + var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0; + + // if element box is not inside the viewport, don't draw the box model + if (box.top > scrollPosition.top + windowSize.height - offsetHeight || + box.left > scrollPosition.left + windowSize.width || + scrollPosition.top > box.top + box.height || + scrollPosition.left > box.left + box.width ) + return; + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var margin = Firebug.browser.getMeasurementBox(el, "margin"); + var padding = Firebug.browser.getMeasurementBox(el, "padding"); + var border = Firebug.browser.getMeasurementBox(el, "border"); + + boxModelStyle.top = top - margin.top + "px"; + boxModelStyle.left = left - margin.left + "px"; + boxModelStyle.height = height + margin.top + margin.bottom + "px"; + boxModelStyle.width = width + margin.left + margin.right + "px"; + + boxBorderStyle.top = margin.top + "px"; + boxBorderStyle.left = margin.left + "px"; + boxBorderStyle.height = height + "px"; + boxBorderStyle.width = width + "px"; + + boxPaddingStyle.top = margin.top + border.top + "px"; + boxPaddingStyle.left = margin.left + border.left + "px"; + boxPaddingStyle.height = height - border.top - border.bottom + "px"; + boxPaddingStyle.width = width - border.left - border.right + "px"; + + boxContentStyle.top = margin.top + border.top + padding.top + "px"; + boxContentStyle.left = margin.left + border.left + padding.left + "px"; + boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px"; + boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px"; + + if (!boxModelVisible) this.showBoxModel(); + }, + + hideBoxModel: function() + { + if (!boxModelVisible) return; + + offlineFragment.appendChild(boxModel); + boxModelVisible = false; + }, + + showBoxModel: function() + { + if (boxModelVisible) return; + + if (outlineVisible) this.hideOutline(); + + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel); + boxModelVisible = true; + } + +}; + +// ************************************************************************************************ +// Inspector Internals + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Shared variables + + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internal variables + +var offlineFragment = null; + +var boxModelVisible = false; + +var boxModel, boxModelStyle, + boxMargin, boxMarginStyle, + boxBorder, boxBorderStyle, + boxPadding, boxPaddingStyle, + boxContent, boxContentStyle; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; +var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;"; + +var inspectStyle = resetStyle + "z-index: 2147483500;"; +var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" + + Env.Location.skinDir + "pixel_transparent.gif);"; + +//if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);"; + +var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;"; +var inspectModelStyle = inspectStyle + inspectModelOpacity; +var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;"; +var inspectBorderStyle = inspectStyle + "background: #666;"; +var inspectPaddingStyle = inspectStyle + "background: SlateBlue;"; +var inspectContentStyle = inspectStyle + "background: SkyBlue;"; + + +var outlineStyle = { + fbHorizontalLine: "background: #3875D7;height: 2px;", + fbVerticalLine: "background: #3875D7;width: 2px;" +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var lastInspecting = 0; +var fbInspectFrame = null; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var outlineVisible = false; +var outlineElements = {}; +var outline = { + "fbOutlineT": "fbHorizontalLine", + "fbOutlineL": "fbVerticalLine", + "fbOutlineB": "fbHorizontalLine", + "fbOutlineR": "fbVerticalLine" +}; + + +var getInspectingTarget = function() +{ + +}; + +// ************************************************************************************************ +// Section + +var createInspectorFrame = function createInspectorFrame() +{ + fbInspectFrame = createGlobalElement("div"); + fbInspectFrame.id = "fbInspectFrame"; + fbInspectFrame.firebugIgnore = true; + fbInspectFrame.style.cssText = inspectFrameStyle; + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame); +}; + +var destroyInspectorFrame = function destroyInspectorFrame() +{ + if (fbInspectFrame) + { + Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame); + fbInspectFrame = null; + } +}; + +var createOutlineInspector = function createOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name] = createGlobalElement("div"); + el.id = name; + el.firebugIgnore = true; + el.style.cssText = inspectStyle + outlineStyle[outline[name]]; + offlineFragment.appendChild(el); + } +}; + +var destroyOutlineInspector = function destroyOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name]; + el.parentNode.removeChild(el); + } +}; + +var createBoxModelInspector = function createBoxModelInspector() +{ + boxModel = createGlobalElement("div"); + boxModel.id = "fbBoxModel"; + boxModel.firebugIgnore = true; + boxModelStyle = boxModel.style; + boxModelStyle.cssText = inspectModelStyle; + + boxMargin = createGlobalElement("div"); + boxMargin.id = "fbBoxMargin"; + boxMarginStyle = boxMargin.style; + boxMarginStyle.cssText = inspectMarginStyle; + boxModel.appendChild(boxMargin); + + boxBorder = createGlobalElement("div"); + boxBorder.id = "fbBoxBorder"; + boxBorderStyle = boxBorder.style; + boxBorderStyle.cssText = inspectBorderStyle; + boxModel.appendChild(boxBorder); + + boxPadding = createGlobalElement("div"); + boxPadding.id = "fbBoxPadding"; + boxPaddingStyle = boxPadding.style; + boxPaddingStyle.cssText = inspectPaddingStyle; + boxModel.appendChild(boxPadding); + + boxContent = createGlobalElement("div"); + boxContent.id = "fbBoxContent"; + boxContentStyle = boxContent.style; + boxContentStyle.cssText = inspectContentStyle; + boxModel.appendChild(boxContent); + + offlineFragment.appendChild(boxModel); +}; + +var destroyBoxModelInspector = function destroyBoxModelInspector() +{ + boxModel.parentNode.removeChild(boxModel); +}; + +// ************************************************************************************************ +// Section + + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +// next-generation Console Panel (will override consoje.js) +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Constants + +/* +const Cc = Components.classes; +const Ci = Components.interfaces; +const nsIPrefBranch2 = Ci.nsIPrefBranch2; +const PrefService = Cc["@mozilla.org/preferences-service;1"]; +const prefs = PrefService.getService(nsIPrefBranch2); +/**/ +/* + +// new offline message handler +o = {x:1,y:2}; + +r = Firebug.getRep(o); + +r.tag.tag.compile(); + +outputs = []; +html = r.tag.renderHTML({object:o}, outputs); + + +// finish rendering the template (the DOM part) +target = $("build"); +target.innerHTML = html; +root = target.firstChild; + +domArgs = [root, r.tag.context, 0]; +domArgs.push.apply(domArgs, r.tag.domArgs); +domArgs.push.apply(domArgs, outputs); +r.tag.tag.renderDOM.apply(self ? self : r.tag.subject, domArgs); + + + */ +var consoleQueue = []; +var lastHighlightedObject; +var FirebugContext = Env.browser; + +// ************************************************************************************************ + +var maxQueueRequests = 500; + +// ************************************************************************************************ + +Firebug.ConsoleBase = +{ + log: function(object, context, className, rep, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"log",[context, object, className, sourceLink]); + return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle); + }, + + logFormatted: function(objects, context, className, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]); + return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle); + }, + + openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush) + { + return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle); + }, + + closeGroup: function(context, noThrottle) + { + return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true); + }, + + logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow) + { + // TODO: xxxpedro console console2 + noThrottle = true; // xxxpedro forced because there is no TabContext yet + + if (!context) + context = FirebugContext; + + if (FBTrace.DBG_ERRORS && !context) + FBTrace.sysout("Console.logRow has no context, skipping objects", objects); + + if (!context) + return; + + if (noThrottle || !context) + { + var panel = this.getPanel(context); + if (panel) + { + var row = panel.append(appender, objects, className, rep, sourceLink, noRow); + var container = panel.panelNode; + + // TODO: xxxpedro what is this? console console2 + /* + var template = Firebug.NetMonitor.NetLimit; + + while (container.childNodes.length > maxQueueRequests + 1) + { + clearDomplate(container.firstChild.nextSibling); + container.removeChild(container.firstChild.nextSibling); + panel.limit.limitInfo.totalCount++; + template.updateCounter(panel.limit); + } + dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]); + /**/ + return row; + } + else + { + consoleQueue.push([appender, objects, context, className, rep, sourceLink, noThrottle, noRow]); + } + } + else + { + if (!context.throttle) + { + //FBTrace.sysout("console.logRow has not context.throttle! "); + return; + } + var args = [appender, objects, context, className, rep, sourceLink, true, noRow]; + context.throttle(this.logRow, this, args); + } + }, + + appendFormatted: function(args, row, context) + { + if (!context) + context = FirebugContext; + + var panel = this.getPanel(context); + panel.appendFormatted(args, row); + }, + + clear: function(context) + { + if (!context) + //context = FirebugContext; + context = Firebug.context; + + /* + if (context) + Firebug.Errors.clear(context); + /**/ + + var panel = this.getPanel(context, true); + if (panel) + { + panel.clear(); + } + }, + + // Override to direct output to your panel + getPanel: function(context, noCreate) + { + //return context.getPanel("console", noCreate); + // TODO: xxxpedro console console2 + return Firebug.chrome ? Firebug.chrome.getPanel("Console") : null; + } + +}; + +// ************************************************************************************************ + +//TODO: xxxpedro +//var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase); +var ActivableConsole = extend(Firebug.ConsoleBase, +{ + isAlwaysEnabled: function() + { + return true; + } +}); + +Firebug.Console = Firebug.Console = extend(ActivableConsole, +//Firebug.Console = extend(ActivableConsole, +{ + dispatchName: "console", + + error: function() + { + Firebug.Console.logFormatted(arguments, Firebug.browser, "error"); + }, + + flush: function() + { + dispatch(this.fbListeners,"flush",[]); + + for (var i=0, length=consoleQueue.length; i objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + if (typeof(object) != "undefined") + this.appendObject(object, row, part.rep); + else + this.appendObject(part.type, row, FirebugReps.Text); + } + else + FirebugReps.Text.tag.append({object: part}, row); + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + logText(" ", row); + var object = objects[i]; + if (typeof(object) == "string") + FirebugReps.Text.tag.append({object: object}, row); + else + this.appendObject(object, row); + } + }, + + appendOpenGroup: function(objects, row, rep) + { + if (!this.groups) + this.groups = []; + + setClass(row, "logGroup"); + setClass(row, "opened"); + + var innerRow = this.createRow("logRow"); + setClass(innerRow, "logGroupLabel"); + if (rep) + rep.tag.replace({"objects": objects}, innerRow); + else + this.appendFormatted(objects, innerRow, rep); + row.appendChild(innerRow); + //dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]); + var groupBody = this.createRow("logGroupBody"); + row.appendChild(groupBody); + groupBody.setAttribute('role', 'group'); + this.groups.push(groupBody); + + addEvent(innerRow, "mousedown", function(event) + { + if (isLeftClick(event)) + { + //console.log(event.currentTarget == event.target); + + var target = event.target || event.srcElement; + + target = getAncestorByClass(target, "logGroupLabel"); + + var groupRow = target.parentNode; + + if (hasClass(groupRow, "opened")) + { + removeClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'false'); + } + else + { + setClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'true'); + } + } + }); + }, + + appendCloseGroup: function(object, row, rep) + { + if (this.groups) + this.groups.pop(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // TODO: xxxpedro console2 + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + onMouseDown: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + var repObject = object ? object.repObject : null; + + if (!repObject) + { + return; + } + + if (hasClass(object, "objectLink-object")) + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(repObject, true); + } + else if (hasClass(object, "objectLink-element")) + { + Firebug.chrome.selectPanel("HTML"); + Firebug.chrome.getPanel("HTML").select(repObject, true); + } + + /* + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + /**/ + + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "Console", + title: "Console", + //searchable: true, + //breakable: true, + //editable: false, + + options: + { + hasCommandLine: true, + hasToolButtons: true, + isPreRendered: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.context = Firebug.browser.window; + this.document = Firebug.chrome.document; + this.onMouseMove = bind(this.onMouseMove, this); + this.onMouseDown = bind(this.onMouseDown, this); + + this.clearButton = new Button({ + element: $("fbConsole_btClear"), + owner: Firebug.Console, + onClick: Firebug.Console.clear + }); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); // loads persisted content + //Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content + + if (!this.persistedContent && Firebug.Console.isAlwaysEnabled()) + { + this.insertLogLimit(this.context); + + // Initialize log limit and listen for changes. + this.updateMaxLimit(); + + if (this.context.consoleReloadWarning) // we have not yet injected the console + this.insertReloadWarning(); + } + + //Firebug.Console.injector.install(Firebug.browser.window); + + addEvent(this.panelNode, "mouseover", this.onMouseMove); + addEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.clearButton.initialize(); + + //consolex.trace(); + //TODO: xxxpedro remove this + /* + Firebug.Console.openGroup(["asd"], null, "group", null, false); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + /**/ + + //TODO: xxxpedro preferences prefs + //prefs.addObserver(Firebug.prefDomain, this, false); + }, + + initializeNode : function() + { + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this]); + if (FBTrace.DBG_CONSOLE) + { + this.onScroller = bind(this.onScroll, this); + addEvent(this.panelNode, "scroll", this.onScroller); + } + + this.onResizer = bind(this.onResize, this); + this.resizeEventTarget = Firebug.chrome.$('fbContentBox'); + addEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + destroyNode : function() + { + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this]); + if (this.onScroller) + removeEvent(this.panelNode, "scroll", this.onScroller); + + //removeEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + shutdown: function() + { + //TODO: xxxpedro console console2 + this.clearButton.shutdown(); + + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + + //TODO: xxxpedro preferences prefs + //prefs.removeObserver(Firebug.prefDomain, this, false); + }, + + ishow: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel show; " + this.context.getName(), state); + + var enabled = Firebug.Console.isAlwaysEnabled(); + if (enabled) + { + Firebug.Console.disabledPanelPage.hide(this); + this.showCommandLine(true); + this.showToolbarButtons("fbConsoleButtons", true); + Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent); + + if (state && state.wasScrolledToBottom) + { + this.wasScrolledToBottom = state.wasScrolledToBottom; + delete state.wasScrolledToBottom; + } + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + } + else + { + this.hide(state); + Firebug.Console.disabledPanelPage.show(this); + } + }, + + ihide: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel hide; " + this.context.getName(), state); + + this.showToolbarButtons("fbConsoleButtons", false); + this.showCommandLine(false); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + destroy: function(state) + { + if (this.panelNode.offsetHeight) + this.wasScrolledToBottom = isScrolledToBottom(this.panelNode); + + if (state) + state.wasScrolledToBottom = this.wasScrolledToBottom; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + shouldBreakOnNext: function() + { + // xxxHonza: shouldn't the breakOnErrors be context related? + // xxxJJB, yes, but we can't support it because we can't yet tell + // which window the error is on. + return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors"); + }, + + getBreakOnNextTooltip: function(enabled) + { + return (enabled ? $STR("console.Disable Break On All Errors") : + $STR("console.Break On All Errors")); + }, + + enablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.enablePanel.apply(this, arguments); + + this.showCommandLine(true); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + }, + + disablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.disablePanel.apply(this, arguments); + + this.showCommandLine(false); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowJavaScriptErrors", "showJSErrors"), + optionMenu("ShowJavaScriptWarnings", "showJSWarnings"), + optionMenu("ShowCSSErrors", "showCSSErrors"), + optionMenu("ShowXMLErrors", "showXMLErrors"), + optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"), + optionMenu("ShowChromeErrors", "showChromeErrors"), + optionMenu("ShowChromeMessages", "showChromeMessages"), + optionMenu("ShowExternalErrors", "showExternalErrors"), + optionMenu("ShowNetworkErrors", "showNetworkErrors"), + this.getShowStackTraceMenuItem(), + this.getStrictOptionMenuItem(), + "-", + optionMenu("LargeCommandLine", "largeCommandLine") + ]; + }, + + getShowStackTraceMenuItem: function() + { + var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace"); + if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled()) + menuItem.disabled = true; + return menuItem; + }, + + getStrictOptionMenuItem: function() + { + var strictDomain = "javascript.options"; + var strictName = "strict"; + var strictValue = prefs.getBoolPref(strictDomain+"."+strictName); + return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue, + command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) }; + }, + + getBreakOnMenuItems: function() + { + //xxxHonza: no BON options for now. + /*return [ + optionMenu("console.option.Persist Break On Error", "persistBreakOnError") + ];*/ + return []; + }, + + search: function(text) + { + if (!text) + return; + + // Make previously visible nodes invisible again + if (this.matchSet) + { + for (var i in this.matchSet) + removeClass(this.matchSet[i], "matched"); + } + + this.matchSet = []; + + function findRow(node) { return getAncestorByClass(node, "logRow"); } + var search = new TextSearch(this.panelNode, findRow); + + var logRow = search.find(text); + if (!logRow) + { + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]); + return false; + } + for (; logRow; logRow = search.findNext()) + { + setClass(logRow, "matched"); + this.matchSet.push(logRow); + } + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]); + return true; + }, + + breakOnNext: function(breaking) + { + Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // private + + createRow: function(rowName, className) + { + var elt = this.document.createElement("div"); + elt.className = rowName + (className ? " " + rowName + "-" + className : ""); + return elt; + }, + + getTopContainer: function() + { + if (this.groups && this.groups.length) + return this.groups[this.groups.length-1]; + else + return this.panelNode; + }, + + filterLogRow: function(logRow, scrolledToBottom) + { + if (this.searchText) + { + setClass(logRow, "matching"); + setClass(logRow, "matched"); + + // Search after a delay because we must wait for a frame to be created for + // the new logRow so that the finder will be able to locate it + setTimeout(bindFixed(function() + { + if (this.searchFilter(this.searchText, logRow)) + this.matchSet.push(logRow); + else + removeClass(logRow, "matched"); + + removeClass(logRow, "matching"); + + if (scrolledToBottom) + scrollToBottom(this.panelNode); + }, this), 100); + } + }, + + searchFilter: function(text, logRow) + { + var count = this.panelNode.childNodes.length; + var searchRange = this.document.createRange(); + searchRange.setStart(this.panelNode, 0); + searchRange.setEnd(this.panelNode, count); + + var startPt = this.document.createRange(); + startPt.setStartBefore(logRow); + + var endPt = this.document.createRange(); + endPt.setStartAfter(logRow); + + return finder.Find(text, searchRange, startPt, endPt) != null; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + // xxxHonza check this out. + var prefDomain = "Firebug.extension."; + var prefName = data.substr(prefDomain.length); + if (prefName == "console.logLimit") + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = 1000; + //TODO: xxxpedro preferences log limit? + //var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + }, + + showCommandLine: function(shouldShow) + { + //TODO: xxxpedro show command line important + return; + + if (shouldShow) + { + collapse(Firebug.chrome.$("fbCommandBox"), false); + Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome); + } + else + { + // Make sure that entire content of the Console panel is hidden when + // the panel is disabled. + Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine); + collapse(Firebug.chrome.$("fbCommandBox"), true); + } + }, + + onScroll: function(event) + { + // Update the scroll position flag if the position changes. + this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", wasScrolledToBottom: " + + this.context.getName(), event); + }, + + onResize: function(event) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight + + ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " + + this.panelNode.scrollHeight + ", " + this.context.getName(), event); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + } +}); + +// ************************************************************************************************ + +function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +} + +// ************************************************************************************************ + +var appendObject = Firebug.ConsolePanel.prototype.appendObject; +var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted; +var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup; +var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup; + +// ************************************************************************************************ + +//Firebug.registerActivableModule(Firebug.Console); +Firebug.registerModule(Firebug.Console); +Firebug.registerPanel(Firebug.ConsolePanel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +var frameCounters = {}; +var traceRecursion = 0; + +Firebug.Console.injector = +{ + install: function(context) + { + var win = context.window; + + var consoleHandler = new FirebugConsoleHandler(context, win); + + var properties = + [ + "log", + "debug", + "info", + "warn", + "error", + "assert", + "dir", + "dirxml", + "group", + "groupCollapsed", + "groupEnd", + "time", + "timeEnd", + "count", + "trace", + "profile", + "profileEnd", + "clear", + "open", + "close" + ]; + + var Handler = function(name) + { + var c = consoleHandler; + var f = consoleHandler[name]; + return function(){return f.apply(c,arguments)}; + }; + + var installer = function(c) + { + for (var i=0, l=properties.length; i 1) + { + traceRecursion--; + return; + } + + var frames = []; + + for (var fn = arguments.callee.caller.caller; fn; fn = fn.caller) + { + if (wasVisited(fn)) break; + + var args = []; + + for (var i = 0, l = fn.arguments.length; i < l; ++i) + { + args.push({value: fn.arguments[i]}); + } + + frames.push({fn: fn, name: getFuncName(fn), args: args}); + } + + + // **************************************************************************************** + + try + { + (0)(); + } + catch(e) + { + var result = e; + + var stack = + result.stack || // Firefox / Google Chrome + result.stacktrace || // Opera + ""; + + stack = stack.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks + var items = stack.split(/[\n\r]/); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Google Chrome + if (FBL.isSafari) + { + //var reChromeStackItem = /^\s+at\s+([^\(]+)\s\((.*)\)$/; + //var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + + var reChromeStackItemName = /\s*\($/; + var reChromeStackItemValue = /^(.+)\:(\d+\:\d+)\)?$/; + + var framePos = 0; + for (var i=4, length=items.length; i 1) + { + objects = [errorObject]; + for (var i = 1; i < args.length; i++) + objects.push(args[i]); + } + + var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle + row.scrollIntoView(); + } + + function getComponentsStackDump() + { + // Starting with our stack, walk back to the user-level code + var frame = Components.stack; + var userURL = win.location.href.toString(); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame); + + // Drop frames until we get into user code. + while (frame && FBL.isSystemURL(frame.filename) ) + frame = frame.caller; + + // Drop two more frames, the injected console function and firebugAppendConsole() + if (frame) + frame = frame.caller; + if (frame) + frame = frame.caller; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame); + + return frame; + } + + function getStackLink() + { + // TODO: xxxpedro console2 + return; + //return FBL.getFrameSourceLink(getComponentsStackDump()); + } + + function getJSDUserStack() + { + var trace = FBL.getCurrentStackTrace(context); + + var frames = trace ? trace.frames : null; + if (frames && (frames.length > 0) ) + { + var oldest = frames.length - 1; // 6 - 1 = 5 + for (var i = 0; i < frames.length; i++) + { + if (frames[oldest - i].href.indexOf("chrome:") == 0) break; + var fn = frames[oldest - i].fn + ""; + if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line + } + FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace); + trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code + + return trace; + } + else + return "Firebug failed to get stack trace with any frames"; + } +} + +// ************************************************************************************************ +// Register console namespace + +FBL.registerConsole = function() +{ + //TODO: xxxpedro console options override + //if (Env.Options.overrideConsole) + var win = Env.browser.window; + Firebug.Console.injector.install(win); +}; + +registerConsole(); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +// ************************************************************************************************ +// Globals + +var commandPrefix = ">>>"; +var reOpenBracket = /[\[\(\{]/; +var reCloseBracket = /[\]\)\}]/; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var commandHistory = []; +var commandPointer = -1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var isAutoCompleting = null; +var autoCompletePrefix = null; +var autoCompleteExpr = null; +var autoCompleteBuffer = null; +var autoCompletePosition = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var fbCommandLine = null; +var fbLargeCommandLine = null; +var fbLargeCommandButtons = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _completion = +{ + window: + [ + "console" + ], + + document: + [ + "getElementById", + "getElementsByTagName" + ] +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _stack = function(command) +{ + commandHistory.push(command); + commandPointer = commandHistory.length; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +// ************************************************************************************************ +// CommandLine + +Firebug.CommandLine = extend(Firebug.Module, +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + element: null, + isMultiLine: false, + isActive: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + initialize: function(doc) + { + this.clear = bind(this.clear, this); + this.enter = bind(this.enter, this); + + this.onError = bind(this.onError, this); + this.onKeyDown = bind(this.onKeyDown, this); + this.onMultiLineKeyDown = bind(this.onMultiLineKeyDown, this); + + addEvent(Firebug.browser.window, "error", this.onError); + addEvent(Firebug.chrome.window, "error", this.onError); + }, + + shutdown: function(doc) + { + this.deactivate(); + + removeEvent(Firebug.browser.window, "error", this.onError); + removeEvent(Firebug.chrome.window, "error", this.onError); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + activate: function(multiLine, hideToggleIcon, onRun) + { + defineCommandLineAPI(); + + if (this.isActive) + { + if (this.isMultiLine == multiLine) return; + + this.deactivate(); + } + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + if (multiLine) + { + onRun = onRun || this.enter; + + this.isMultiLine = true; + + this.element = fbLargeCommandLine; + + addEvent(this.element, "keydown", this.onMultiLineKeyDown); + + addEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton = new Button({ + element: $("fbCommand_btRun"), + owner: Firebug.CommandLine, + onClick: onRun + }); + + this.runButton.initialize(); + + this.clearButton = new Button({ + element: $("fbCommand_btClear"), + owner: Firebug.CommandLine, + onClick: this.clear + }); + + this.clearButton.initialize(); + } + else + { + this.isMultiLine = false; + this.element = fbCommandLine; + + if (!fbCommandLine) + return; + + addEvent(this.element, "keydown", this.onKeyDown); + } + + //Firebug.Console.log("activate", this.element); + + if (isOpera) + fixOperaTabKey(this.element); + + if(this.lastValue) + this.element.value = this.lastValue; + + this.isActive = true; + }, + + deactivate: function() + { + if (!this.isActive) return; + + //Firebug.Console.log("deactivate", this.element); + + this.isActive = false; + + this.lastValue = this.element.value; + + if (this.isMultiLine) + { + removeEvent(this.element, "keydown", this.onMultiLineKeyDown); + + removeEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton.destroy(); + this.clearButton.destroy(); + } + else + { + removeEvent(this.element, "keydown", this.onKeyDown); + } + + this.element = null + delete this.element; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focus: function() + { + this.element.focus(); + }, + + blur: function() + { + this.element.blur(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + clear: function() + { + this.element.value = ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + evaluate: function(expr) + { + // TODO: need to register the API in console.firebug.commandLineAPI + var api = "Firebug.CommandLine.API" + + var result = Firebug.context.evaluate(expr, "window", api, Firebug.Console.error); + + return result; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + enter: function() + { + var command = this.element.value; + + if (!command) return; + + _stack(command); + + Firebug.Console.log(commandPrefix + " " + stripNewLines(command), Firebug.browser, "command", FirebugReps.Text); + + var result = this.evaluate(command); + + Firebug.Console.log(result); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + prevCommand: function() + { + if (commandPointer > 0 && commandHistory.length > 0) + this.element.value = commandHistory[--commandPointer]; + }, + + nextCommand: function() + { + var element = this.element; + + var limit = commandHistory.length -1; + var i = commandPointer; + + if (i < limit) + element.value = commandHistory[++commandPointer]; + + else if (i == limit) + { + ++commandPointer; + element.value = ""; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + autocomplete: function(reverse) + { + var element = this.element; + + var command = element.value; + var offset = getExpressionOffset(command); + + var valBegin = offset ? command.substr(0, offset) : ""; + var val = command.substr(offset); + + var buffer, obj, objName, commandBegin, result, prefix; + + // if it is the beginning of the completion + if(!isAutoCompleting) + { + + // group1 - command begin + // group2 - base object + // group3 - property prefix + var reObj = /(.*[^_$\w\d\.])?((?:[_$\w][_$\w\d]*\.)*)([_$\w][_$\w\d]*)?$/; + var r = reObj.exec(val); + + // parse command + if (r[1] || r[2] || r[3]) + { + commandBegin = r[1] || ""; + objName = r[2] || ""; + prefix = r[3] || ""; + } + else if (val == "") + { + commandBegin = objName = prefix = ""; + } else + return; + + isAutoCompleting = true; + + // find base object + if(objName == "") + obj = window; + + else + { + objName = objName.replace(/\.$/, ""); + + var n = objName.split("."); + var target = window, o; + + for (var i=0, ni; ni = n[i]; i++) + { + if (o = target[ni]) + target = o; + + else + { + target = null; + break; + } + } + obj = target; + } + + // map base object + if(obj) + { + autoCompletePrefix = prefix; + autoCompleteExpr = valBegin + commandBegin + (objName ? objName + "." : ""); + autoCompletePosition = -1; + + buffer = autoCompleteBuffer = isIE ? + _completion[objName || "window"] || [] : []; + + for(var p in obj) + buffer.push(p); + } + + // if it is the continuation of the last completion + } else + buffer = autoCompleteBuffer; + + if (buffer) + { + prefix = autoCompletePrefix; + + var diff = reverse ? -1 : 1; + + for(var i=autoCompletePosition+diff, l=buffer.length, bi; i>=0 && i', msg, '', + '' + ]; + + // TODO: xxxpedro ajust to Console2 + //Firebug.Console.writeRow(html, "error"); + }, + + onKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + /*tab, shift, control, alt*/ + if (code != 9 && code != 16 && code != 17 && code != 18) + { + isAutoCompleting = false; + } + + if (code == 13 /* enter */) + { + this.enter(); + this.clear(); + } + else if (code == 27 /* ESC */) + { + setTimeout(this.clear, 0); + } + else if (code == 38 /* up */) + { + this.prevCommand(); + } + else if (code == 40 /* down */) + { + this.nextCommand(); + } + else if (code == 9 /* tab */) + { + this.autocomplete(e.shiftKey); + } + else + return; + + cancelEvent(e, true); + return false; + }, + + onMultiLineKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + if (code == 13 /* enter */ && e.ctrlKey) + { + this.enter(); + } + } +}); + +Firebug.registerModule(Firebug.CommandLine); + + +// ************************************************************************************************ +// + +function getExpressionOffset(command) +{ + // XXXjoe This is kind of a poor-man's JavaScript parser - trying + // to find the start of the expression that the cursor is inside. + // Not 100% fool proof, but hey... + + var bracketCount = 0; + + var start = command.length-1; + for (; start >= 0; --start) + { + var c = command[start]; + if ((c == "," || c == ";" || c == " ") && !bracketCount) + break; + if (reOpenBracket.test(c)) + { + if (bracketCount) + --bracketCount; + else + break; + } + else if (reCloseBracket.test(c)) + ++bracketCount; + } + + return start + 1; +} + +// ************************************************************************************************ +// CommandLine API + +var CommandLineAPI = +{ + $: function(id) + { + return Firebug.browser.document.getElementById(id) + }, + + $$: function(selector, context) + { + context = context || Firebug.browser.document; + return Firebug.Selector ? + Firebug.Selector(selector, context) : + Firebug.Console.error("Firebug.Selector module not loaded."); + }, + + $0: null, + + $1: null, + + dir: function(o) + { + Firebug.Console.log(o, Firebug.context, "dir", Firebug.DOMPanel.DirTable); + }, + + dirxml: function(o) + { + ///if (o instanceof Window) + if (instanceOf(o, "Window")) + o = o.document.documentElement; + ///else if (o instanceof Document) + else if (instanceOf(o, "Document")) + o = o.documentElement; + + // TODO: xxxpedro html3 + ///Firebug.Console.log(o, Firebug.context, "dirxml", Firebug.HTMLPanel.SoloElement); + var div = Firebug.Console.log(o, Firebug.context, "dirxml"); + var html = []; + Firebug.Reps.appendNode(o, html); + div.innerHTML = html.join(""); + + } +}; + +// ************************************************************************************************ + +var defineCommandLineAPI = function defineCommandLineAPI() +{ + Firebug.CommandLine.API = {}; + for (var m in CommandLineAPI) + if (!Env.browser.window[m]) + Firebug.CommandLine.API[m] = CommandLineAPI[m]; + + var stack = FirebugChrome.htmlSelectionStack; + if (stack) + { + Firebug.CommandLine.API.$0 = stack[0]; + Firebug.CommandLine.API.$1 = stack[1]; + } +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +if (Env.Options.disableXHRListener) + return; + +// ************************************************************************************************ +// XHRSpy + +var XHRSpy = function() +{ + this.requestHeaders = []; + this.responseHeaders = []; +}; + +XHRSpy.prototype = +{ + method: null, + url: null, + async: null, + + xhrRequest: null, + + href: null, + + loaded: false, + + logRow: null, + + responseText: null, + + requestHeaders: null, + responseHeaders: null, + + sourceLink: null, // {href:"file.html", line: 22} + + getURL: function() + { + return this.href; + } +}; + +// ************************************************************************************************ +// XMLHttpRequestWrapper + +var XMLHttpRequestWrapper = function(activeXObject) +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal variables + + var xhrRequest = typeof activeXObject != "undefined" ? + activeXObject : + new _XMLHttpRequest(), + + spy = new XHRSpy(), + + self = this, + + reqType, + reqUrl, + reqStartTS; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal methods + + var updateSelfPropertiesIgnore = { + abort: 1, + channel: 1, + getAllResponseHeaders: 1, + getInterface: 1, + getResponseHeader: 1, + mozBackgroundRequest: 1, + multipart: 1, + onreadystatechange: 1, + open: 1, + send: 1, + setRequestHeader: 1 + }; + + var updateSelfProperties = function() + { + if (supportsXHRIterator) + { + for (var propName in xhrRequest) + { + if (propName in updateSelfPropertiesIgnore) + continue; + + try + { + var propValue = xhrRequest[propName]; + + if (propValue && !isFunction(propValue)) + self[propName] = propValue; + } + catch(E) + { + //console.log(propName, E.message); + } + } + } + else + { + // will fail to read these xhrRequest properties if the request is not completed + if (xhrRequest.readyState == 4) + { + self.status = xhrRequest.status; + self.statusText = xhrRequest.statusText; + self.responseText = xhrRequest.responseText; + self.responseXML = xhrRequest.responseXML; + } + } + }; + + var updateXHRPropertiesIgnore = { + channel: 1, + onreadystatechange: 1, + readyState: 1, + responseBody: 1, + responseText: 1, + responseXML: 1, + status: 1, + statusText: 1, + upload: 1 + }; + + var updateXHRProperties = function() + { + for (var propName in self) + { + if (propName in updateXHRPropertiesIgnore) + continue; + + try + { + var propValue = self[propName]; + + if (propValue && !xhrRequest[propName]) + { + xhrRequest[propName] = propValue; + } + } + catch(E) + { + //console.log(propName, E.message); + } + } + }; + + var logXHR = function() + { + var row = Firebug.Console.log(spy, null, "spy", Firebug.Spy.XHR); + + if (row) + { + setClass(row, "loading"); + spy.logRow = row; + } + }; + + var finishXHR = function() + { + var duration = new Date().getTime() - reqStartTS; + var success = xhrRequest.status == 200; + + var responseHeadersText = xhrRequest.getAllResponseHeaders(); + var responses = responseHeadersText ? responseHeadersText.split(/[\n\r]/) : []; + var reHeader = /^(\S+):\s*(.*)/; + + for (var i=0, l=responses.length; i 0; + + /**/ + + return this; +}; + +// ************************************************************************************************ +// ActiveXObject Wrapper (IE6 only) + +var _ActiveXObject; +var isIE6 = /msie 6/i.test(navigator.appVersion); + +if (isIE6) +{ + _ActiveXObject = window.ActiveXObject; + + var xhrObjects = " MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP "; + + window.ActiveXObject = function(name) + { + var error = null; + + try + { + var activeXObject = new _ActiveXObject(name); + } + catch(e) + { + error = e; + } + finally + { + if (!error) + { + if (xhrObjects.indexOf(" " + name + " ") != -1) + return new XMLHttpRequestWrapper(activeXObject); + else + return activeXObject; + } + else + throw error.message; + } + }; +} + +// ************************************************************************************************ + +// Register the XMLHttpRequestWrapper for non-IE6 browsers +if (!isIE6) +{ + var _XMLHttpRequest = XMLHttpRequest; + window.XMLHttpRequest = function() + { + return new XMLHttpRequestWrapper(); + }; +} + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var reIgnore = /about:|javascript:|resource:|chrome:|jar:/; +var layoutInterval = 300; +var indentWidth = 18; + +var cacheSession = null; +var contexts = new Array(); +var panelName = "net"; +var maxQueueRequests = 500; +//var panelBar1 = $("fbPanelBar1"); // chrome not available at startup +var activeRequests = []; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var mimeExtensionMap = +{ + "txt": "text/plain", + "html": "text/html", + "htm": "text/html", + "xhtml": "text/html", + "xml": "text/xml", + "css": "text/css", + "js": "application/x-javascript", + "jss": "application/x-javascript", + "jpg": "image/jpg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "png": "image/png", + "bmp": "image/bmp", + "swf": "application/x-shockwave-flash", + "flv": "video/x-flv" +}; + +var fileCategories = +{ + "undefined": 1, + "html": 1, + "css": 1, + "js": 1, + "xhr": 1, + "image": 1, + "flash": 1, + "txt": 1, + "bin": 1 +}; + +var textFileCategories = +{ + "txt": 1, + "html": 1, + "xhr": 1, + "css": 1, + "js": 1 +}; + +var binaryFileCategories = +{ + "bin": 1, + "flash": 1 +}; + +var mimeCategoryMap = +{ + "text/plain": "txt", + "application/octet-stream": "bin", + "text/html": "html", + "text/xml": "html", + "text/css": "css", + "application/x-javascript": "js", + "text/javascript": "js", + "application/javascript" : "js", + "image/jpeg": "image", + "image/jpg": "image", + "image/gif": "image", + "image/png": "image", + "image/bmp": "image", + "application/x-shockwave-flash": "flash", + "video/x-flv": "flash" +}; + +var binaryCategoryMap = +{ + "image": 1, + "flash" : 1 +}; + +// ************************************************************************************************ + +/** + * @module Represents a module object for the Net panel. This object is derived + * from Firebug.ActivableModule in order to support activation (enable/disable). + * This allows to avoid (performance) expensive features if the functionality is not necessary + * for the user. + */ +Firebug.NetMonitor = extend(Firebug.ActivableModule, +{ + dispatchName: "netMonitor", + + clear: function(context) + { + // The user pressed a Clear button so, remove content of the panel... + var panel = context.getPanel(panelName, true); + if (panel) + panel.clear(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + return; + + this.panelName = panelName; + + Firebug.ActivableModule.initialize.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + // HTTP observer must be registered now (and not in monitorContext, since if a + // page is opened in a new tab the top document request would be missed otherwise. + NetHttpObserver.registerObserver(); + NetHttpActivityObserver.registerObserver(); + + Firebug.Debugger.addListener(this.DebuggerListener); + }, + + shutdown: function() + { + return; + + prefs.removeObserver(Firebug.prefDomain, this, false); + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + + NetHttpObserver.unregisterObserver(); + NetHttpActivityObserver.unregisterObserver(); + + Firebug.Debugger.removeListener(this.DebuggerListener); + } +}); + + +/** + * @domplate Represents a template that is used to reneder detailed info about a request. + * This template is rendered when a request is expanded. + */ +Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep, new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoBody", _repObject: "$file"}, + TAG("$infoTabs", {file: "$file"}), + TAG("$infoBodies", {file: "$file"}) + ), + + infoTabs: + DIV({"class": "netInfoTabs focusRow subFocusRow", "role": "tablist"}, + A({"class": "netInfoParamsTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Params", + $collapsed: "$file|hideParams"}, + $STR("URLParameters") + ), + A({"class": "netInfoHeadersTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Headers"}, + $STR("Headers") + ), + A({"class": "netInfoPostTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Post", + $collapsed: "$file|hidePost"}, + $STR("Post") + ), + A({"class": "netInfoPutTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Put", + $collapsed: "$file|hidePut"}, + $STR("Put") + ), + A({"class": "netInfoResponseTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Response", + $collapsed: "$file|hideResponse"}, + $STR("Response") + ), + A({"class": "netInfoCacheTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Cache", + $collapsed: "$file|hideCache"}, + $STR("Cache") + ), + A({"class": "netInfoHtmlTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Html", + $collapsed: "$file|hideHtml"}, + $STR("HTML") + ) + ), + + infoBodies: + DIV({"class": "netInfoBodies outerFocusRow"}, + TABLE({"class": "netInfoParamsText netInfoText netInfoParamsTable", "role": "tabpanel", + cellpadding: 0, cellspacing: 0}, TBODY()), + DIV({"class": "netInfoHeadersText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPostText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPutText netInfoText", "role": "tabpanel"}), + PRE({"class": "netInfoResponseText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoCacheText netInfoText", "role": "tabpanel"}, + TABLE({"class": "netInfoCacheTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("Cache")}) + ) + ), + DIV({"class": "netInfoHtmlText netInfoText", "role": "tabpanel"}, + IFRAME({"class": "netInfoHtmlPreview", "role": "document"}) + ) + ), + + headerDataTag: + FOR("param", "$headers", + TR({"role": "listitem"}, + TD({"class": "netInfoParamName", "role": "presentation"}, + TAG("$param|getNameTag", {param: "$param"}) + ), + TD({"class": "netInfoParamValue", "role": "list", "aria-label": "$param.name"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class": "focusRow subFocusRow", "role": "listitem"}, "$line") + ) + ) + ) + ), + + customTab: + A({"class": "netInfo$tabId\\Tab netInfoTab", onclick: "$onClickTab", view: "$tabId", "role": "tab"}, + "$tabTitle" + ), + + customBody: + DIV({"class": "netInfo$tabId\\Text netInfoText", "role": "tabpanel"}), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + nameTag: + SPAN("$param|getParamName"), + + nameWithTooltipTag: + SPAN({title: "$param.name"}, "$param|getParamName"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getNameTag: function(param) + { + return (this.getParamName(param) == param.name) ? this.nameTag : this.nameWithTooltipTag; + }, + + getParamName: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + name = name.substr(0, limit) + "..."; + return name; + }, + + getParamTitle: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + return name; + return ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + hideParams: function(file) + { + return !file.urlParams || !file.urlParams.length; + }, + + hidePost: function(file) + { + return file.method.toUpperCase() != "POST"; + }, + + hidePut: function(file) + { + return file.method.toUpperCase() != "PUT"; + }, + + hideResponse: function(file) + { + return false; + //return file.category in binaryFileCategories; + }, + + hideCache: function(file) + { + return true; + //xxxHonza: I don't see any reason why not to display the cache also info for images. + return !file.cacheEntry; // || file.category=="image"; + }, + + hideHtml: function(file) + { + return (file.mimeType != "text/html") && (file.mimeType != "application/xhtml+xml"); + }, + + onClickTab: function(event) + { + this.selectTab(event.currentTarget || event.srcElement); + }, + + getParamValueIterator: function(param) + { + // TODO: xxxpedro console2 + return param.value; + + // This value is inserted into CODE element and so, make sure the HTML isn't escaped (1210). + // This is why the second parameter is true. + // The CODE (with style white-space:pre) element preserves whitespaces so they are + // displayed the same, as they come from the server (1194). + // In case of a long header values of post parameters the value must be wrapped (2105). + return wrapText(param.value, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + appendTab: function(netInfoBox, tabId, tabTitle) + { + // Create new tab and body. + var args = {tabId: tabId, tabTitle: tabTitle}; + ///this.customTab.append(args, netInfoBox.getElementsByClassName("netInfoTabs").item(0)); + ///this.customBody.append(args, netInfoBox.getElementsByClassName("netInfoBodies").item(0)); + this.customTab.append(args, $$(".netInfoTabs", netInfoBox)[0]); + this.customBody.append(args, $$(".netInfoBodies", netInfoBox)[0]); + }, + + selectTabByName: function(netInfoBox, tabName) + { + var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab"); + if (tab) + this.selectTab(tab); + }, + + selectTab: function(tab) + { + var view = tab.getAttribute("view"); + + var netInfoBox = getAncestorByClass(tab, "netInfoBody"); + + var selectedTab = netInfoBox.selectedTab; + + if (selectedTab) + { + //netInfoBox.selectedText.removeAttribute("selected"); + removeClass(netInfoBox.selectedText, "netInfoTextSelected"); + + removeClass(selectedTab, "netInfoTabSelected"); + //selectedTab.removeAttribute("selected"); + selectedTab.setAttribute("aria-selected", "false"); + } + + var textBodyName = "netInfo" + view + "Text"; + + selectedTab = netInfoBox.selectedTab = tab; + + netInfoBox.selectedText = $$("."+textBodyName, netInfoBox)[0]; + //netInfoBox.selectedText = netInfoBox.getElementsByClassName(textBodyName).item(0); + + //netInfoBox.selectedText.setAttribute("selected", "true"); + setClass(netInfoBox.selectedText, "netInfoTextSelected"); + + setClass(selectedTab, "netInfoTabSelected"); + selectedTab.setAttribute("selected", "true"); + selectedTab.setAttribute("aria-selected", "true"); + + var file = Firebug.getRepObject(netInfoBox); + + //var context = Firebug.getElementPanel(netInfoBox).context; + var context = Firebug.chrome; + + this.updateInfo(netInfoBox, file, context); + }, + + updateInfo: function(netInfoBox, file, context) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.updateInfo; file", file); + + if (!netInfoBox) + { + if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS) + FBTrace.sysout("net.updateInfo; ERROR netInfo == null " + file.href, file); + return; + } + + var tab = netInfoBox.selectedTab; + + if (hasClass(tab, "netInfoParamsTab")) + { + if (file.urlParams && !netInfoBox.urlParamsPresented) + { + netInfoBox.urlParamsPresented = true; + this.insertHeaderRows(netInfoBox, file.urlParams, "Params"); + } + } + + else if (hasClass(tab, "netInfoHeadersTab")) + { + var headersText = $$(".netInfoHeadersText", netInfoBox)[0]; + //var headersText = netInfoBox.getElementsByClassName("netInfoHeadersText").item(0); + + if (file.responseHeaders && !netInfoBox.responseHeadersPresented) + { + netInfoBox.responseHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.responseHeaders, "ResponseHeaders"); + } + + if (file.requestHeaders && !netInfoBox.requestHeadersPresented) + { + netInfoBox.requestHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.requestHeaders, "RequestHeaders"); + } + } + + else if (hasClass(tab, "netInfoPostTab")) + { + if (!netInfoBox.postPresented) + { + netInfoBox.postPresented = true; + //var postText = netInfoBox.getElementsByClassName("netInfoPostText").item(0); + var postText = $$(".netInfoPostText", netInfoBox)[0]; + NetInfoPostData.render(context, postText, file); + } + } + + else if (hasClass(tab, "netInfoPutTab")) + { + if (!netInfoBox.putPresented) + { + netInfoBox.putPresented = true; + //var putText = netInfoBox.getElementsByClassName("netInfoPutText").item(0); + var putText = $$(".netInfoPutText", netInfoBox)[0]; + NetInfoPostData.render(context, putText, file); + } + } + + else if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented) + { + ///var responseTextBox = netInfoBox.getElementsByClassName("netInfoResponseText").item(0); + var responseTextBox = $$(".netInfoResponseText", netInfoBox)[0]; + if (file.category == "image") + { + netInfoBox.responsePresented = true; + + var responseImage = netInfoBox.ownerDocument.createElement("img"); + responseImage.src = file.href; + + clearNode(responseTextBox); + responseTextBox.appendChild(responseImage, responseTextBox); + } + else ///if (!(binaryCategoryMap.hasOwnProperty(file.category))) + { + this.setResponseText(file, netInfoBox, responseTextBox, context); + } + } + + else if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented) + { + var responseTextBox = netInfoBox.getElementsByClassName("netInfoCacheText").item(0); + if (file.cacheEntry) { + netInfoBox.cachePresented = true; + this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache"); + } + } + + else if (hasClass(tab, "netInfoHtmlTab") && file.loaded && !netInfoBox.htmlPresented) + { + netInfoBox.htmlPresented = true; + + var text = Utils.getResponseText(file, context); + + ///var iframe = netInfoBox.getElementsByClassName("netInfoHtmlPreview").item(0); + var iframe = $$(".netInfoHtmlPreview", netInfoBox)[0]; + + ///iframe.contentWindow.document.body.innerHTML = text; + + // TODO: xxxpedro net - remove scripts + var reScript = //gi; + + text = text.replace(reScript, ""); + + iframe.contentWindow.document.write(text); + iframe.contentWindow.document.close(); + } + + // Notify listeners about update so, content of custom tabs can be updated. + dispatch(NetInfoBody.fbListeners, "updateTabBody", [netInfoBox, file, context]); + }, + + setResponseText: function(file, netInfoBox, responseTextBox, context) + { + //********************************************** + //********************************************** + //********************************************** + netInfoBox.responsePresented = true; + // line breaks somehow are different in IE + // make this only once in the initialization? we don't have net panels and modules yet. + if (isIE) + responseTextBox.style.whiteSpace = "nowrap"; + + responseTextBox[ + typeof responseTextBox.textContent != "undefined" ? + "textContent" : + "innerText" + ] = file.responseText; + + return; + //********************************************** + //********************************************** + //********************************************** + + // Get response text and make sure it doesn't exceed the max limit. + var text = Utils.getResponseText(file, context); + var limit = Firebug.netDisplayedResponseLimit + 15; + var limitReached = text ? (text.length > limit) : false; + if (limitReached) + text = text.substr(0, limit) + "..."; + + // Insert the response into the UI. + if (text) + insertWrappedText(text, responseTextBox); + else + insertWrappedText("", responseTextBox); + + // Append a message informing the user that the response isn't fully displayed. + if (limitReached) + { + var object = { + text: $STR("net.responseSizeLimitMessage"), + onClickLink: function() { + var panel = context.getPanel("net", true); + panel.openResponseInTab(file); + } + }; + Firebug.NetMonitor.ResponseSizeLimit.append(object, responseTextBox); + } + + netInfoBox.responsePresented = true; + + if (FBTrace.DBG_NET) + FBTrace.sysout("net.setResponseText; response text updated"); + }, + + insertHeaderRows: function(netInfoBox, headers, tableName, rowName) + { + if (!headers.length) + return; + + var headersTable = $$(".netInfo"+tableName+"Table", netInfoBox)[0]; + //var headersTable = netInfoBox.getElementsByClassName("netInfo"+tableName+"Table").item(0); + var tbody = getChildByClass(headersTable, "netInfo" + rowName + "Body"); + if (!tbody) + tbody = headersTable.firstChild; + var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title"); + + this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody); + removeClass(titleRow, "collapsed"); + } +}); + +var NetInfoBody = Firebug.NetMonitor.NetInfoBody; + +// ************************************************************************************************ + +/** + * @domplate Used within the Net panel to display raw source of request and response headers + * as well as pretty-formatted summary of these headers. + */ +Firebug.NetMonitor.NetInfoHeaders = domplate(Firebug.Rep, //new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoHeadersTable", "role": "tabpanel"}, + DIV({"class": "netInfoHeadersGroup netInfoResponseHeadersTitle"}, + SPAN($STR("ResponseHeaders")), + SPAN({"class": "netHeadersViewSource response collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "ResponseHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoResponseHeadersBody", "role": "list", + "aria-label": $STR("ResponseHeaders")}) + ), + DIV({"class": "netInfoHeadersGroup netInfoRequestHeadersTitle"}, + SPAN($STR("RequestHeaders")), + SPAN({"class": "netHeadersViewSource request collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "RequestHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoRequestHeadersBody", "role": "list", + "aria-label": $STR("RequestHeaders")}) + ) + ), + + sourceTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + PRE({"class": "source"}) + ) + ), + + onViewSource: function(event) + { + var target = event.target; + var requestHeaders = (target.rowName == "RequestHeaders"); + + var netInfoBox = getAncestorByClass(target, "netInfoBody"); + var file = netInfoBox.repObject; + + if (target.sourceDisplayed) + { + var headers = requestHeaders ? file.requestHeaders : file.responseHeaders; + this.insertHeaderRows(netInfoBox, headers, target.rowName); + target.innerHTML = $STR("net.headers.view source"); + } + else + { + var source = requestHeaders ? file.requestHeadersText : file.responseHeadersText; + this.insertSource(netInfoBox, source, target.rowName); + target.innerHTML = $STR("net.headers.pretty print"); + } + + target.sourceDisplayed = !target.sourceDisplayed; + + cancelEvent(event); + }, + + insertSource: function(netInfoBox, source, rowName) + { + // This breaks copy to clipboard. + //if (source) + // source = source.replace(/\r\n/gm, "\\r\\n\r\n"); + + ///var tbody = netInfoBox.getElementsByClassName("netInfo" + rowName + "Body").item(0); + var tbody = $$(".netInfo" + rowName + "Body", netInfoBox)[0]; + var node = this.sourceTag.replace({}, tbody); + ///var sourceNode = node.getElementsByClassName("source").item(0); + var sourceNode = $$(".source", node)[0]; + sourceNode.innerHTML = source; + }, + + insertHeaderRows: function(netInfoBox, headers, rowName) + { + var headersTable = $$(".netInfoHeadersTable", netInfoBox)[0]; + var tbody = $$(".netInfo" + rowName + "Body", headersTable)[0]; + + //var headersTable = netInfoBox.getElementsByClassName("netInfoHeadersTable").item(0); + //var tbody = headersTable.getElementsByClassName("netInfo" + rowName + "Body").item(0); + + clearNode(tbody); + + if (!headers.length) + return; + + NetInfoBody.headerDataTag.insertRows({headers: headers}, tbody); + + var titleRow = getChildByClass(headersTable, "netInfo" + rowName + "Title"); + removeClass(titleRow, "collapsed"); + }, + + init: function(parent) + { + var rootNode = this.tag.append({}, parent); + + var netInfoBox = getAncestorByClass(parent, "netInfoBody"); + var file = netInfoBox.repObject; + + var viewSource; + + viewSource = $$(".request", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource request").item(0); + if (file.requestHeadersText) + removeClass(viewSource, "collapsed"); + + viewSource = $$(".response", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource response").item(0); + if (file.responseHeadersText) + removeClass(viewSource, "collapsed"); + }, + + renderHeaders: function(parent, headers, rowName) + { + if (!parent.firstChild) + this.init(parent); + + this.insertHeaderRows(parent, headers, rowName); + } +}); + +var NetInfoHeaders = Firebug.NetMonitor.NetInfoHeaders; + +// ************************************************************************************************ + +/** + * @domplate Represents posted data within request info (the info, which is visible when + * a request entry is expanded. This template renders content of the Post tab. + */ +Firebug.NetMonitor.NetInfoPostData = domplate(Firebug.Rep, /*new Firebug.Listener(),*/ +{ + // application/x-www-form-urlencoded + paramsTable: + TABLE({"class": "netInfoPostParamsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parameters")}, + TR({"class": "netInfoPostParamsTitle", "role": "presentation"}, + TD({colspan: 3, "role": "presentation"}, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parameters"), + SPAN({"class": "netInfoPostContentType"}, + "application/x-www-form-urlencoded" + ) + ) + ) + ) + ) + ), + + // multipart/form-data + partsTable: + TABLE({"class": "netInfoPostPartsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parts")}, + TR({"class": "netInfoPostPartsTitle", "role": "presentation"}, + TD({colspan: 2, "role":"presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parts"), + SPAN({"class": "netInfoPostContentType"}, + "multipart/form-data" + ) + ) + ) + ) + ) + ), + + // application/json + jsonTable: + TABLE({"class": "netInfoPostJSONTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + ///TBODY({"role": "list", "aria-label": $STR("jsonviewer.tab.JSON")}, + TBODY({"role": "list", "aria-label": $STR("JSON")}, + TR({"class": "netInfoPostJSONTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + ///$STR("jsonviewer.tab.JSON") + $STR("JSON") + ) + ) + ), + TR( + TD({"class": "netInfoPostJSONBody"}) + ) + ) + ), + + // application/xml + xmlTable: + TABLE({"class": "netInfoPostXMLTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("xmlviewer.tab.XML")}, + TR({"class": "netInfoPostXMLTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("xmlviewer.tab.XML") + ) + ) + ), + TR( + TD({"class": "netInfoPostXMLBody"}) + ) + ) + ), + + sourceTable: + TABLE({"class": "netInfoPostSourceTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Source")}, + TR({"class": "netInfoPostSourceTitle", "role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + DIV({"class": "netInfoPostSource"}, + $STR("net.label.Source") + ) + ) + ) + ) + ), + + sourceBodyTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class":"focusRow subFocusRow" , "role": "listitem"},"$line") + ) + ) + ), + + getParamValueIterator: function(param) + { + return NetInfoBody.getParamValueIterator(param); + }, + + render: function(context, parentNode, file) + { + //debugger; + var spy = getAncestorByClass(parentNode, "spyHead"); + var spyObject = spy.repObject; + var data = spyObject.data; + + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + var contentType = file.mimeType; + + ///var text = Utils.getPostText(file, context, true); + ///if (text == undefined) + /// return; + + ///if (Utils.isURLEncodedRequest(file, context)) + // fake Utils.isURLEncodedRequest identification + if (contentType && contentType == "application/x-www-form-urlencoded" || + data && data.indexOf("=") != -1) + { + ///var lines = text.split("\n"); + ///var params = parseURLEncodedText(lines[lines.length-1]); + var params = parseURLEncodedTextArray(data); + if (params) + this.insertParameters(parentNode, params); + } + + ///if (Utils.isMultiPartRequest(file, context)) + ///{ + /// var data = this.parseMultiPartText(file, context); + /// if (data) + /// this.insertParts(parentNode, data); + ///} + + // moved to the top + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + + ///if (Firebug.JSONViewerModel.isJSON(contentType)) + var jsonData = { + responseText: data + }; + + if (Firebug.JSONViewerModel.isJSON(contentType, data)) + ///this.insertJSON(parentNode, file, context); + this.insertJSON(parentNode, jsonData, context); + + ///if (Firebug.XMLViewerModel.isXML(contentType)) + /// this.insertXML(parentNode, file, context); + + ///var postText = Utils.getPostText(file, context); + ///postText = Utils.formatPostText(postText); + var postText = data; + if (postText) + this.insertSource(parentNode, postText); + }, + + insertParameters: function(parentNode, params) + { + if (!params || !params.length) + return; + + var paramTable = this.paramsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostParamsTitle", paramTable)[0]; + //var paramTable = this.paramsTable.append(null, parentNode); + //var row = paramTable.getElementsByClassName("netInfoPostParamsTitle").item(0); + + var tbody = paramTable.getElementsByTagName("tbody")[0]; + + NetInfoBody.headerDataTag.insertRows({headers: params}, row); + }, + + insertParts: function(parentNode, data) + { + if (!data.params || !data.params.length) + return; + + var partsTable = this.partsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostPartsTitle", paramTable)[0]; + //var partsTable = this.partsTable.append(null, parentNode); + //var row = partsTable.getElementsByClassName("netInfoPostPartsTitle").item(0); + + NetInfoBody.headerDataTag.insertRows({headers: data.params}, row); + }, + + insertJSON: function(parentNode, file, context) + { + ///var text = Utils.getPostText(file, context); + var text = file.responseText; + ///var data = parseJSONString(text, "http://" + file.request.originalURI.host); + var data = parseJSONString(text); + if (!data) + return; + + ///var jsonTable = this.jsonTable.append(null, parentNode); + var jsonTable = this.jsonTable.append({}, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostJSONBody").item(0); + var jsonBody = $$(".netInfoPostJSONBody", jsonTable)[0]; + + if (!this.toggles) + this.toggles = {}; + + Firebug.DOMPanel.DirTable.tag.replace( + {object: data, toggles: this.toggles}, jsonBody); + }, + + insertXML: function(parentNode, file, context) + { + var text = Utils.getPostText(file, context); + + var jsonTable = this.xmlTable.append(null, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostXMLBody").item(0); + var jsonBody = $$(".netInfoPostXMLBody", jsonTable)[0]; + + Firebug.XMLViewerModel.insertXML(jsonBody, text); + }, + + insertSource: function(parentNode, text) + { + var sourceTable = this.sourceTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostSourceTitle", sourceTable)[0]; + //var sourceTable = this.sourceTable.append(null, parentNode); + //var row = sourceTable.getElementsByClassName("netInfoPostSourceTitle").item(0); + + var param = {value: [text]}; + this.sourceBodyTag.insertRows({param: param}, row); + }, + + parseMultiPartText: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text == undefined) + return null; + + FBTrace.sysout("net.parseMultiPartText; boundary: ", text); + + var boundary = text.match(/\s*boundary=\s*(.*)/)[1]; + + var divider = "\r\n\r\n"; + var bodyStart = text.indexOf(divider); + var body = text.substr(bodyStart + divider.length); + + var postData = {}; + postData.mimeType = "multipart/form-data"; + postData.params = []; + + var parts = body.split("--" + boundary); + for (var i=0; i 1) ? m[1] : "", + value: trim(part[1]) + }); + } + + return postData; + } +}); + +var NetInfoPostData = Firebug.NetMonitor.NetInfoPostData; + +// ************************************************************************************************ + + +// TODO: xxxpedro net i18n +var $STRP = function(a){return a;}; + +Firebug.NetMonitor.NetLimit = domplate(Firebug.Rep, +{ + collapsed: true, + + tableTag: + DIV( + TABLE({width: "100%", cellpadding: 0, cellspacing: 0}, + TBODY() + ) + ), + + limitTag: + TR({"class": "netRow netLimitRow", $collapsed: "$isCollapsed"}, + TD({"class": "netCol netLimitCol", colspan: 6}, + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY( + TR( + TD( + SPAN({"class": "netLimitLabel"}, + $STRP("plural.Limit_Exceeded", [0]) + ) + ), + TD({style: "width:100%"}), + TD( + BUTTON({"class": "netLimitButton", title: "$limitPrefsTitle", + onclick: "$onPreferences"}, + $STR("LimitPrefs") + ) + ), + TD(" ") + ) + ) + ) + ) + ), + + isCollapsed: function() + { + return this.collapsed; + }, + + onPreferences: function(event) + { + openNewTab("about:config"); + }, + + updateCounter: function(row) + { + removeClass(row, "collapsed"); + + // Update info within the limit row. + var limitLabel = row.getElementsByClassName("netLimitLabel").item(0); + limitLabel.firstChild.nodeValue = $STRP("plural.Limit_Exceeded", [row.limitInfo.totalCount]); + }, + + createTable: function(parent, limitInfo) + { + var table = this.tableTag.replace({}, parent); + var row = this.createRow(table.firstChild.firstChild, limitInfo); + return [table, row]; + }, + + createRow: function(parent, limitInfo) + { + var row = this.limitTag.insertRows(limitInfo, parent, this)[0]; + row.limitInfo = limitInfo; + return row; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + if (data.indexOf("net.logLimit") != -1) + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = Firebug.getPref(Firebug.prefDomain, "net.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + } +}); + +var NetLimit = Firebug.NetMonitor.NetLimit; + +// ************************************************************************************************ + +Firebug.NetMonitor.ResponseSizeLimit = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "netInfoResponseSizeLimit"}, + SPAN("$object.beforeLink"), + A({"class": "objectLink", onclick: "$onClickLink"}, + "$object.linkText" + ), + SPAN("$object.afterLink") + ), + + reLink: /^(.*)(.*)<\/a>(.*$)/, + append: function(obj, parent) + { + var m = obj.text.match(this.reLink); + return this.tag.append({onClickLink: obj.onClickLink, + object: { + beforeLink: m[1], + linkText: m[2], + afterLink: m[3] + }}, parent, this); + } +}); + +// ************************************************************************************************ +// ************************************************************************************************ + +Firebug.NetMonitor.Utils = +{ + findHeader: function(headers, name) + { + if (!headers) + return null; + + name = name.toLowerCase(); + for (var i = 0; i < headers.length; ++i) + { + var headerName = headers[i].name.toLowerCase(); + if (headerName == name) + return headers[i].value; + } + }, + + formatPostText: function(text) + { + if (text instanceof XMLDocument) + return getElementXML(text.documentElement); + else + return text; + }, + + getPostText: function(file, context, noLimit) + { + if (!file.postText) + { + file.postText = readPostTextFromRequest(file.request, context); + + if (!file.postText && context) + file.postText = readPostTextFromPage(file.href, context); + } + + if (!file.postText) + return file.postText; + + var limit = Firebug.netDisplayedPostBodyLimit; + if (file.postText.length > limit && !noLimit) + { + return cropString(file.postText, limit, + "\n\n... " + $STR("net.postDataSizeLimitMessage") + " ...\n\n"); + } + + return file.postText; + }, + + getResponseText: function(file, context) + { + // The response can be also empty string so, check agains "undefined". + return (typeof(file.responseText) != "undefined")? file.responseText : + context.sourceCache.loadText(file.href, file.method, file); + }, + + isURLEncodedRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded") == 0) + return true; + + // The header value doesn't have to be always exactly "application/x-www-form-urlencoded", + // there can be even charset specified. So, use indexOf rather than just "==". + var headerValue = Utils.findHeader(file.requestHeaders, "content-type"); + if (headerValue && headerValue.indexOf("application/x-www-form-urlencoded") == 0) + return true; + + return false; + }, + + isMultiPartRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: multipart/form-data") == 0) + return true; + return false; + }, + + getMimeType: function(mimeType, uri) + { + if (!mimeType || !(mimeCategoryMap.hasOwnProperty(mimeType))) + { + var ext = getFileExtension(uri); + if (!ext) + return mimeType; + else + { + var extMimeType = mimeExtensionMap[ext.toLowerCase()]; + return extMimeType ? extMimeType : mimeType; + } + } + else + return mimeType; + }, + + getDateFromSeconds: function(s) + { + var d = new Date(); + d.setTime(s*1000); + return d; + }, + + getHttpHeaders: function(request, file) + { + try + { + var http = QI(request, Ci.nsIHttpChannel); + file.status = request.responseStatus; + + // xxxHonza: is there any problem to do this in requestedFile method? + file.method = http.requestMethod; + file.urlParams = parseURLParams(file.href); + file.mimeType = Utils.getMimeType(request.contentType, request.name); + + if (!file.responseHeaders && Firebug.collectHttpHeaders) + { + var requestHeaders = [], responseHeaders = []; + + http.visitRequestHeaders({ + visitHeader: function(name, value) + { + requestHeaders.push({name: name, value: value}); + } + }); + http.visitResponseHeaders({ + visitHeader: function(name, value) + { + responseHeaders.push({name: name, value: value}); + } + }); + + file.requestHeaders = requestHeaders; + file.responseHeaders = responseHeaders; + } + } + catch (exc) + { + // An exception can be throwed e.g. when the request is aborted and + // request.responseStatus is accessed. + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("net.getHttpHeaders FAILS " + file.href, exc); + } + }, + + isXHR: function(request) + { + try + { + var callbacks = request.notificationCallbacks; + var xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null; + if (FBTrace.DBG_NET) + FBTrace.sysout("net.isXHR; " + (xhrRequest != null) + ", " + safeGetName(request)); + + return (xhrRequest != null); + } + catch (exc) + { + } + + return false; + }, + + getFileCategory: function(file) + { + if (file.category) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; current: " + file.category + " for: " + file.href, file); + return file.category; + } + + if (file.isXHR) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; XHR for: " + file.href, file); + return file.category = "xhr"; + } + + if (!file.mimeType) + { + var ext = getFileExtension(file.href); + if (ext) + file.mimeType = mimeExtensionMap[ext.toLowerCase()]; + } + + /*if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; " + mimeCategoryMap[file.mimeType] + + ", mimeType: " + file.mimeType + " for: " + file.href, file);*/ + + if (!file.mimeType) + return ""; + + // Solve cases when charset is also specified, eg "text/html; charset=UTF-8". + var mimeType = file.mimeType; + if (mimeType) + mimeType = mimeType.split(";")[0]; + + return (file.category = mimeCategoryMap[mimeType]); + } +}; + +var Utils = Firebug.NetMonitor.Utils; + +// ************************************************************************************************ + +//Firebug.registerRep(Firebug.NetMonitor.NetRequestTable); +//Firebug.registerActivableModule(Firebug.NetMonitor); +//Firebug.registerPanel(NetPanel); + +Firebug.registerModule(Firebug.NetMonitor); +//Firebug.registerRep(Firebug.NetMonitor.BreakpointRep); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +// List of contexts with XHR spy attached. +var contexts = []; + +// ************************************************************************************************ +// Spy Module + +/** + * @module Represents a XHR Spy module. The main purpose of the XHR Spy feature is to monitor + * XHR activity of the current page and create appropriate log into the Console panel. + * This feature can be controlled by an option Show XMLHttpRequests (from within the + * console panel). + * + * The module is responsible for attaching/detaching a HTTP Observers when Firebug is + * activated/deactivated for a site. + */ +Firebug.Spy = extend(Firebug.Module, +/** @lends Firebug.Spy */ +{ + dispatchName: "spy", + + initialize: function() + { + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + Firebug.Module.initialize.apply(this, arguments); + }, + + shutdown: function() + { + Firebug.Module.shutdown.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + }, + + initContext: function(context) + { + context.spies = []; + + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, context.window); + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.initContext " + contexts.length + " ", context.getName()); + }, + + destroyContext: function(context) + { + // For any spies that are in progress, remove our listeners so that they don't leak + this.detachObserver(context, null); + + if (FBTrace.DBG_SPY && context.spies.length) + FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies (" + + context.spies.length + ") " + context.getName()); + + delete context.spies; + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.destroyContext " + contexts.length + " ", context.getName()); + }, + + watchWindow: function(context, win) + { + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, win); + }, + + unwatchWindow: function(context, win) + { + try + { + // This make sure that the existing context is properly removed from "contexts" array. + this.detachObserver(context, win); + } + catch (ex) + { + // Get exceptions here sometimes, so let's just ignore them + // since the window is going away anyhow + ERROR(ex); + } + }, + + updateOption: function(name, value) + { + // XXXjjb Honza, if Console.isEnabled(context) false, then this can't be called, + // but somehow seems not correct + if (name == "showXMLHttpRequests") + { + var tach = value ? this.attachObserver : this.detachObserver; + for (var i = 0; i < TabWatcher.contexts.length; ++i) + { + var context = TabWatcher.contexts[i]; + iterateWindows(context.window, function(win) + { + tach.apply(this, [context, win]); + }); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Attaching Spy to XHR requests. + + /** + * Returns false if Spy should not be attached to XHRs executed by the specified window. + */ + skipSpy: function(win) + { + if (!win) + return true; + + // Don't attach spy to chrome. + var uri = safeGetWindowLocation(win); + if (uri && (uri.indexOf("about:") == 0 || uri.indexOf("chrome:") == 0)) + return true; + }, + + attachObserver: function(context, win) + { + if (Firebug.Spy.skipSpy(win)) + return; + + for (var i=0; insIHttpChannel. + * Returns null if the request doesn't represent XHR. + */ + getXHR: function(request) + { + // Does also query-interface for nsIHttpChannel. + if (!(request instanceof Ci.nsIHttpChannel)) + return null; + + try + { + var callbacks = request.notificationCallbacks; + return (callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null); + } + catch (exc) + { + if (exc.name == "NS_NOINTERFACE") + { + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.getXHR; Request is not nsIXMLHttpRequest: " + + safeGetRequestName(request)); + } + } + + return null; + } +}); + + + + + +// ************************************************************************************************ + +/* +function getSpyForXHR(request, xhrRequest, context, noCreate) +{ + var spy = null; + + // Iterate all existing spy objects in this context and look for one that is + // already created for this request. + var length = context.spies.length; + for (var i=0; i= 3) + { + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (netInfoBox) + { + netInfoBox.htmlPresented = false; + netInfoBox.responsePresented = false; + } + } + + // If the request is loading update the end time. + if (spy.xhrRequest.readyState == 3) + { + spy.responseTime = spy.endTime - spy.sendTime; + updateTime(spy); + } + + // Request loaded. Get all the info from the request now, just in case the + // XHR would be aborted in the original onReadyStateChange handler. + if (spy.xhrRequest.readyState == 4) + { + // Cumulate response so, multipart response content is properly displayed. + if (SpyHttpActivityObserver.getActivityDistributor()) + spy.responseText += spy.xhrRequest.responseText; + else + { + // xxxHonza: remove from FB 1.6 + if (!spy.responseText) + spy.responseText = spy.xhrRequest.responseText; + } + + // The XHR is loaded now (used also by the activity observer). + spy.loaded = true; + + // Update UI. + updateHttpSpyInfo(spy); + + // Notify Net pane about a request beeing loaded. + // xxxHonza: I don't think this is necessary. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.stopFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); + + // Notify registered listeners about finish of the XHR. + dispatch(Firebug.Spy.fbListeners, "onLoad", [spy.context, spy]); + } + + // Pass the event to the original page handler. + callPageHandler(spy, event, originalHandler); +} + +function onHTTPSpyLoad(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyLoad: " + spy.href, spy); + + // Detach must be done in onLoad (not in onreadystatechange) otherwise + // onAbort would not be handled. + spy.detach(); + + // xxxHonza: Still needed for Fx 3.5 (#502959) + if (!SpyHttpActivityObserver.getActivityDistributor()) + onHTTPSpyReadyStateChange(spy, null); +} + +function onHTTPSpyError(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyError; " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } +} + +function onHTTPSpyAbort(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyAbort: " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } + + spy.statusText = "Aborted"; + updateLogRow(spy); + + // Notify Net pane about a request beeing aborted. + // xxxHonza: the net panel shoud find out this itself. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.abortFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); +} +/**/ + +// ************************************************************************************************ + +/** + * @domplate Represents a template for XHRs logged in the Console panel. The body of the + * log (displayed when expanded) is rendered using {@link Firebug.NetMonitor.NetInfoBody}. + */ + +Firebug.Spy.XHR = domplate(Firebug.Rep, +/** @lends Firebug.Spy.XHR */ + +{ + tag: + DIV({"class": "spyHead", _repObject: "$object"}, + TABLE({"class": "spyHeadTable focusRow outerFocusRow", cellpadding: 0, cellspacing: 0, + "role": "listitem", "aria-expanded": "false"}, + TBODY({"role": "presentation"}, + TR({"class": "spyRow"}, + TD({"class": "spyTitleCol spyCol", onclick: "$onToggleBody"}, + DIV({"class": "spyTitle"}, + "$object|getCaption" + ), + DIV({"class": "spyFullTitle spyTitle"}, + "$object|getFullUri" + ) + ), + TD({"class": "spyCol"}, + DIV({"class": "spyStatus"}, "$object|getStatus") + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyIcon"}) + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyTime"}) + ), + TD({"class": "spyCol"}, + TAG(FirebugReps.SourceLink.tag, {object: "$object.sourceLink"}) + ) + ) + ) + ) + ), + + getCaption: function(spy) + { + return spy.method.toUpperCase() + " " + cropString(spy.getURL(), 100); + }, + + getFullUri: function(spy) + { + return spy.method.toUpperCase() + " " + spy.getURL(); + }, + + getStatus: function(spy) + { + var text = ""; + if (spy.statusCode) + text += spy.statusCode + " "; + + if (spy.statusText) + return text += spy.statusText; + + return text; + }, + + onToggleBody: function(event) + { + var target = event.currentTarget || event.srcElement; + var logRow = getAncestorByClass(target, "logRow-spy"); + + if (isLeftClick(event)) + { + toggleClass(logRow, "opened"); + + var spy = getChildByClass(logRow, "spyHead").repObject; + var spyHeadTable = getAncestorByClass(target, "spyHeadTable"); + + if (hasClass(logRow, "opened")) + { + updateHttpSpyInfo(spy, logRow); + if (spyHeadTable) + spyHeadTable.setAttribute('aria-expanded', 'true'); + } + else + { + //var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + //dispatch(Firebug.NetMonitor.NetInfoBody.fbListeners, "destroyTabBody", [netInfoBox, spy]); + //if (spyHeadTable) + // spyHeadTable.setAttribute('aria-expanded', 'false'); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(spy) + { + copyToClipboard(spy.getURL()); + }, + + copyParams: function(spy) + { + var text = spy.postText; + if (!text) + return; + + var url = reEncodeURL(spy, text, true); + copyToClipboard(url); + }, + + copyResponse: function(spy) + { + copyToClipboard(spy.responseText); + }, + + openInTab: function(spy) + { + openNewTab(spy.getURL(), spy.postText); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object) + { + // TODO: xxxpedro spy xhr + return false; + + return object instanceof Firebug.Spy.XMLHttpRequestSpy; + }, + + browseObject: function(spy, context) + { + var url = spy.getURL(); + openNewTab(url); + return true; + }, + + getRealObject: function(spy, context) + { + return spy.xhrRequest; + }, + + getContextMenuItems: function(spy) + { + var items = [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, spy) } + ]; + + if (spy.postText) + { + items.push( + {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, spy) } + ); + } + + items.push( + {label: "CopyResponse", command: bindFixed(this.copyResponse, this, spy) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, spy) } + ); + + return items; + } +}); + +// ************************************************************************************************ + +function updateTime(spy) +{ + var timeBox = spy.logRow.getElementsByClassName("spyTime").item(0); + if (spy.responseTime) + timeBox.textContent = " " + formatTime(spy.responseTime); +} + +function updateLogRow(spy) +{ + updateTime(spy); + + var statusBox = spy.logRow.getElementsByClassName("spyStatus").item(0); + statusBox.textContent = Firebug.Spy.XHR.getStatus(spy); + + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "loaded"); + + try + { + var errorRange = Math.floor(spy.xhrRequest.status/100); + if (errorRange == 4 || errorRange == 5) + setClass(spy.logRow, "error"); + } + catch (exc) + { + } +} + +var updateHttpSpyInfo = function updateHttpSpyInfo(spy, logRow) +{ + if (!spy.logRow && logRow) + spy.logRow = logRow; + + if (!spy.logRow || !hasClass(spy.logRow, "opened")) + return; + + if (!spy.params) + //spy.params = parseURLParams(spy.href+""); + spy.params = parseURLParams(spy.href+""); + + if (!spy.requestHeaders) + spy.requestHeaders = getRequestHeaders(spy); + + if (!spy.responseHeaders && spy.loaded) + spy.responseHeaders = getResponseHeaders(spy); + + var template = Firebug.NetMonitor.NetInfoBody; + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (!netInfoBox) + { + var head = getChildByClass(spy.logRow, "spyHead"); + netInfoBox = template.tag.append({"file": spy}, head); + dispatch(template.fbListeners, "initTabBody", [netInfoBox, spy]); + template.selectTabByName(netInfoBox, "Response"); + } + else + { + template.updateInfo(netInfoBox, spy, spy.context); + } +}; + + + +// ************************************************************************************************ + +function getRequestHeaders(spy) +{ + var headers = []; + + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitRequestHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + + return headers; +} + +function getResponseHeaders(spy) +{ + var headers = []; + + try + { + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitResponseHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + } + catch (exc) + { + if (FBTrace.DBG_SPY || FBTrace.DBG_ERRORS) + FBTrace.sysout("spy.getResponseHeaders; EXCEPTION " + + safeGetRequestName(spy.request), exc); + } + + return headers; +} + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.Spy); +//Firebug.registerRep(Firebug.Spy.XHR); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ + +// List of JSON content types. +var contentTypes = +{ + "text/plain": 1, + "text/javascript": 1, + "text/x-javascript": 1, + "text/json": 1, + "text/x-json": 1, + "application/json": 1, + "application/x-json": 1, + "application/javascript": 1, + "application/x-javascript": 1, + "application/json-rpc": 1 +}; + +// ************************************************************************************************ +// Model implementation + +Firebug.JSONViewerModel = extend(Firebug.Module, +{ + dispatchName: "jsonViewer", + initialize: function() + { + Firebug.NetMonitor.NetInfoBody.addListener(this); + + // Used by Firebug.DOMPanel.DirTable domplate. + this.toggles = {}; + }, + + shutdown: function() + { + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody", infoBox); + + // Let listeners to parse the JSON. + dispatch(this.fbListeners, "onParseJSON", [file]); + + // The JSON is still no there, try to parse most common cases. + if (!file.jsonObject) + { + ///if (this.isJSON(safeGetContentType(file.request), file.responseText)) + if (this.isJSON(file.mimeType, file.responseText)) + file.jsonObject = this.parseJSON(file); + } + + // The jsonObject is created so, the JSON tab can be displayed. + if (file.jsonObject && hasProperties(file.jsonObject)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "JSON", + ///$STR("jsonviewer.tab.JSON")); + $STR("JSON")); + + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody; JSON object available " + + (typeof(file.jsonObject) != "undefined"), file.jsonObject); + } + }, + + isJSON: function(contentType, data) + { + // Workaround for JSON responses without proper content type + // Let's consider all responses starting with "{" as JSON. In the worst + // case there will be an exception when parsing. This means that no-JSON + // responses (and post data) (with "{") can be parsed unnecessarily, + // which represents a little overhead, but this happens only if the request + // is actually expanded by the user in the UI (Net & Console panels). + + ///var responseText = data ? trimLeft(data) : null; + ///if (responseText && responseText.indexOf("{") == 0) + /// return true; + var responseText = data ? trim(data) : null; + if (responseText && responseText.indexOf("{") == 0) + return true; + + if (!contentType) + return false; + + contentType = contentType.split(";")[0]; + contentType = trim(contentType); + return contentTypes[contentType]; + }, + + // Update listener for TabView + updateTabBody: function(infoBox, file, context) + { + var tab = infoBox.selectedTab; + ///var tabBody = infoBox.getElementsByClassName("netInfoJSONText").item(0); + var tabBody = $$(".netInfoJSONText", infoBox)[0]; + if (!hasClass(tab, "netInfoJSONTab") || tabBody.updated) + return; + + tabBody.updated = true; + + if (file.jsonObject) { + Firebug.DOMPanel.DirTable.tag.replace( + {object: file.jsonObject, toggles: this.toggles}, tabBody); + } + }, + + parseJSON: function(file) + { + var jsonString = new String(file.responseText); + ///return parseJSONString(jsonString, "http://" + file.request.originalURI.host); + return parseJSONString(jsonString); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.JSONViewerModel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +// List of XML related content types. +var xmlContentTypes = +[ + "text/xml", + "application/xml", + "application/xhtml+xml", + "application/rss+xml", + "application/atom+xml",, + "application/vnd.mozilla.maybe.feed", + "application/rdf+xml", + "application/vnd.mozilla.xul+xml" +]; + +// ************************************************************************************************ +// Model implementation + +/** + * @module Implements viewer for XML based network responses. In order to create a new + * tab wihin network request detail, a listener is registered into + * Firebug.NetMonitor.NetInfoBody object. + */ +Firebug.XMLViewerModel = extend(Firebug.Module, +{ + dispatchName: "xmlViewer", + + initialize: function() + { + ///Firebug.ActivableModule.initialize.apply(this, arguments); + Firebug.Module.initialize.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.addListener(this); + }, + + shutdown: function() + { + ///Firebug.ActivableModule.shutdown.apply(this, arguments); + Firebug.Module.shutdown.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + /** + * Check response's content-type and if it's a XML, create a new tab with XML preview. + */ + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody", infoBox); + + // If the response is XML let's display a pretty preview. + ///if (this.isXML(safeGetContentType(file.request))) + if (this.isXML(file.mimeType, file.responseText)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML", + ///$STR("xmlviewer.tab.XML")); + $STR("XML")); + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody; XML response available"); + } + }, + + isXML: function(contentType) + { + if (!contentType) + return false; + + // Look if the response is XML based. + for (var i=0; i\s*/, ""); + + var div = parentNode.ownerDocument.createElement("div"); + div.innerHTML = xmlText; + + var root = div.getElementsByTagName("*")[0]; + + /*** + var parser = CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser"); + var doc = parser.parseFromString(text, "text/xml"); + var root = doc.documentElement; + + // Error handling + var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml"; + if (root.namespaceURI == nsURI && root.nodeName == "parsererror") + { + this.ParseError.tag.replace({error: { + message: root.firstChild.nodeValue, + source: root.lastChild.textContent + }}, parentNode); + return; + } + /**/ + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc); + + // Override getHidden in these templates. The parsed XML documen is + // hidden, but we want to display it using 'visible' styling. + /* + var templates = [ + Firebug.HTMLPanel.CompleteElement, + Firebug.HTMLPanel.Element, + Firebug.HTMLPanel.TextElement, + Firebug.HTMLPanel.EmptyElement, + Firebug.HTMLPanel.XEmptyElement, + ]; + + var originals = []; + for (var i=0; iFirebug.XMLViewerModel. + */ +Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "xmlInfoError"}, + DIV({"class": "xmlInfoErrorMsg"}, "$error.message"), + PRE({"class": "xmlInfoErrorSource"}, "$error|getSource") + ), + + getSource: function(error) + { + var parts = error.source.split("\n"); + if (parts.length != 2) + return error.source; + + var limit = 50; + var column = parts[1].length; + if (column >= limit) { + parts[0] = "..." + parts[0].substr(column - limit); + parts[1] = "..." + parts[1].substr(column - limit); + } + + if (parts[0].length > 80) + parts[0] = parts[0].substr(0, 80) + "..."; + + return parts.join("\n"); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.XMLViewerModel); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var ElementCache = Firebug.Lite.Cache.Element; +var cacheID = Firebug.Lite.Cache.ID; + +var ignoreHTMLProps = +{ + // ignores the attributes injected by Sizzle, otherwise it will + // be visible on IE (when enumerating element.attributes) + sizcache: 1, + sizset: 1 +}; + +// ignores also the cache property injected by firebug +ignoreHTMLProps[cacheID] = 1; + + +// ************************************************************************************************ +// HTML Module + +Firebug.HTML = extend(Firebug.Module, +{ + appendTreeNode: function(nodeArray, html) + { + var reTrim = /^\s+|\s+$/g; + + if (!nodeArray.length) nodeArray = [nodeArray]; + + for (var n=0, node; node=nodeArray[n]; n++) + { + if (node.nodeType == 1) + { + if (Firebug.ignoreFirebugElements && node.firebugIgnore) continue; + + var uid = ElementCache(node); + var child = node.childNodes; + var childLength = child.length; + + var nodeName = node.nodeName.toLowerCase(); + + var nodeVisible = isVisible(node); + + var hasSingleTextChild = childLength == 1 && node.firstChild.nodeType == 3 && + nodeName != "script" && nodeName != "style"; + + var nodeControl = !hasSingleTextChild && childLength > 0 ? + ('
      ') : ''; + + var isIE = false; + + if(isIE && nodeControl) + html.push(nodeControl); + + if (typeof uid != 'undefined') + html.push( + '
      ', + !isIE && nodeControl ? nodeControl: "", + '<', nodeName, '' + ); + else + html.push( + '
      <', + nodeName, '' + ); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || Firebug.ignoreFirebugElements && + ignoreHTMLProps.hasOwnProperty(attr.nodeName)) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? formatStyles(node.style.cssText) : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + /* + // source code nodes + if (nodeName == 'script' || nodeName == 'style') + { + + if(document.all){ + var src = node.innerHTML+'\n'; + + }else { + var src = '\n'+node.innerHTML+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + '
      '; + } + + html.push('>
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ', + '
      </', + nodeName, + '>
      ', + '
      ' + ); + + + }/**/ + + // Just a single text node child + if (hasSingleTextChild) + { + var value = child[0].nodeValue.replace(reTrim, ''); + if(value) + { + html.push( + '>', + escapeHTML(value), + '</', + nodeName, + '>' + ); + } + else + html.push('/>'); // blank text, print as childless node + + } + else if (childLength > 0) + { + html.push('>'); + } + else + html.push('/>'); + + } + else if (node.nodeType == 3) + { + if ( node.parentNode && ( node.parentNode.nodeName.toLowerCase() == "script" || + node.parentNode.nodeName.toLowerCase() == "style" ) ) + { + var value = node.nodeValue.replace(reTrim, ''); + + if(isIE){ + var src = value+'\n'; + + }else { + var src = '\n'+value+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + ''; + } + + html.push('
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ' + ); + + } + else + { + var value = node.nodeValue.replace(reTrim, ''); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + } + } + }, + + appendTreeChildren: function(treeNode) + { + var doc = Firebug.chrome.document; + var uid = treeNode.id; + var parentNode = ElementCache.get(uid); + + if (parentNode.childNodes.length == 0) return; + + var treeNext = treeNode.nextSibling; + var treeParent = treeNode.parentNode; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl nodeMaximized'; + + var html = []; + var children = doc.createElement("div"); + children.className = "nodeChildren"; + this.appendTreeNode(parentNode.childNodes, html); + children.innerHTML = html.join(""); + + treeParent.insertBefore(children, treeNext); + + var closeElement = doc.createElement("div"); + closeElement.className = "objectBox-element"; + closeElement.innerHTML = '</' + + parentNode.nodeName.toLowerCase() + '>' + + treeParent.insertBefore(closeElement, treeNext); + + }, + + removeTreeChildren: function(treeNode) + { + var children = treeNode.nextSibling; + var closeTag = children.nextSibling; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl'; + + children.parentNode.removeChild(children); + closeTag.parentNode.removeChild(closeTag); + }, + + isTreeNodeVisible: function(id) + { + return $(id); + }, + + select: function(el) + { + var id = el && ElementCache(el); + if (id) + this.selectTreeNode(id); + }, + + selectTreeNode: function(id) + { + id = ""+id; + var node, stack = []; + while(id && !this.isTreeNodeVisible(id)) + { + stack.push(id); + + var node = ElementCache.get(id).parentNode; + + if (node) + id = ElementCache(node); + else + break; + } + + stack.push(id); + + while(stack.length > 0) + { + id = stack.pop(); + node = $(id); + + if (stack.length > 0 && ElementCache.get(id).childNodes.length > 0) + this.appendTreeChildren(node); + } + + selectElement(node); + + // TODO: xxxpedro + if (fbPanel1) + fbPanel1.scrollTop = Math.round(node.offsetTop - fbPanel1.clientHeight/2); + } + +}); + +Firebug.registerModule(Firebug.HTML); + +// ************************************************************************************************ +// HTML Panel + +function HTMLPanel(){}; + +HTMLPanel.prototype = extend(Firebug.Panel, +{ + name: "HTML", + title: "HTML", + + options: { + hasSidePanel: true, + //hasToolButtons: true, + isPreRendered: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "4px 3px 1px 15px"; + this.panelNode.style.minWidth = "500px"; + + if (Env.Options.enablePersistent || Firebug.chrome.type != "popup") + this.createUI(); + + if(!this.sidePanelBar.selectedPanel) + { + this.sidePanelBar.selectPanel("css"); + } + }, + + destroy: function() + { + selectedElement = null + fbPanel1 = null; + + selectedSidePanelTS = null; + selectedSidePanelTimer = null; + + Firebug.Panel.destroy.apply(this, arguments); + }, + + createUI: function() + { + var rootNode = Firebug.browser.document.documentElement; + var html = []; + Firebug.HTML.appendTreeNode(rootNode, html); + + this.panelNode.innerHTML = html.join(""); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + addEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = $("fbPanel1"); + + if(!selectedElement) + { + Firebug.HTML.selectTreeNode(ElementCache(Firebug.browser.document.body)); + } + + // TODO: xxxpedro + addEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + addEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + addEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + }, + + shutdown: function() + { + // TODO: xxxpedro + removeEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + removeEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + removeEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + + removeEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = null; + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + reattach: function() + { + // TODO: panel reattach + if(FirebugChrome.selectedHTMLElementId) + Firebug.HTML.selectTreeNode(FirebugChrome.selectedHTMLElementId); + }, + + updateSelection: function(object) + { + var id = ElementCache(object); + + if (id) + { + Firebug.HTML.selectTreeNode(id); + } + } +}); + +Firebug.registerPanel(HTMLPanel); + +// ************************************************************************************************ + +var formatStyles = function(styles) +{ + return isIE ? + // IE return CSS property names in upper case, so we need to convert them + styles.replace(/([^\s]+)\s*:/g, function(m,g){return g.toLowerCase()+":"}) : + // other browsers are just fine + styles; +}; + +// ************************************************************************************************ + +var selectedElement = null +var fbPanel1 = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +var selectedSidePanelTS, selectedSidePanelTimer; + +var selectElement= function selectElement(e) +{ + if (e != selectedElement) + { + if (selectedElement) + selectedElement.className = "objectBox-element"; + + e.className = e.className + " selectedElement"; + + if (FBL.isFirefox) + e.style.MozBorderRadius = "2px"; + + else if (FBL.isSafari) + e.style.WebkitBorderRadius = "2px"; + + selectedElement = e; + + FirebugChrome.selectedHTMLElementId = e.id; + + var target = ElementCache.get(e.id); + var selectedSidePanel = Firebug.chrome.getPanel("HTML").sidePanelBar.selectedPanel; + + var stack = FirebugChrome.htmlSelectionStack; + + stack.unshift(target); + + if (stack.length > 2) + stack.pop(); + + var lazySelect = function() + { + selectedSidePanelTS = new Date().getTime(); + + selectedSidePanel.select(target, true); + }; + + if (selectedSidePanelTimer) + { + clearTimeout(selectedSidePanelTimer); + selectedSidePanelTimer = null; + } + + if (new Date().getTime() - selectedSidePanelTS > 100) + setTimeout(lazySelect, 0) + else + selectedSidePanelTimer = setTimeout(lazySelect, 150); + } +} + + +// ************************************************************************************************ +// *** TODO: REFACTOR ************************************************************************** +// ************************************************************************************************ +Firebug.HTML.onTreeClick = function (e) +{ + e = e || event; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + + if (targ.className.indexOf('nodeControl') != -1 || targ.className == 'nodeTag') + { + var isIE = false; + + if(targ.className == 'nodeTag') + { + var control = isIE ? (targ.parentNode.previousSibling || targ) : + (targ.parentNode.previousSibling || targ); + + selectElement(targ.parentNode.parentNode); + + if (control.className.indexOf('nodeControl') == -1) + return; + + } else + control = targ; + + FBL.cancelEvent(e); + + var treeNode = isIE ? control.nextSibling : control.parentNode; + + //FBL.Firebug.Console.log(treeNode); + + if (control.className.indexOf(' nodeMaximized') != -1) { + FBL.Firebug.HTML.removeTreeChildren(treeNode); + } else { + FBL.Firebug.HTML.appendTreeChildren(treeNode); + } + } + else if (targ.className == 'nodeValue' || targ.className == 'nodeName') + { + /* + var input = FBL.Firebug.chrome.document.getElementById('treeInput'); + + input.style.display = "block"; + input.style.left = targ.offsetLeft + 'px'; + input.style.top = FBL.topHeight + targ.offsetTop - FBL.fbPanel1.scrollTop + 'px'; + input.style.width = targ.offsetWidth + 6 + 'px'; + input.value = targ.textContent || targ.innerText; + input.focus(); + /**/ + } +} + +function onListMouseOut(e) +{ + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + if (hasClass(targ, "fbPanel")) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + } +}; + +var hoverElement = null; +var hoverElementTS = 0; + +Firebug.HTML.onListMouseMove = function onListMouseMove(e) +{ + try + { + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + var found = false; + while (targ && !found) { + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) + targ = targ.parentNode; + else + found = true; + } + + if (!targ) + { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + /* + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + /**/ + + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + + var el = ElementCache.get(uid.value); + + var nodeName = el.nodeName.toLowerCase(); + + if (FBL.isIE && " meta title script link ".indexOf(" "+nodeName+" ") != -1) + return; + + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) return; + + if (el.id == "FirebugUI" || " html head body br script link iframe ".indexOf(" "+nodeName+" ") != -1) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + if ((new Date().getTime() - hoverElementTS > 40) && hoverElement != el) { + hoverElementTS = new Date().getTime(); + hoverElement = el; + FBL.Firebug.Inspector.drawBoxModel(el); + } + } + catch(E) + { + } +} + + +// ************************************************************************************************ + +Firebug.Reps = { + + appendText: function(object, html) + { + html.push(escapeHTML(objectToString(object))); + }, + + appendNull: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendString: function(object, html) + { + html.push('"', escapeHTML(objectToString(object)), + '"'); + }, + + appendInteger: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFloat: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFunction: function(object, html) + { + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m && m[1] ? m[1] : "function"; + html.push('', escapeHTML(name), '()'); + }, + + appendObject: function(object, html) + { + /* + var rep = Firebug.getRep(object); + var outputs = []; + + rep.tag.tag.compile(); + + var str = rep.tag.renderHTML({object: object}, outputs); + html.push(str); + /**/ + + try + { + if (object == undefined) + this.appendNull("undefined", html); + else if (object == null) + this.appendNull("null", html); + else if (typeof object == "string") + this.appendString(object, html); + else if (typeof object == "number") + this.appendInteger(object, html); + else if (typeof object == "boolean") + this.appendInteger(object, html); + else if (typeof object == "function") + this.appendFunction(object, html); + else if (object.nodeType == 1) + this.appendSelector(object, html); + else if (typeof object == "object") + { + if (typeof object.length != "undefined") + this.appendArray(object, html); + else + this.appendObjectFormatted(object, html); + } + else + this.appendText(object, html); + } + catch (exc) + { + } + /**/ + }, + + appendObjectFormatted: function(object, html) + { + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push('', m ? m[1] : text, '') + }, + + appendSelector: function(object, html) + { + var uid = ElementCache(object); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push(''); + + html.push('', escapeHTML(object.nodeName.toLowerCase()), ''); + if (object.id) + html.push('#', escapeHTML(object.id), ''); + if (object.className) + html.push('.', escapeHTML(object.className), ''); + + html.push(''); + }, + + appendNode: function(node, html) + { + if (node.nodeType == 1) + { + var uid = ElementCache(node); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push( + '
      ', + '', + '<', node.nodeName.toLowerCase(), ''); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || attr.nodeName == cacheID) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? node.style.cssText : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + if (node.firstChild) + { + html.push('>
      '); + + for (var child = node.firstChild; child; child = child.nextSibling) + this.appendNode(child, html); + + html.push('
      </', + node.nodeName.toLowerCase(), '>
      '); + } + else + html.push('/>'); + } + else if (node.nodeType == 3) + { + var value = trim(node.nodeValue); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + }, + + appendArray: function(object, html) + { + html.push('[ '); + + for (var i = 0, l = object.length, obj; i < l; ++i) + { + this.appendObject(object[i], html); + + if (i < l-1) + html.push(', '); + } + + html.push(' ]'); + } + +}; + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +/* + +Hack: +Firebug.chrome.currentPanel = Firebug.chrome.selectedPanel; +Firebug.showInfoTips = true; +Firebug.InfoTip.initializeBrowser(Firebug.chrome); + +/**/ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var maxWidth = 100, maxHeight = 80; +var infoTipMargin = 10; +var infoTipWindowPadding = 25; + +// ************************************************************************************************ + +Firebug.InfoTip = extend(Firebug.Module, +{ + dispatchName: "infoTip", + tags: domplate( + { + infoTipTag: DIV({"class": "infoTip"}), + + colorTag: + DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, " "), + + imgTag: + DIV({"class": "infoTipImageBox infoTipLoading"}, + IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat", + onload: "$onLoadImage"}), + IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}), + DIV({"class": "infoTipCaption"}) + ), + + onLoadImage: function(event) + { + var img = event.currentTarget || event.srcElement; + ///var bgImg = img.nextSibling; + ///if (!bgImg) + /// return; // Sometimes gets called after element is dead + + ///var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + /// TODO: xxxpedro infoTip hack + var caption = getElementByClass(innerBox, "infoTipCaption"); + var bgImg = getElementByClass(innerBox, "infoTipBgImage"); + if (!bgImg) + return; // Sometimes gets called after element is dead + + // TODO: xxxpedro infoTip IE and timing issue + // TODO: use offline document to avoid flickering + if (isIE) + removeClass(innerBox, "infoTipLoading"); + + var updateInfoTip = function(){ + + var w = img.naturalWidth || img.width || 10, + h = img.naturalHeight || img.height || 10; + + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + //caption.innerHTML = $STRF("Dimensions", [w, h]); + caption.innerHTML = $STRF(w + " x " + h); + + + }; + + if (isIE) + setTimeout(updateInfoTip, 0); + else + { + updateInfoTip(); + removeClass(innerBox, "infoTipLoading"); + } + + /// + } + + /* + /// onLoadImage original + onLoadImage: function(event) + { + var img = event.currentTarget; + var bgImg = img.nextSibling; + if (!bgImg) + return; // Sometimes gets called after element is dead + + var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + var w = img.naturalWidth, h = img.naturalHeight; + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + caption.innerHTML = $STRF("Dimensions", [w, h]); + + removeClass(innerBox, "infoTipLoading"); + } + /**/ + + }), + + initializeBrowser: function(browser) + { + browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser); + browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser); + + ///var doc = browser.contentDocument; + var doc = browser.document; + if (!doc) + return; + + ///doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true); + addEvent(doc, "mouseover", browser.onInfoTipMouseMove); + addEvent(doc, "mouseout", browser.onInfoTipMouseOut); + addEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc)); + }, + + uninitializeBrowser: function(browser) + { + if (browser.infoTip) + { + ///var doc = browser.contentDocument; + var doc = browser.document; + ///doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true); + removeEvent(doc, "mouseover", browser.onInfoTipMouseMove); + removeEvent(doc, "mouseout", browser.onInfoTipMouseOut); + removeEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + browser.infoTip.parentNode.removeChild(browser.infoTip); + delete browser.infoTip; + delete browser.onInfoTipMouseMove; + } + }, + + showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset) + { + if (!Firebug.showInfoTips) + return; + + var scrollParent = getOverflowParent(target); + var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0); + + if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset)) + { + var htmlElt = infoTip.ownerDocument.documentElement; + var panelWidth = htmlElt.clientWidth; + var panelHeight = htmlElt.clientHeight; + + if (x+infoTip.offsetWidth+infoTipMargin > panelWidth) + { + infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px"; + infoTip.style.right = "auto"; + } + else + { + infoTip.style.left = (x+infoTipMargin) + "px"; + infoTip.style.right = "auto"; + } + + if (y+infoTip.offsetHeight+infoTipMargin > panelHeight) + { + infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px"; + infoTip.style.bottom = "auto"; + } + else + { + infoTip.style.top = (y+infoTipMargin) + "px"; + infoTip.style.bottom = "auto"; + } + + if (FBTrace.DBG_INFOTIP) + FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top + + ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom + + ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight + + ", offsetWidth: " + infoTip.offsetWidth + + ", x: " + x + ", panelWidth: " + panelWidth + + ", y: " + y + ", panelHeight: " + panelHeight); + + infoTip.setAttribute("active", "true"); + } + else + this.hideInfoTip(infoTip); + }, + + hideInfoTip: function(infoTip) + { + if (infoTip) + infoTip.removeAttribute("active"); + }, + + onMouseOut: function(event, browser) + { + if (!event.relatedTarget) + this.hideInfoTip(browser.infoTip); + }, + + onMouseMove: function(event, browser) + { + // Ignore if the mouse is moving over the existing info tip. + if (getAncestorByClass(event.target, "infoTip")) + return; + + if (browser.currentPanel) + { + var x = event.clientX, y = event.clientY, target = event.target || event.srcElement; + this.showInfoTip(browser.infoTip, browser.currentPanel, target, x, y, event.rangeParent, event.rangeOffset); + } + else + this.hideInfoTip(browser.infoTip); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + populateColorInfoTip: function(infoTip, color) + { + this.tags.colorTag.replace({rgbValue: color}, infoTip); + return true; + }, + + populateImageInfoTip: function(infoTip, url, repeat) + { + if (!repeat) + repeat = "no-repeat"; + + this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip); + + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + disable: function() + { + // XXXjoe For each browser, call uninitializeBrowser + }, + + showPanel: function(browser, panel) + { + if (panel) + { + var infoTip = panel.panelBrowser.infoTip; + if (!infoTip) + infoTip = this.initializeBrowser(panel.panelBrowser); + this.hideInfoTip(infoTip); + } + + }, + + showSidePanel: function(browser, panel) + { + this.showPanel(browser, panel); + } +}); + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.InfoTip); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +// move to FBL +(function() { + +// ************************************************************************************************ +// XPath + +/** + * Gets an XPath for an element which describes its hierarchical location. + */ +this.getElementXPath = function(element) +{ + if (element && element.id) + return '//*[@id="' + element.id + '"]'; + else + return this.getElementTreeXPath(element); +}; + +this.getElementTreeXPath = function(element) +{ + var paths = []; + + for (; element && element.nodeType == 1; element = element.parentNode) + { + var index = 0; + for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) + { + if (sibling.nodeName == element.nodeName) + ++index; + } + + var tagName = element.nodeName.toLowerCase(); + var pathIndex = (index ? "[" + (index+1) + "]" : ""); + paths.splice(0, 0, tagName + pathIndex); + } + + return paths.length ? "/" + paths.join("/") : null; +}; + +this.getElementsByXPath = function(doc, xpath) +{ + var nodes = []; + + try { + var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + for (var item = result.iterateNext(); item; item = result.iterateNext()) + nodes.push(item); + } + catch (exc) + { + // Invalid xpath expressions make their way here sometimes. If that happens, + // we still want to return an empty set without an exception. + } + + return nodes; +}; + +this.getRuleMatchingElements = function(rule, doc) +{ + var css = rule.selectorText; + var xpath = this.cssToXPath(css); + return this.getElementsByXPath(doc, xpath); +}; + + +}).call(FBL); + + + + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + +var toCamelCase = function toCamelCase(s) +{ + return s.replace(reSelectorCase, toCamelCaseReplaceFn); +}; + +var toSelectorCase = function toSelectorCase(s) +{ + return s.replace(reCamelCase, "-$1").toLowerCase(); + +}; + +var reCamelCase = /([A-Z])/g; +var reSelectorCase = /\-(.)/g; +var toCamelCaseReplaceFn = function toCamelCaseReplaceFn(m,g) +{ + return g.toUpperCase(); +}; + + + + + +// ************************************************************************************************ + +var ElementCache = Firebug.Lite.Cache.Element; +var StyleSheetCache = Firebug.Lite.Cache.StyleSheet; + +var globalCSSRuleIndex; + +var externalStyleSheetURLs = []; +var externalStyleSheetWarning = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "warning focusRow", style: "font-weight:normal;", role: 'listitem'}, + SPAN("$object|STR"), + A({"href": "$href", target:"_blank"}, "$link|STR") + ) +}); + + +var processAllStyleSheetsTimeout = null; +var loadExternalStylesheet = function(doc, styleSheetIterator, styleSheet) +{ + var url = styleSheet.href; + styleSheet.firebugIgnore = true; + + var source = Firebug.Lite.Proxy.load(url); + + // TODO: check for null and error responses + + + // remove comments + //var reMultiComment = /(\/\*([^\*]|\*(?!\/))*\*\/)/g; + //source = source.replace(reMultiComment, ""); + + // convert relative addresses to absolute ones + source = source.replace(/url\(([^\)]+)\)/g, function(a,name){ + + var hasDomain = /\w+:\/\/./.test(name); + + if (!hasDomain) + { + name = name.replace(/^(["'])(.+)\1$/, "$2"); + var first = name.charAt(0); + + // relative path, based on root + if (first == "/") + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLRoot + var m = /^([^:]+:\/{1,3}[^\/]+)/.exec(url); + + return m ? + "url(" + m[1] + name + ")" : + "url(" + name + ")"; + } + // relative path, based on current location + else + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLPath + var path = url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g, ""); + + path = path + name; + + var reBack = /[^\/]+\/\.\.\//; + while(reBack.test(path)) + { + path = path.replace(reBack, ""); + } + + //console.log("url(" + path + ")"); + + return "url(" + path + ")"; + } + } + + // if it is an absolute path, there is nothing to do + return a; + }); + + var oldStyle = styleSheet.ownerNode; + + if (!oldStyle) return; + + if (!oldStyle.parentNode) return; + + var style = createGlobalElement("style"); + style.setAttribute("charset","utf-8"); + style.setAttribute("type", "text/css"); + style.innerHTML = source; + + //debugger; + oldStyle.parentNode.insertBefore(style, oldStyle.nextSibling); + oldStyle.parentNode.removeChild(oldStyle); + + + //doc.getElementsByTagName("head")[0].appendChild(style); + + doc.styleSheets[doc.styleSheets.length-1].externalURL = url; + + console.log(url, "call " + externalStyleSheetURLs.length, source); + + externalStyleSheetURLs.pop(); + + if (processAllStyleSheetsTimeout) + { + clearTimeout(processAllStyleSheetsTimeout); + } + + processAllStyleSheetsTimeout = setTimeout(function(){ + console.log("processing"); + FBL.processAllStyleSheets(doc, styleSheetIterator); + processAllStyleSheetsTimeout = null; + },200); + +}; + + +FBL.processAllStyleSheets = function(doc, styleSheetIterator) +{ + styleSheetIterator = styleSheetIterator || processStyleSheet; + + globalCSSRuleIndex = -1; + + var styleSheets = doc.styleSheets; + var importedStyleSheets = []; + + if (FBTrace.DBG_CSS) + var start = new Date().getTime(); + + for(var i=0, length=styleSheets.length; i maxSpecificity) + { + maxSpecificity = spec; + mostSpecificSelector = sel; + } + } + } + + rule.specificity = maxSpecificity; + } + } + + rules.sort(sortElementRules); + //rules.sort(solveRulesTied); + + return rules; +}; + +var sortElementRules = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + var specificityA = ruleA.specificity; + var specificityB = ruleB.specificity; + + if (specificityA > specificityB) + return 1; + + else if (specificityA < specificityB) + return -1; + + else + return ruleA.order > ruleB.order ? 1 : -1; +}; + +var solveRulesTied = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + if (ruleA.specificity == ruleB.specificity) + return ruleA.order > ruleB.order ? 1 : -1; + + return null; +}; + +var reSelectorTag = /(^|\s)(?:\w+)/g; +var reSelectorClass = /\.[\w\d_-]+/g; +var reSelectorId = /#[\w\d_-]+/g; + +var getCSSRuleSpecificity = function(selector) +{ + var match = selector.match(reSelectorTag); + var tagCount = match ? match.length : 0; + + match = selector.match(reSelectorClass); + var classCount = match ? match.length : 0; + + match = selector.match(reSelectorId); + var idCount = match ? match.length : 0; + + return tagCount + 10*classCount + 100*idCount; +}; + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; +//const nsIDOMCSSStyleRule = Ci.nsIDOMCSSStyleRule; +//const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor; +//const nsISelectionDisplay = Ci.nsISelectionDisplay; +//const nsISelectionController = Ci.nsISelectionController; + +// See: http://mxr.mozilla.org/mozilla1.9.2/source/content/events/public/nsIEventStateManager.h#153 +//const STATE_ACTIVE = 0x01; +//const STATE_FOCUS = 0x02; +//const STATE_HOVER = 0x04; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +Firebug.SourceBoxPanel = Firebug.Panel; + +var domUtils = null; + +var textContent = isIE ? "innerText" : "textContent"; +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var CSSDomplateBase = { + isEditable: function(rule) + { + return !rule.isSystemSheet; + }, + isSelectorEditable: function(rule) + { + return rule.isSelectorEditable && this.isEditable(rule); + } +}; + +var CSSPropTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssProp focusRow", $disabledStyle: "$prop.disabled", + $editGroup: "$rule|isEditable", + $cssOverridden: "$prop.overridden", role : "option"}, + A({"class": "cssPropDisable"}, "  "), + SPAN({"class": "cssPropName", $editable: "$rule|isEditable"}, "$prop.name"), + SPAN({"class": "cssColon"}, ":"), + SPAN({"class": "cssPropValue", $editable: "$rule|isEditable"}, "$prop.value$prop.important"), + SPAN({"class": "cssSemi"}, ";") + ) +}); + +var CSSRuleTag = + TAG("$rule.tag", {rule: "$rule"}); + +var CSSImportRuleTag = domplate({ + tag: DIV({"class": "cssRule insertInto focusRow importRule", _repObject: "$rule.rule"}, + "@import "", + A({"class": "objectLink", _repObject: "$rule.rule.styleSheet"}, "$rule.rule.href"), + "";" + ) +}); + +var CSSStyleRuleTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssRule insertInto", + $cssEditableRule: "$rule|isEditable", + $editGroup: "$rule|isSelectorEditable", + _repObject: "$rule.rule", + "ruleId": "$rule.id", role : 'presentation'}, + DIV({"class": "cssHead focusRow", role : 'listitem'}, + SPAN({"class": "cssSelector", $editable: "$rule|isSelectorEditable"}, "$rule.selector"), " {" + ), + DIV({role : 'group'}, + DIV({"class": "cssPropertyListBox", role : 'listbox'}, + FOR("prop", "$rule.props", + TAG(CSSPropTag.tag, {rule: "$rule", prop: "$prop"}) + ) + ) + ), + DIV({"class": "editable insertBefore", role:"presentation"}, "}") + ) +}); + +var reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/; + +var reURL = /url\("?([^"\)]+)?"?\)/; + +var reRepeat = /no-repeat|repeat-x|repeat-y|repeat/; + +//const sothinkInstalled = !!$("swfcatcherKey_sidebar"); +var sothinkInstalled = false; +var styleGroups = +{ + text: [ + "font-family", + "font-size", + "font-weight", + "font-style", + "color", + "text-transform", + "text-decoration", + "letter-spacing", + "word-spacing", + "line-height", + "text-align", + "vertical-align", + "direction", + "column-count", + "column-gap", + "column-width" + ], + + background: [ + "background-color", + "background-image", + "background-repeat", + "background-position", + "background-attachment", + "opacity" + ], + + box: [ + "width", + "height", + "top", + "right", + "bottom", + "left", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + "-moz-border-top-radius", + "-moz-border-right-radius", + "-moz-border-bottom-radius", + "-moz-border-left-radius", + "outline-top-width", + "outline-right-width", + "outline-bottom-width", + "outline-left-width", + "outline-top-color", + "outline-right-color", + "outline-bottom-color", + "outline-left-color", + "outline-top-style", + "outline-right-style", + "outline-bottom-style", + "outline-left-style" + ], + + layout: [ + "position", + "display", + "visibility", + "z-index", + "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow + "overflow-y", + "overflow-clip", + "white-space", + "clip", + "float", + "clear", + "-moz-box-sizing" + ], + + other: [ + "cursor", + "list-style-image", + "list-style-position", + "list-style-type", + "marker-offset", + "user-focus", + "user-select", + "user-modify", + "user-input" + ] +}; + +var styleGroupTitles = +{ + text: "Text", + background: "Background", + box: "Box Model", + layout: "Layout", + other: "Other" +}; + +Firebug.CSSModule = extend(Firebug.Module, +{ + freeEdit: function(styleSheet, value) + { + if (!styleSheet.editStyleSheet) + { + var ownerNode = getStyleSheetOwnerNode(styleSheet); + styleSheet.disabled = true; + + var url = CCSV("@mozilla.org/network/standard-url;1", Components.interfaces.nsIURL); + url.spec = styleSheet.href; + + var editStyleSheet = ownerNode.ownerDocument.createElementNS( + "http://www.w3.org/1999/xhtml", + "style"); + unwrapObject(editStyleSheet).firebugIgnore = true; + editStyleSheet.setAttribute("type", "text/css"); + editStyleSheet.setAttributeNS( + "http://www.w3.org/XML/1998/namespace", + "base", + url.directory); + if (ownerNode.hasAttribute("media")) + { + editStyleSheet.setAttribute("media", ownerNode.getAttribute("media")); + } + + // Insert the edited stylesheet directly after the old one to ensure the styles + // cascade properly. + ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling); + + styleSheet.editStyleSheet = editStyleSheet; + } + + styleSheet.editStyleSheet.innerHTML = value; + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n"); + + dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]); + }, + + insertRule: function(styleSheet, cssText, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("Insert: " + ruleIndex + " " + cssText); + var insertIndex = styleSheet.insertRule(cssText, ruleIndex); + + dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]); + + return insertIndex; + }, + + deleteRule: function(styleSheet, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("deleteRule: " + ruleIndex + " " + styleSheet.cssRules.length, styleSheet.cssRules); + dispatch(this.fbListeners, "onCSSDeleteRule", [styleSheet, ruleIndex]); + + styleSheet.deleteRule(ruleIndex); + }, + + setProperty: function(rule, propName, propValue, propPriority) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + // good browsers + if (style.getPropertyValue) + { + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect + // unless we remove the property first + style.removeProperty(propName); + + style.setProperty(propName, propValue, propPriority); + } + // sad browsers + else + { + // TODO: xxxpedro parse CSS rule to find property priority in IE? + //console.log(propName, propValue); + style[toCamelCase(propName)] = propValue; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue, propPriority, prevValue, prevPriority, rule, baseText]); + } + }, + + removeProperty: function(rule, propName, parent) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + if (style.getPropertyValue) + { + + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + style.removeProperty(propName); + } + else + { + style[toCamelCase(propName)] = ""; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue, prevPriority, rule, baseText]); + } + }/*, + + cleanupSheets: function(doc, context) + { + // Due to the manner in which the layout engine handles multiple + // references to the same sheet we need to kick it a little bit. + // The injecting a simple stylesheet then removing it will force + // Firefox to regenerate it's CSS hierarchy. + // + // WARN: This behavior was determined anecdotally. + // See http://code.google.com/p/fbug/issues/detail?id=2440 + var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + style.setAttribute("charset","utf-8"); + unwrapObject(style).firebugIgnore = true; + style.setAttribute("type", "text/css"); + style.innerHTML = "#fbIgnoreStyleDO_NOT_USE {}"; + addStyleSheet(doc, style); + style.parentNode.removeChild(style); + + // https://bugzilla.mozilla.org/show_bug.cgi?id=500365 + // This voodoo touches each style sheet to force some Firefox internal change to allow edits. + var styleSheets = getAllStyleSheets(context); + for(var i = 0; i < styleSheets.length; i++) + { + try + { + var rules = styleSheets[i].cssRules; + if (rules.length > 0) + var touch = rules[0]; + if (FBTrace.DBG_CSS && touch) + FBTrace.sysout("css.show() touch "+typeof(touch)+" in "+(styleSheets[i].href?styleSheets[i].href:context.getName())); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.show: sheet.cssRules FAILS for "+(styleSheets[i]?styleSheets[i].href:"null sheet")+e, e); + } + } + }, + cleanupSheetHandler: function(event, context) + { + var target = event.target || event.srcElement, + tagName = (target.tagName || "").toLowerCase(); + if (tagName == "link") + { + this.cleanupSheets(target.ownerDocument, context); + } + }, + watchWindow: function(context, win) + { + var cleanupSheets = bind(this.cleanupSheets, this), + cleanupSheetHandler = bind(this.cleanupSheetHandler, this, context), + doc = win.document; + + //doc.addEventListener("DOMAttrModified", cleanupSheetHandler, false); + //doc.addEventListener("DOMNodeInserted", cleanupSheetHandler, false); + }, + loadedContext: function(context) + { + var self = this; + iterateWindows(context.browser.contentWindow, function(subwin) + { + self.cleanupSheets(subwin.document, context); + }); + } + /**/ +}); + +// ************************************************************************************************ + +Firebug.CSSStyleSheetPanel = function() {}; + +Firebug.CSSStyleSheetPanel.prototype = extend(Firebug.SourceBoxPanel, +{ + template: domplate( + { + tag: + DIV({"class": "cssSheet insertInto a11yCSSView"}, + FOR("rule", "$rules", + CSSRuleTag + ), + DIV({"class": "cssSheet editable insertBefore"}, "") + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + refresh: function() + { + if (this.location) + this.updateLocation(this.location); + else if (this.selection) + this.updateSelection(this.selection); + }, + + toggleEditing: function() + { + if (!this.stylesheetEditor) + this.stylesheetEditor = new StyleSheetEditor(this.document); + + if (this.editing) + Firebug.Editor.stopEditing(); + else + { + if (!this.location) + return; + + var styleSheet = this.location.editStyleSheet + ? this.location.editStyleSheet.sheet + : this.location; + + var css = getStyleSheetCSS(styleSheet, this.context); + //var topmost = getTopmostRuleLine(this.panelNode); + + this.stylesheetEditor.styleSheet = this.location; + Firebug.Editor.startEditing(this.panelNode, css, this.stylesheetEditor); + //this.stylesheetEditor.scrollToLine(topmost.line, topmost.offset); + } + }, + + getStylesheetURL: function(rule) + { + if (this.location.href) + return this.location.href; + else + return this.context.window.location.href; + }, + + getRuleByLine: function(styleSheet, line) + { + if (!domUtils) + return null; + + var cssRules = styleSheet.cssRules; + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + if (rule instanceof CSSStyleRule) + { + var ruleLine = domUtils.getRuleLine(rule); + if (ruleLine >= line) + return rule; + } + } + }, + + highlightRule: function(rule) + { + var ruleElement = Firebug.getElementByRepObject(this.panelNode.firstChild, rule); + if (ruleElement) + { + scrollIntoCenterView(ruleElement, this.panelNode); + setClassTimed(ruleElement, "jumpHighlight", this.context); + } + }, + + getStyleSheetRules: function(context, styleSheet) + { + var isSystemSheet = isSystemStyleSheet(styleSheet); + + function appendRules(cssRules) + { + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + + // TODO: xxxpedro opera instanceof stylesheet remove the following comments when + // the issue with opera and style sheet Classes has been solved. + + //if (rule instanceof CSSStyleRule) + if (instanceOf(rule, "CSSStyleRule")) + { + var props = this.getRuleProperties(context, rule); + //var line = domUtils.getRuleLine(rule); + var line = null; + + var selector = rule.selectorText; + + if (isIE) + { + selector = selector.replace(reSelectorTag, + function(s){return s.toLowerCase();}); + } + + var ruleId = rule.selectorText+"/"+line; + rules.push({tag: CSSStyleRuleTag.tag, rule: rule, id: ruleId, + selector: selector, props: props, + isSystemSheet: isSystemSheet, + isSelectorEditable: true}); + } + //else if (rule instanceof CSSImportRule) + else if (instanceOf(rule, "CSSImportRule")) + rules.push({tag: CSSImportRuleTag.tag, rule: rule}); + //else if (rule instanceof CSSMediaRule) + else if (instanceOf(rule, "CSSMediaRule")) + appendRules.apply(this, [rule.cssRules]); + else + { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_CSS) + FBTrace.sysout("css getStyleSheetRules failed to classify a rule ", rule); + } + } + } + + var rules = []; + appendRules.apply(this, [styleSheet.cssRules || styleSheet.rules]); + return rules; + }, + + parseCSSProps: function(style, inheritMode) + { + var props = []; + + if (Firebug.expandShorthandProps) + { + var count = style.length-1, + index = style.length; + while (index--) + { + var propName = style.item(count - index); + this.addProperty(propName, style.getPropertyValue(propName), !!style.getPropertyPriority(propName), false, inheritMode, props); + } + } + else + { + var lines = style.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g); + var propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/; + var line,i=0; + // TODO: xxxpedro port to firebug: variable leaked into global namespace + var m; + + while(line=lines[i++]){ + m = propRE.exec(line); + if(!m) + continue; + //var name = m[1], value = m[2], important = !!m[3]; + if (m[2]) + this.addProperty(m[1], m[2], !!m[3], false, inheritMode, props); + }; + } + + return props; + }, + + getRuleProperties: function(context, rule, inheritMode) + { + var props = this.parseCSSProps(rule.style, inheritMode); + + // TODO: xxxpedro port to firebug: variable leaked into global namespace + //var line = domUtils.getRuleLine(rule); + var line; + var ruleId = rule.selectorText+"/"+line; + this.addOldProperties(context, ruleId, inheritMode, props); + sortProperties(props); + + return props; + }, + + addOldProperties: function(context, ruleId, inheritMode, props) + { + if (context.selectorMap && context.selectorMap.hasOwnProperty(ruleId) ) + { + var moreProps = context.selectorMap[ruleId]; + for (var i = 0; i < moreProps.length; ++i) + { + var prop = moreProps[i]; + this.addProperty(prop.name, prop.value, prop.important, true, inheritMode, props); + } + } + }, + + addProperty: function(name, value, important, disabled, inheritMode, props) + { + name = name.toLowerCase(); + + if (inheritMode && !inheritedStyleNames[name]) + return; + + name = this.translateName(name, value); + if (name) + { + value = stripUnits(rgbToHex(value)); + important = important ? " !important" : ""; + + var prop = {name: name, value: value, important: important, disabled: disabled}; + props.push(prop); + } + }, + + translateName: function(name, value) + { + // Don't show these proprietary Mozilla properties + if ((value == "-moz-initial" + && (name == "-moz-background-clip" || name == "-moz-background-origin" + || name == "-moz-background-inline-policy")) + || (value == "physical" + && (name == "margin-left-ltr-source" || name == "margin-left-rtl-source" + || name == "margin-right-ltr-source" || name == "margin-right-rtl-source")) + || (value == "physical" + && (name == "padding-left-ltr-source" || name == "padding-left-rtl-source" + || name == "padding-right-ltr-source" || name == "padding-right-rtl-source"))) + return null; + + // Translate these back to the form the user probably expects + if (name == "margin-left-value") + return "margin-left"; + else if (name == "margin-right-value") + return "margin-right"; + else if (name == "margin-top-value") + return "margin-top"; + else if (name == "margin-bottom-value") + return "margin-bottom"; + else if (name == "padding-left-value") + return "padding-left"; + else if (name == "padding-right-value") + return "padding-right"; + else if (name == "padding-top-value") + return "padding-top"; + else if (name == "padding-bottom-value") + return "padding-bottom"; + // XXXjoe What about border! + else + return name; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + editElementStyle: function() + { + ///var rulesBox = this.panelNode.getElementsByClassName("cssElementRuleContainer")[0]; + var rulesBox = $$(".cssElementRuleContainer", this.panelNode)[0]; + var styleRuleBox = rulesBox && Firebug.getElementByRepObject(rulesBox, this.selection); + if (!styleRuleBox) + { + var rule = {rule: this.selection, inherited: false, selector: "element.style", props: []}; + if (!rulesBox) + { + // The element did not have any displayed styles. We need to create the whole tree and remove + // the no styles message + styleRuleBox = this.template.cascadedTag.replace({ + rules: [rule], inherited: [], inheritLabel: "Inherited from" // $STR("InheritedFrom") + }, this.panelNode); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("cssElementRuleContainer")[0]; + styleRuleBox = $$(".cssElementRuleContainer", styleRuleBox)[0]; + } + else + styleRuleBox = this.template.ruleTag.insertBefore({rule: rule}, rulesBox); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("insertInto")[0]; + styleRuleBox = $$(".insertInto", styleRuleBox)[0]; + } + + Firebug.Editor.insertRowForObject(styleRuleBox); + }, + + insertPropertyRow: function(row) + { + Firebug.Editor.insertRowForObject(row); + }, + + insertRule: function(row) + { + var location = getAncestorByClass(row, "cssRule"); + if (!location) + { + location = getChildByClass(this.panelNode, "cssSheet"); + Firebug.Editor.insertRowForObject(location); + } + else + { + Firebug.Editor.insertRow(location, "before"); + } + }, + + editPropertyRow: function(row) + { + var propValueBox = getChildByClass(row, "cssPropValue"); + Firebug.Editor.startEditing(propValueBox); + }, + + deletePropertyRow: function(row) + { + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + Firebug.CSSModule.removeProperty(rule, propName); + + // Remove the property from the selector map, if it was disabled + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if ( this.context.selectorMap && this.context.selectorMap.hasOwnProperty(ruleId) ) + { + var map = this.context.selectorMap[ruleId]; + for (var i = 0; i < map.length; ++i) + { + if (map[i].name == propName) + { + map.splice(i, 1); + break; + } + } + } + if (this.name == "stylesheet") + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [this, row.firstChild, true]); + row.parentNode.removeChild(row); + + this.markChange(this.name == "stylesheet"); + }, + + disablePropertyRow: function(row) + { + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + + if (!this.context.selectorMap) + this.context.selectorMap = {}; + + // XXXjoe Generate unique key for elements too + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if (!(this.context.selectorMap.hasOwnProperty(ruleId))) + this.context.selectorMap[ruleId] = []; + + var map = this.context.selectorMap[ruleId]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + if (hasClass(row, "disabledStyle")) + { + Firebug.CSSModule.removeProperty(rule, propName); + + map.push({"name": propName, "value": parsedValue.value, + "important": parsedValue.priority}); + } + else + { + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + + var index = findPropByName(map, propName); + map.splice(index, 1); + } + + this.markChange(this.name == "stylesheet"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onMouseDown: function(event) + { + //console.log("onMouseDown", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + // XXjoe Hack to only allow clicking on the checkbox + if (!isLeftClick(event) || offset > 20) + return; + + var target = event.target || event.srcElement; + if (hasClass(target, "textEditor")) + return; + + var row = getAncestorByClass(target, "cssProp"); + if (row && hasClass(row, "editGroup")) + { + this.disablePropertyRow(row); + cancelEvent(event); + } + }, + + onDoubleClick: function(event) + { + //console.log("onDoubleClick", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + if (!isLeftClick(event) || offset <= 20) + return; + + var target = event.target || event.srcElement; + + //console.log("ok", target, hasClass(target, "textEditorInner"), !isLeftClick(event), offset <= 20); + + // if the inline editor was clicked, don't insert a new rule + if (hasClass(target, "textEditorInner")) + return; + + var row = getAncestorByClass(target, "cssRule"); + if (row && !getAncestorByClass(target, "cssPropName") + && !getAncestorByClass(target, "cssPropValue")) + { + this.insertPropertyRow(row); + cancelEvent(event); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "stylesheet", + title: "CSS", + parentPanel: null, + searchable: true, + dependents: ["css", "stylesheet", "dom", "domSide", "layout"], + + options: + { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onMouseDown = bind(this.onMouseDown, this); + this.onDoubleClick = bind(this.onDoubleClick, this); + + if (this.name == "stylesheet") + { + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var selectNode = this.selectNode = createElement("select"); + + processAllStyleSheets(doc, function(doc, styleSheet) + { + var key = StyleSheetCache.key(styleSheet); + var fileName = getFileName(styleSheet.href) || getFileName(doc.location.href); + var option = createElement("option", {value: key}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }); + + this.toolButtonsNode.appendChild(selectNode); + } + /**/ + }, + + onChangeSelect: function(event) + { + event = event || window.event; + var target = event.srcElement || event.currentTarget; + var key = target.value; + var styleSheet = StyleSheetCache.get(key); + + this.updateLocation(styleSheet); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + + //if (!domUtils) + //{ + // try { + // domUtils = CCSV("@mozilla.org/inspector/dom-utils;1", "inIDOMUtils"); + // } catch (exc) { + // if (FBTrace.DBG_ERRORS) + // FBTrace.sysout("@mozilla.org/inspector/dom-utils;1 FAILED to load: "+exc, exc); + // } + //} + + //TODO: xxxpedro + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + this.initializeNode(); + + if (this.name == "stylesheet") + { + var styleSheets = Firebug.browser.document.styleSheets; + + if (styleSheets.length > 0) + { + addEvent(this.selectNode, "change", this.onChangeSelect); + + this.updateLocation(styleSheets[0]); + } + } + + //Firebug.SourceBoxPanel.initialize.apply(this, arguments); + }, + + shutdown: function() + { + // must destroy the editor when we leave the panel to avoid problems (Issue 2981) + Firebug.Editor.stopEditing(); + + if (this.name == "stylesheet") + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + } + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + destroy: function(state) + { + //state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop; + + //persistObjects(this, state); + + // xxxpedro we are stopping the editor in the shutdown method already + //Firebug.Editor.stopEditing(); + Firebug.Panel.destroy.apply(this, arguments); + }, + + initializeNode: function(oldPanelNode) + { + addEvent(this.panelNode, "mousedown", this.onMouseDown); + addEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.initializeNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'css']); + }, + + destroyNode: function() + { + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + removeEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.destroyNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'css']); + }, + + ishow: function(state) + { + Firebug.Inspector.stopInspecting(true); + + this.showToolbarButtons("fbCSSButtons", true); + + if (this.context.loaded && !this.location) // wait for loadedContext to restore the panel + { + restoreObjects(this, state); + + if (!this.location) + this.location = this.getDefaultLocation(); + + if (state && state.scrollTop) + this.panelNode.scrollTop = state.scrollTop; + } + }, + + ihide: function() + { + this.showToolbarButtons("fbCSSButtons", false); + + this.lastScrollTop = this.panelNode.scrollTop; + }, + + supportsObject: function(object) + { + if (object instanceof CSSStyleSheet) + return 1; + else if (object instanceof CSSStyleRule) + return 2; + else if (object instanceof CSSStyleDeclaration) + return 2; + else if (object instanceof SourceLink && object.type == "css" && reCSS.test(object.href)) + return 2; + else + return 0; + }, + + updateLocation: function(styleSheet) + { + if (!styleSheet) + return; + if (styleSheet.editStyleSheet) + styleSheet = styleSheet.editStyleSheet.sheet; + + // if it is a restricted stylesheet, show the warning message and abort the update process + if (styleSheet.restricted) + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, this.panelNode); + + // TODO: xxxpedro remove when there the external resource problem is fixed + externalStyleSheetWarning.tag.append({ + object: "The stylesheet could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22" + }, this.panelNode); + + return; + } + + var rules = this.getStyleSheetRules(this.context, styleSheet); + + var result; + if (rules.length) + result = this.template.tag.replace({rules: rules}, this.panelNode); + else + result = FirebugReps.Warning.tag.replace({object: "EmptyStyleSheet"}, this.panelNode); + + // TODO: xxxpedro need to fix showToolbarButtons function + //this.showToolbarButtons("fbCSSButtons", !isSystemStyleSheet(this.location)); + + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, this.panelNode]); + }, + + updateSelection: function(object) + { + this.selection = null; + + if (object instanceof CSSStyleDeclaration) { + object = object.parentRule; + } + + if (object instanceof CSSStyleRule) + { + this.navigate(object.parentStyleSheet); + this.highlightRule(object); + } + else if (object instanceof CSSStyleSheet) + { + this.navigate(object); + } + else if (object instanceof SourceLink) + { + try + { + var sourceLink = object; + + var sourceFile = getSourceFileByHref(sourceLink.href, this.context); + if (sourceFile) + { + clearNode(this.panelNode); // replace rendered stylesheets + this.showSourceFile(sourceFile); + + var lineNo = object.line; + if (lineNo) + this.scrollToLine(lineNo, this.jumpHighlightFactory(lineNo, this.context)); + } + else // XXXjjb we should not be taking this path + { + var stylesheet = getStyleSheetByHref(sourceLink.href, this.context); + if (stylesheet) + this.navigate(stylesheet); + else + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href, sourceLink); + } + } + } + catch(exc) { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.upDateSelection FAILS "+exc, exc); + } + } + }, + + updateOption: function(name, value) + { + if (name == "expandShorthandProps") + this.refresh(); + }, + + getLocationList: function() + { + var styleSheets = getAllStyleSheets(this.context); + return styleSheets; + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") }, + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ]; + }, + + getContextMenuItems: function(style, target) + { + var items = []; + + if (this.infoTipType == "color") + { + items.push( + {label: "CopyColor", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) } + ); + } + else if (this.infoTipType == "image") + { + items.push( + {label: "CopyImageLocation", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) }, + {label: "OpenImageInNewTab", + command: bindFixed(openNewTab, FBL, this.infoTipObject) } + ); + } + + ///if (this.selection instanceof Element) + if (isElement(this.selection)) + { + items.push( + //"-", + {label: "EditStyle", + command: bindFixed(this.editElementStyle, this) } + ); + } + else if (!isSystemStyleSheet(this.selection)) + { + items.push( + //"-", + {label: "NewRule", + command: bindFixed(this.insertRule, this, target) } + ); + } + + var cssRule = getAncestorByClass(target, "cssRule"); + if (cssRule && hasClass(cssRule, "cssEditableRule")) + { + items.push( + "-", + {label: "NewProp", + command: bindFixed(this.insertPropertyRow, this, target) } + ); + + var propRow = getAncestorByClass(target, "cssProp"); + if (propRow) + { + var propName = getChildByClass(propRow, "cssPropName")[textContent]; + var isDisabled = hasClass(propRow, "disabledStyle"); + + items.push( + {label: $STRF("EditProp", [propName]), nol10n: true, + command: bindFixed(this.editPropertyRow, this, propRow) }, + {label: $STRF("DeleteProp", [propName]), nol10n: true, + command: bindFixed(this.deletePropertyRow, this, propRow) }, + {label: $STRF("DisableProp", [propName]), nol10n: true, + type: "checkbox", checked: isDisabled, + command: bindFixed(this.disablePropertyRow, this, propRow) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ); + + return items; + }, + + browseObject: function(object) + { + if (this.infoTipType == "image") + { + openNewTab(this.infoTipObject); + return true; + } + }, + + showInfoTip: function(infoTip, target, x, y) + { + var propValue = getAncestorByClass(target, "cssPropValue"); + if (propValue) + { + var offset = getClientOffset(propValue); + var offsetX = x-offset.x; + + var text = propValue[textContent]; + var charWidth = propValue.offsetWidth/text.length; + var charOffset = Math.floor(offsetX/charWidth); + + var cssValue = parseCSSValue(text, charOffset); + if (cssValue) + { + if (cssValue.value == this.infoTipValue) + return true; + + this.infoTipValue = cssValue.value; + + if (cssValue.type == "rgb" || (!cssValue.type && isColorKeyword(cssValue.value))) + { + this.infoTipType = "color"; + this.infoTipObject = cssValue.value; + + return Firebug.InfoTip.populateColorInfoTip(infoTip, cssValue.value); + } + else if (cssValue.type == "url") + { + ///var propNameNode = target.parentNode.getElementsByClassName("cssPropName").item(0); + var propNameNode = getElementByClass(target.parentNode, "cssPropName"); + if (propNameNode && isImageRule(propNameNode[textContent])) + { + var rule = Firebug.getRepObject(target); + var baseURL = this.getStylesheetURL(rule); + var relURL = parseURLValue(cssValue.value); + var absURL = isDataURL(relURL) ? relURL:absoluteURL(relURL, baseURL); + var repeat = parseRepeatValue(text); + + this.infoTipType = "image"; + this.infoTipObject = absURL; + + return Firebug.InfoTip.populateImageInfoTip(infoTip, absURL, repeat); + } + } + } + } + + delete this.infoTipType; + delete this.infoTipValue; + delete this.infoTipObject; + }, + + getEditor: function(target, value) + { + if (target == this.panelNode + || hasClass(target, "cssSelector") || hasClass(target, "cssRule") + || hasClass(target, "cssSheet")) + { + if (!this.ruleEditor) + this.ruleEditor = new CSSRuleEditor(this.document); + + return this.ruleEditor; + } + else + { + if (!this.editor) + this.editor = new CSSEditor(this.document); + + return this.editor; + } + }, + + getDefaultLocation: function() + { + try + { + var styleSheets = this.context.window.document.styleSheets; + if (styleSheets.length) + { + var sheet = styleSheets[0]; + return (Firebug.filterSystemURLs && isSystemURL(getURLForStyleSheet(sheet))) ? null : sheet; + } + } + catch (exc) + { + if (FBTrace.DBG_LOCATIONS) + FBTrace.sysout("css.getDefaultLocation FAILS "+exc, exc); + } + }, + + getObjectDescription: function(styleSheet) + { + var url = getURLForStyleSheet(styleSheet); + var instance = getInstanceForStyleSheet(styleSheet); + + var baseDescription = splitURLBase(url); + if (instance) { + baseDescription.name = baseDescription.name + " #" + (instance + 1); + } + return baseDescription; + }, + + search: function(text, reverse) + { + var curDoc = this.searchCurrentDoc(!Firebug.searchGlobal, text, reverse); + if (!curDoc && Firebug.searchGlobal) + { + return this.searchOtherDocs(text, reverse); + } + return curDoc; + }, + + searchOtherDocs: function(text, reverse) + { + var scanRE = Firebug.Search.getTestingRegex(text); + function scanDoc(styleSheet) { + // we don't care about reverse here as we are just looking for existence, + // if we do have a result we will handle the reverse logic on display + for (var i = 0; i < styleSheet.cssRules.length; i++) + { + if (scanRE.test(styleSheet.cssRules[i].cssText)) + { + return true; + } + } + } + + if (this.navigateToNextDocument(scanDoc, reverse)) + { + return this.searchCurrentDoc(true, text, reverse); + } + }, + + searchCurrentDoc: function(wrapSearch, text, reverse) + { + if (!text) + { + delete this.currentSearch; + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + { + row = this.currentSearch.findNext(wrapSearch, false, reverse, Firebug.Search.isCaseSensitive(text)); + } + else + { + if (this.editing) + { + this.currentSearch = new TextSearch(this.stylesheetEditor.box); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + scrollSelectionIntoView(this); + return true; + } + else + return false; + } + else + { + function findRow(node) { return node.nodeType == 1 ? node : node.parentNode; } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + } + } + + if (row) + { + this.document.defaultView.getSelection().selectAllChildren(row); + scrollIntoCenterView(row, this.panelNode); + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, null]); + return false; + } + }, + + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive"), + Firebug.Search.searchOptionMenu("search.Multiple_Files", "searchGlobal") + ]; + } +}); +/**/ +// ************************************************************************************************ + +function CSSElementPanel() {} + +CSSElementPanel.prototype = extend(Firebug.CSSStyleSheetPanel.prototype, +{ + template: domplate( + { + cascadedTag: + DIV({"class": "a11yCSSView", role : 'presentation'}, + DIV({role : 'list', 'aria-label' : $STR('aria.labels.style rules') }, + FOR("rule", "$rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ), + DIV({role : "list", 'aria-label' :$STR('aria.labels.inherited style rules')}, + FOR("section", "$inherited", + H1({"class": "cssInheritHeader groupHeader focusRow", role : 'listitem' }, + SPAN({"class": "cssInheritLabel"}, "$inheritLabel"), + TAG(FirebugReps.Element.shortTag, {object: "$section.element"}) + ), + DIV({role : 'group'}, + FOR("rule", "$section.rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ) + ) + ) + ), + + ruleTag: + isIE ? + // IE needs the sourceLink first, otherwise it will be rendered outside the panel + DIV({"class": "cssElementRuleContainer"}, + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}), + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}) + ) + : + // other browsers need the sourceLink last, otherwise it will cause an extra space + // before the rule representation + DIV({"class": "cssElementRuleContainer"}, + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}), + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateCascadeView: function(element) + { + //dispatch([Firebug.A11yModel], 'onBeforeCSSRulesAdded', [this]); + var rules = [], sections = [], usedProps = {}; + this.getInheritedRules(element, sections, usedProps); + this.getElementRules(element, rules, usedProps); + + if (rules.length || sections.length) + { + var inheritLabel = "Inherited from"; // $STR("InheritedFrom"); + var result = this.template.cascadedTag.replace({rules: rules, inherited: sections, + inheritLabel: inheritLabel}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + else + { + var result = FirebugReps.Warning.tag.replace({object: "EmptyElementCSS"}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + + // TODO: xxxpedro remove when there the external resource problem is fixed + if (externalStyleSheetURLs.length > 0) + externalStyleSheetWarning.tag.append({ + object: "The results here may be inaccurate because some " + + "stylesheets could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22" + }, this.panelNode); + }, + + getStylesheetURL: function(rule) + { + // if the parentStyleSheet.href is null, CSS std says its inline style. + // TODO: xxxpedro IE doesn't have rule.parentStyleSheet so we must fall back to the doc.location + if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href) + return rule.parentStyleSheet.href; + else + return this.selection.ownerDocument.location.href; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getInheritedRules: function(element, sections, usedProps) + { + var parent = element.parentNode; + if (parent && parent.nodeType == 1) + { + this.getInheritedRules(parent, sections, usedProps); + + var rules = []; + this.getElementRules(parent, rules, usedProps, true); + + if (rules.length) + sections.splice(0, 0, {element: parent, rules: rules}); + } + }, + + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + + // TODO: xxxpedro remove document specificity issue + //var eid = ElementCache(element); + //inspectedRules = ElementCSSRulesMap[eid]; + + inspectedRules = getElementCSSRules(element); + + if (inspectedRules) + { + for (var i = 0, length=inspectedRules.length; i < length; ++i) + { + var ruleId = inspectedRules[i]; + var ruleData = CSSRuleMap[ruleId]; + var rule = ruleData.rule; + + var ssid = ruleData.styleSheetId; + var parentStyleSheet = StyleSheetCache.get(ssid); + + var href = parentStyleSheet.externalURL ? parentStyleSheet.externalURL : parentStyleSheet.href; // Null means inline + + var instance = null; + //var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = false; + //var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + // + //var line = domUtils.getRuleLine(rule); + var line; + + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: ruleData.selector, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /* + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + try + { + inspectedRules = domUtils ? domUtils.getCSSStyleRules(element) : null; + } catch (exc) {} + + if (inspectedRules) + { + for (var i = 0; i < inspectedRules.Count(); ++i) + { + var rule = QI(inspectedRules.GetElementAt(i), nsIDOMCSSStyleRule); + + var href = rule.parentStyleSheet.href; // Null means inline + + var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + var line = domUtils.getRuleLine(rule); + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: rule.selectorText, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /**/ + markOverridenProps: function(props, usedProps, inheritMode) + { + for (var i = 0; i < props.length; ++i) + { + var prop = props[i]; + if ( usedProps.hasOwnProperty(prop.name) ) + { + var deadProps = usedProps[prop.name]; // all previous occurrences of this property + for (var j = 0; j < deadProps.length; ++j) + { + var deadProp = deadProps[j]; + if (!deadProp.disabled && !deadProp.wasInherited && deadProp.important && !prop.important) + prop.overridden = true; // new occurrence overridden + else if (!prop.disabled) + deadProp.overridden = true; // previous occurrences overridden + } + } + else + usedProps[prop.name] = []; + + prop.wasInherited = inheritMode ? true : false; + usedProps[prop.name].push(prop); // all occurrences of a property seen so far, by name + } + }, + + getStyleProperties: function(element, rules, usedProps, inheritMode) + { + var props = this.parseCSSProps(element.style, inheritMode); + this.addOldProperties(this.context, getElementXPath(element), inheritMode, props); + + sortProperties(props); + this.markOverridenProps(props, usedProps, inheritMode); + + if (props.length) + rules.splice(0, 0, + {rule: element, id: getElementXPath(element), + selector: "element.style", props: props, inherited: inheritMode}); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "css", + title: "Style", + parentPanel: "HTML", + order: 0, + + initialize: function() + { + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + Firebug.CSSStyleSheetPanel.prototype.initialize.apply(this, arguments); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + + //this.updateCascadeView(document.getElementsByTagName("h1")[0]); + //this.updateCascadeView(document.getElementById("build")); + + /* + this.onStateChange = bindFixed(this.contentStateCheck, this); + this.onHoverChange = bindFixed(this.contentStateCheck, this, STATE_HOVER); + this.onActiveChange = bindFixed(this.contentStateCheck, this, STATE_ACTIVE); + /**/ + }, + + ishow: function(state) + { + }, + + watchWindow: function(win) + { + if (domUtils) + { + // Normally these would not be required, but in order to update after the state is set + // using the options menu we need to monitor these global events as well + var doc = win.document; + ///addEvent(doc, "mouseover", this.onHoverChange); + ///addEvent(doc, "mousedown", this.onActiveChange); + } + }, + unwatchWindow: function(win) + { + var doc = win.document; + ///removeEvent(doc, "mouseover", this.onHoverChange); + ///removeEvent(doc, "mousedown", this.onActiveChange); + + if (isAncestor(this.stateChangeEl, doc)) + { + this.removeStateChangeHandlers(); + } + }, + + supportsObject: function(object) + { + return object instanceof Element ? 1 : 0; + }, + + updateView: function(element) + { + this.updateCascadeView(element); + if (domUtils) + { + this.contentState = safeGetContentState(element); + this.addStateChangeHandlers(element); + } + }, + + updateSelection: function(element) + { + if ( !instanceOf(element , "Element") ) // html supports SourceLink + return; + + if (sothinkInstalled) + { + FirebugReps.Warning.tag.replace({object: "SothinkWarning"}, this.panelNode); + return; + } + + /* + if (!domUtils) + { + FirebugReps.Warning.tag.replace({object: "DOMInspectorWarning"}, this.panelNode); + return; + } + /**/ + + if (!element) + return; + + this.updateView(element); + }, + + updateOption: function(name, value) + { + if (name == "showUserAgentCSS" || name == "expandShorthandProps") + this.refresh(); + }, + + getOptionsMenuItems: function() + { + var ret = [ + {label: "Show User Agent CSS", type: "checkbox", checked: Firebug.showUserAgentCSS, + command: bindFixed(Firebug.togglePref, Firebug, "showUserAgentCSS") }, + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") } + ]; + if (domUtils && this.selection) + { + var state = safeGetContentState(this.selection); + + ret.push("-"); + ret.push({label: ":active", type: "checkbox", checked: state & STATE_ACTIVE, + command: bindFixed(this.updateContentState, this, STATE_ACTIVE, state & STATE_ACTIVE)}); + ret.push({label: ":hover", type: "checkbox", checked: state & STATE_HOVER, + command: bindFixed(this.updateContentState, this, STATE_HOVER, state & STATE_HOVER)}); + } + return ret; + }, + + updateContentState: function(state, remove) + { + domUtils.setContentState(remove ? this.selection.ownerDocument.documentElement : this.selection, state); + this.refresh(); + }, + + addStateChangeHandlers: function(el) + { + this.removeStateChangeHandlers(); + + /* + addEvent(el, "focus", this.onStateChange); + addEvent(el, "blur", this.onStateChange); + addEvent(el, "mouseup", this.onStateChange); + addEvent(el, "mousedown", this.onStateChange); + addEvent(el, "mouseover", this.onStateChange); + addEvent(el, "mouseout", this.onStateChange); + /**/ + + this.stateChangeEl = el; + }, + + removeStateChangeHandlers: function() + { + var sel = this.stateChangeEl; + if (sel) + { + /* + removeEvent(sel, "focus", this.onStateChange); + removeEvent(sel, "blur", this.onStateChange); + removeEvent(sel, "mouseup", this.onStateChange); + removeEvent(sel, "mousedown", this.onStateChange); + removeEvent(sel, "mouseover", this.onStateChange); + removeEvent(sel, "mouseout", this.onStateChange); + /**/ + } + }, + + contentStateCheck: function(state) + { + if (!state || this.contentState & state) + { + var timeoutRunner = bindFixed(function() + { + var newState = safeGetContentState(this.selection); + if (newState != this.contentState) + { + this.context.invalidatePanels(this.name); + } + }, this); + + // Delay exec until after the event has processed and the state has been updated + setTimeout(timeoutRunner, 0); + } + } +}); + +function safeGetContentState(selection) +{ + try + { + return domUtils.getContentState(selection); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.safeGetContentState; EXCEPTION", e); + } +} + +// ************************************************************************************************ + +function CSSComputedElementPanel() {} + +CSSComputedElementPanel.prototype = extend(CSSElementPanel.prototype, +{ + template: domplate( + { + computedTag: + DIV({"class": "a11yCSSView", role : "list", "aria-label" : $STR('aria.labels.computed styles')}, + FOR("group", "$groups", + H1({"class": "cssInheritHeader groupHeader focusRow", role : "listitem"}, + SPAN({"class": "cssInheritLabel"}, "$group.title") + ), + TABLE({width: "100%", role : 'group'}, + TBODY({role : 'presentation'}, + FOR("prop", "$group.props", + TR({"class": 'focusRow computedStyleRow', role : 'listitem'}, + TD({"class": "stylePropName", role : 'presentation'}, "$prop.name"), + TD({"class": "stylePropValue", role : 'presentation'}, "$prop.value") + ) + ) + ) + ) + ) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateComputedView: function(element) + { + var win = isIE ? + element.ownerDocument.parentWindow : + element.ownerDocument.defaultView; + + var style = isIE ? + element.currentStyle : + win.getComputedStyle(element, ""); + + var groups = []; + + for (var groupName in styleGroups) + { + // TODO: xxxpedro i18n $STR + //var title = $STR("StyleGroup-" + groupName); + var title = styleGroupTitles[groupName]; + var group = {title: title, props: []}; + groups.push(group); + + var props = styleGroups[groupName]; + for (var i = 0; i < props.length; ++i) + { + var propName = props[i]; + var propValue = style.getPropertyValue ? + style.getPropertyValue(propName) : + ""+style[toCamelCase(propName)]; + + if (propValue === undefined || propValue === null) + continue; + + propValue = stripUnits(rgbToHex(propValue)); + if (propValue) + group.props.push({name: propName, value: propValue}); + } + } + + var result = this.template.computedTag.replace({groups: groups}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "computed", + title: "Computed", + parentPanel: "HTML", + order: 1, + + updateView: function(element) + { + this.updateComputedView(element); + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Refresh", command: bind(this.refresh, this) } + ]; + } +}); + +// ************************************************************************************************ +// CSSEditor + +function CSSEditor(doc) +{ + this.initializeInline(doc); +} + +CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var rule = Firebug.getRepObject(target); + var emptyProp = + { + // TODO: xxxpedro - uses charCode(255) to force the element being rendered, + // allowing webkit to get the correct position of the property name "span", + // when inserting a new CSS rule? + name: "", + value: "", + important: "" + }; + + if (insertWhere == "before") + return CSSPropTag.tag.insertBefore({prop: emptyProp, rule: rule}, target); + else + return CSSPropTag.tag.insertAfter({prop: emptyProp, rule: rule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + // We need to check the value first in order to avoid a problem in IE8 + // See Issue 3038: Empty (null) styles when adding CSS styles in Firebug Lite + if (!value) return; + + target.innerHTML = escapeForCss(value); + + var row = getAncestorByClass(target, "cssProp"); + if (hasClass(row, "disabledStyle")) + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(target); + + if (hasClass(target, "cssPropName")) + { + if (value && previousValue != value) // name of property has changed. + { + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + + if (propValue && propValue != "undefined") { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSEditor.saveEdit : "+previousValue+"->"+value+" = "+propValue+"\n"); + if (previousValue) + Firebug.CSSModule.removeProperty(rule, previousValue); + Firebug.CSSModule.setProperty(rule, value, parsedValue.value, parsedValue.priority); + } + } + else if (!value) // name of the property has been deleted, so remove the property. + Firebug.CSSModule.removeProperty(rule, previousValue); + } + else if (getAncestorByClass(target, "cssPropValue")) + { + var propName = getChildByClass(row, "cssPropName")[textContent]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + + if (FBTrace.DBG_CSS) + { + FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName +" = "+propValue+"\n"); + // FBTrace.sysout("CSSEditor.saveEdit BEFORE style:",style); + } + + if (value && value != "null") + { + var parsedValue = parsePriority(value); + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + } + else if (previousValue && previousValue != "null") + Firebug.CSSModule.removeProperty(rule, propName); + } + + this.panel.markChange(this.panel.name == "stylesheet"); + }, + + advanceToNext: function(target, charCode) + { + if (charCode == 58 /*":"*/ && hasClass(target, "cssPropName")) + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + if (hasClass(this.target, "cssPropName")) + return {start: 0, end: value.length-1}; + else + return parseCSSValue(value, offset); + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + if (hasClass(this.target, "cssPropName")) + { + return getCSSPropertyNames(); + } + else + { + var row = getAncestorByClass(this.target, "cssProp"); + var propName = getChildByClass(row, "cssPropName")[textContent]; + return getCSSKeywordsByProperty(propName); + } + } +}); + +//************************************************************************************************ +//CSSRuleEditor + +function CSSRuleEditor(doc) +{ + this.initializeInline(doc); + this.completeAsYouType = false; +} +CSSRuleEditor.uniquifier = 0; +CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var emptyRule = { + selector: "", + id: "", + props: [], + isSelectorEditable: true + }; + + if (insertWhere == "before") + return CSSStyleRuleTag.tag.insertBefore({rule: emptyRule}, target); + else + return CSSStyleRuleTag.tag.insertAfter({rule: emptyRule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSRuleEditor.saveEdit: '" + value + "' '" + previousValue + "'", target); + + target.innerHTML = escapeForCss(value); + + if (value === previousValue) return; + + var row = getAncestorByClass(target, "cssRule"); + var styleSheet = this.panel.location; + styleSheet = styleSheet.editStyleSheet ? styleSheet.editStyleSheet.sheet : styleSheet; + + var cssRules = styleSheet.cssRules; + var rule = Firebug.getRepObject(target), oldRule = rule; + var ruleIndex = cssRules.length; + if (rule || Firebug.getRepObject(row.nextSibling)) + { + var searchRule = rule || Firebug.getRepObject(row.nextSibling); + for (ruleIndex=0; ruleIndex b.name ? 1 : -1; + }); +} + +function getTopmostRuleLine(panelNode) +{ + for (var child = panelNode.firstChild; child; child = child.nextSibling) + { + if (child.offsetTop+child.offsetHeight > panelNode.scrollTop) + { + var rule = child.repObject; + if (rule) + return { + line: domUtils.getRuleLine(rule), + offset: panelNode.scrollTop-child.offsetTop + }; + } + } + return 0; +} + +function getStyleSheetCSS(sheet, context) +{ + if (sheet.ownerNode instanceof HTMLStyleElement) + return sheet.ownerNode.innerHTML; + else + return context.sourceCache.load(sheet.href).join(""); +} + +function getStyleSheetOwnerNode(sheet) { + for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet); + + return sheet.ownerNode; +} + +function scrollSelectionIntoView(panel) +{ + var selCon = getSelectionController(panel); + selCon.scrollSelectionIntoView( + nsISelectionController.SELECTION_NORMAL, + nsISelectionController.SELECTION_FOCUS_REGION, true); +} + +function getSelectionController(panel) +{ + var browser = Firebug.chrome.getPanelBrowser(panel); + return browser.docShell.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsISelectionDisplay) + .QueryInterface(nsISelectionController); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.CSSModule); +Firebug.registerPanel(Firebug.CSSStyleSheetPanel); +Firebug.registerPanel(CSSElementPanel); +Firebug.registerPanel(CSSComputedElementPanel); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Script Module + +Firebug.Script = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Script") : null; + }, + + selectSourceCode: function(index) + { + this.getPanel().selectSourceCode(index); + } +}); + +Firebug.registerModule(Firebug.Script); + + +// ************************************************************************************************ +// Script Panel + +function ScriptPanel(){}; + +ScriptPanel.prototype = extend(Firebug.Panel, +{ + name: "Script", + title: "Script", + + selectIndex: 0, // index of the current selectNode's option + sourceIndex: -1, // index of the script node, based in doc.getElementsByTagName("script") + + options: { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var scripts = doc.getElementsByTagName("script"); + var selectNode = this.selectNode = createElement("select"); + + for(var i=0, script; script=scripts[i]; i++) + { + // Don't show Firebug Lite source code in the list of options + if (Firebug.ignoreFirebugElements && script.getAttribute("firebugIgnore")) + continue; + + var fileName = getFileName(script.src) || getFileName(doc.location.href); + var option = createElement("option", {value:i}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }; + + this.toolButtonsNode.appendChild(selectNode); + }, + + initialize: function() + { + // we must render the code first, so the persistent state can be restore + this.selectSourceCode(this.selectIndex); + + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.selectNode, "change", this.onChangeSelect); + }, + + shutdown: function() + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + detach: function(oldChrome, newChrome) + { + Firebug.Panel.detach.apply(this, arguments); + + var oldPanel = oldChrome.getPanel("Script"); + var index = oldPanel.selectIndex; + + this.selectNode.selectedIndex = index; + this.selectIndex = index; + this.sourceIndex = -1; + }, + + onChangeSelect: function(event) + { + var select = this.selectNode; + + this.selectIndex = select.selectedIndex; + + var option = select.options[select.selectedIndex]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + selectSourceCode: function(index) + { + var select = this.selectNode; + select.selectedIndex = index; + + var option = select.options[index]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + renderSourceCode: function(index) + { + if (this.sourceIndex != index) + { + var renderProcess = function renderProcess(src) + { + var html = [], + hl = 0; + + src = isIE && !isExternal ? + src+'\n' : // IE put an extra line when reading source of local resources + '\n'+src; + + // find the number of lines of code + src = src.replace(/\n\r|\r\n/g, "\n"); + var match = src.match(/[\n]/g); + var lines=match ? match.length : 0; + + // render the full source code + line numbers html + html[hl++] = '
      ';
      +                html[hl++] = escapeHTML(src);
      +                html[hl++] = '
      '; + + // render the line number divs + for(var l=1, lines; l<=lines; l++) + { + html[hl++] = '
      '; + html[hl++] = l; + html[hl++] = '
      '; + } + + html[hl++] = '
      '; + + updatePanel(html); + }; + + var updatePanel = function(html) + { + self.panelNode.innerHTML = html.join(""); + + // IE needs this timeout, otherwise the panel won't scroll + setTimeout(function(){ + self.synchronizeUI(); + },0); + }; + + var onFailure = function() + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, self.panelNode); + }; + + var self = this; + + var doc = Firebug.browser.document; + var script = doc.getElementsByTagName("script")[index]; + var url = getScriptURL(script); + var isExternal = url && url != doc.location.href; + + try + { + if (isExternal) + { + Ajax.request({url: url, onSuccess: renderProcess, onFailure: onFailure}); + } + else + { + var src = script.innerHTML; + renderProcess(src); + } + } + catch(e) + { + onFailure(); + } + + this.sourceIndex = index; + } + } +}); + +Firebug.registerPanel(ScriptPanel); + + +// ************************************************************************************************ + + +var getScriptURL = function getScriptURL(script) +{ + var reFile = /([^\/\?#]+)(#.+)?$/; + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = Firebug.browser.document; + + var file = reFile.exec(script.src); + + if (file) + { + var fileName = file[1]; + var fileOptions = file[2]; + + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; + + } + // relative path + else + { + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(doc.location.href)[1]; + + // "../some/path" + if (backDir) + { + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + return path + fileName; + } +}; + +var getFileName = function getFileName(path) +{ + if (!path) return ""; + + var match = path && path.match(/[^\/]+(\?.*)?(#.*)?$/); + + return match && match[0] || path; +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var ElementCache = Firebug.Lite.Cache.Element; + +var insertSliceSize = 18; +var insertInterval = 40; + +var ignoreVars = +{ + "__firebug__": 1, + "eval": 1, + + // We are forced to ignore Java-related variables, because + // trying to access them causes browser freeze + "java": 1, + "sun": 1, + "Packages": 1, + "JavaArray": 1, + "JavaMember": 1, + "JavaObject": 1, + "JavaClass": 1, + "JavaPackage": 1, + "_firebug": 1, + "_FirebugConsole": 1, + "_FirebugCommandLine": 1 +}; + +if (Firebug.ignoreFirebugElements) + ignoreVars[Firebug.Lite.Cache.ID] = 1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var memberPanelRep = + isIE6 ? + {"class": "memberLabel $member.type\\Label", href: "javacript:void(0)"} + : + {"class": "memberLabel $member.type\\Label"}; + +var RowTag = + TR({"class": "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren", role : 'presentation', + level: "$member.level"}, + TD({"class": "memberLabelCell", style: "padding-left: $member.indent\\px", role : 'presentation'}, + A(memberPanelRep, + SPAN({}, "$member.name") + ) + ), + TD({"class": "memberValueCell", role : 'presentation'}, + TAG("$member.tag", {object: "$member.value"}) + ) + ); + +var WatchRowTag = + TR({"class": "watchNewRow", level: 0}, + TD({"class": "watchEditCell", colspan: 2}, + DIV({"class": "watchEditBox a11yFocusNoTab", role: "button", 'tabindex' : '0', + 'aria-label' : $STR('press enter to add new watch expression')}, + $STR("NewWatch") + ) + ) + ); + +var SizerRow = + TR({role : 'presentation'}, + TD({width: "30%"}), + TD({width: "70%"}) + ); + +var domTableClass = isIElt8 ? "domTable domTableIE" : "domTable"; +var DirTablePlate = domplate(Firebug.Rep, +{ + tag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, onclick: "$onClick", role :"tree"}, + TBODY({role: 'presentation'}, + SizerRow, + FOR("member", "$object|memberIterator", RowTag) + ) + ), + + watchTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow, + WatchRowTag + ) + ), + + tableTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow + ) + ), + + rowTag: + FOR("member", "$members", RowTag), + + memberIterator: function(object, level) + { + return getMembers(object, level); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + if (!isLeftClick(event)) + return; + + var target = event.target || event.srcElement; + + var row = getAncestorByClass(target, "memberRow"); + var label = getAncestorByClass(target, "memberLabel"); + if (label && hasClass(row, "hasChildren")) + { + var row = label.parentNode.parentNode; + this.toggleRow(row); + } + else + { + var object = Firebug.getRepObject(target); + if (typeof(object) == "function") + { + Firebug.chrome.select(object, "script"); + cancelEvent(event); + } + else if (event.detail == 2 && !object) + { + var panel = row.parentNode.parentNode.domPanel; + if (panel) + { + var rowValue = panel.getRowPropertyValue(row); + if (typeof(rowValue) == "boolean") + panel.setPropertyValue(row, !rowValue); + else + panel.editProperty(row); + + cancelEvent(event); + } + } + } + + return false; + }, + + toggleRow: function(row) + { + var level = parseInt(row.getAttribute("level")); + var toggles = row.parentNode.parentNode.toggles; + + if (hasClass(row, "opened")) + { + removeClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Remove the path from the toggle tree + for (var i = 0; i < path.length; ++i) + { + if (i == path.length-1) + delete toggles[path[i]]; + else + toggles = toggles[path[i]]; + } + } + + var rowTag = this.rowTag; + var tbody = row.parentNode; + + setTimeout(function() + { + for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling) + { + if (parseInt(firstRow.getAttribute("level")) <= level) + break; + + tbody.removeChild(firstRow); + } + }, row.insertTimeout ? row.insertTimeout : 0); + } + else + { + setClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Mark the path in the toggle tree + for (var i = 0; i < path.length; ++i) + { + var name = path[i]; + if (toggles.hasOwnProperty(name)) + toggles = toggles[name]; + else + toggles = toggles[name] = {}; + } + } + + var value = row.lastChild.firstChild.repObject; + var members = getMembers(value, level+1); + + var rowTag = this.rowTag; + var lastRow = row; + + var delay = 0; + //var setSize = members.length; + //var rowCount = 1; + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + setTimeout(function() + { + if (lastRow.parentNode) + { + var result = rowTag.insertRows({members: slice}, lastRow); + lastRow = result[1]; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [null, result, rowCount, setSize]); + //rowCount += insertSliceSize; + } + if (isLast) + row.removeAttribute("insertTimeout"); + }, delay); + } + + delay += insertInterval; + } + + row.insertTimeout = delay; + } + } +}); + + + +// ************************************************************************************************ + +Firebug.DOMBasePanel = function() {} + +Firebug.DOMBasePanel.prototype = extend(Firebug.Panel, +{ + tag: DirTablePlate.tableTag, + + getRealObject: function(object) + { + // TODO: Move this to some global location + // TODO: Unwrapping should be centralized rather than sprinkling it around ad hoc. + // TODO: We might be able to make this check more authoritative with QueryInterface. + if (!object) return object; + if (object.wrappedJSObject) return object.wrappedJSObject; + return object; + }, + + rebuild: function(update, scrollTop) + { + //dispatch([Firebug.A11yModel], 'onBeforeDomUpdateSelection', [this]); + var members = getMembers(this.selection); + expandMembers(members, this.toggles, 0, 0); + + this.showMembers(members, update, scrollTop); + + //TODO: xxxpedro statusbar + if (!this.parentPanel) + updateStatusBar(this); + }, + + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!tbody.lastChild) return; + + result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //rowCount += insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop) + panelNode.scrollTop = priorScrollTop; + + + // enable to measure rendering performance + //if (isLast) alert(new Date().getTime() - renderStart + "ms"); + + + }, delay)); + + delay += insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + + /* + // new + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + var _insertSliceSize = insertSliceSize; + var _insertInterval = insertInterval; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + var lastSkip = renderStart, now; + + while (members.length) + { + with({slice: members.splice(0, _insertSliceSize), isLast: !members.length}) + { + var _tbody = tbody; + var _rowTag = rowTag; + var _panelNode = panelNode; + var _priorScrollTop = priorScrollTop; + + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!_tbody.lastChild) return; + + result = _rowTag.insertRows({members: slice}, _tbody.lastChild); + + //rowCount += _insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((_panelNode.scrollHeight + _panelNode.offsetHeight) >= _priorScrollTop) + _panelNode.scrollTop = _priorScrollTop; + + + // enable to measure rendering performance + //alert("gap: " + (new Date().getTime() - lastSkip)); + //lastSkip = new Date().getTime(); + + //if (isLast) alert("new: " + (new Date().getTime() - renderStart) + "ms"); + + }, delay)); + + delay += _insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + /**/ + + showEmptyMembers: function() + { + FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode); + }, + + findPathObject: function(object) + { + var pathIndex = -1; + for (var i = 0; i < this.objectPath.length; ++i) + { + // IE needs === instead of == or otherwise some objects will + // be considered equal to different objects, returning the + // wrong index of the objectPath array + if (this.getPathObject(i) === object) + return i; + } + + return -1; + }, + + getPathObject: function(index) + { + var object = this.objectPath[index]; + + if (object instanceof Property) + return object.getObject(); + else + return object; + }, + + getRowObject: function(row) + { + var object = getRowOwnerObject(row); + return object ? object : this.selection; + }, + + getRowPropertyValue: function(row) + { + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object) + { + var propName = getRowName(row); + + if (object instanceof jsdIStackFrame) + return Firebug.Debugger.evaluate(propName, this.context); + else + return object[propName]; + } + }, + /* + copyProperty: function(row) + { + var value = this.getRowPropertyValue(row); + copyToClipboard(value); + }, + + editProperty: function(row, editValue) + { + if (hasClass(row, "watchNewRow")) + { + if (this.context.stopped) + Firebug.Editor.startEditing(row, ""); + else if (Firebug.Console.isAlwaysEnabled()) // not stopped in debugger, need command line + { + if (Firebug.CommandLine.onCommandLineFocus()) + Firebug.Editor.startEditing(row, ""); + else + row.innerHTML = $STR("warning.Command line blocked?"); + } + else + row.innerHTML = $STR("warning.Console must be enabled"); + } + else if (hasClass(row, "watchRow")) + Firebug.Editor.startEditing(row, getRowName(row)); + else + { + var object = this.getRowObject(row); + this.context.thisValue = object; + + if (!editValue) + { + var propValue = this.getRowPropertyValue(row); + + var type = typeof(propValue); + if (type == "undefined" || type == "number" || type == "boolean") + editValue = propValue; + else if (type == "string") + editValue = "\"" + escapeJS(propValue) + "\""; + else if (propValue == null) + editValue = "null"; + else if (object instanceof Window || object instanceof jsdIStackFrame) + editValue = getRowName(row); + else + editValue = "this." + getRowName(row); + } + + + Firebug.Editor.startEditing(row, editValue); + } + }, + + deleteProperty: function(row) + { + if (hasClass(row, "watchRow")) + this.deleteWatch(row); + else + { + var object = getRowOwnerObject(row); + if (!object) + object = this.selection; + object = this.getRealObject(object); + + if (object) + { + var name = getRowName(row); + try + { + delete object[name]; + } + catch (exc) + { + return; + } + + this.rebuild(true); + this.markChange(); + } + } + }, + + setPropertyValue: function(row, value) // value must be string + { + if(FBTrace.DBG_DOM) + { + FBTrace.sysout("row: "+row); + FBTrace.sysout("value: "+value+" type "+typeof(value), value); + } + + var name = getRowName(row); + if (name == "this") + return; + + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object && !(object instanceof jsdIStackFrame)) + { + // unwrappedJSObject.property = unwrappedJSObject + Firebug.CommandLine.evaluate(value, this.context, object, this.context.getGlobalScope(), + function success(result, context) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate success object["+name+"]="+result+" type "+typeof(result), result); + object[name] = result; + }, + function failed(exc, context) + { + try + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate failed with exc:"+exc+" object["+name+"]="+value+" type "+typeof(value), exc); + // If the value doesn't parse, then just store it as a string. Some users will + // not realize they're supposed to enter a JavaScript expression and just type + // literal text + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + ); + } + else if (this.context.stopped) + { + try + { + Firebug.CommandLine.evaluate(name+"="+value, this.context); + } + catch (exc) + { + try + { + // See catch block above... + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + } + + this.rebuild(true); + this.markChange(); + }, + + highlightRow: function(row) + { + if (this.highlightedRow) + cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context); + + this.highlightedRow = row; + + if (row) + setClassTimed(row, "jumpHighlight", this.context); + },/**/ + + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + create: function() + { + // TODO: xxxpedro + this.context = Firebug.browser; + + this.objectPath = []; + this.propertyPath = []; + this.viewPath = []; + this.pathIndex = -1; + this.toggles = {}; + + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.panelNode, "mousemove", this.onMouseMove); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + /* + destroy: function(state) + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + + if (this.pathIndex) + state.pathIndex = this.pathIndex; + if (this.viewPath) + state.viewPath = this.viewPath; + if (this.propertyPath) + state.propertyPath = this.propertyPath; + + if (this.propertyPath.length > 0 && !this.propertyPath[1]) + state.firstSelection = persistObject(this.getPathObject(1), this.context); + + Firebug.Panel.destroy.apply(this, arguments); + }, + /**/ + + ishow: function(state) + { + if (this.context.loaded && !this.selection) + { + if (!state) + { + this.select(null); + return; + } + if (state.viewPath) + this.viewPath = state.viewPath; + if (state.propertyPath) + this.propertyPath = state.propertyPath; + + var defaultObject = this.getDefaultSelection(this.context); + var selectObject = defaultObject; + + if (state.firstSelection) + { + var restored = state.firstSelection(this.context); + if (restored) + { + selectObject = restored; + this.objectPath = [defaultObject, restored]; + } + else + this.objectPath = [defaultObject]; + } + else + this.objectPath = [defaultObject]; + + if (this.propertyPath.length > 1) + { + for (var i = 1; i < this.propertyPath.length; ++i) + { + var name = this.propertyPath[i]; + if (!name) + continue; + + var object = selectObject; + try + { + selectObject = object[name]; + } + catch (exc) + { + selectObject = null; + } + + if (selectObject) + { + this.objectPath.push(new Property(object, name)); + } + else + { + // If we can't access a property, just stop + this.viewPath.splice(i); + this.propertyPath.splice(i); + this.objectPath.splice(i); + selectObject = this.getPathObject(this.objectPath.length-1); + break; + } + } + } + + var selection = state.pathIndex <= this.objectPath.length-1 + ? this.getPathObject(state.pathIndex) + : this.getPathObject(this.objectPath.length-1); + + this.select(selection); + } + }, + /* + hide: function() + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + }, + /**/ + + supportsObject: function(object) + { + if (object == null) + return 1000; + + if (typeof(object) == "undefined") + return 1000; + else if (object instanceof SourceLink) + return 0; + else + return 1; // just agree to support everything but not agressively. + }, + + refresh: function() + { + this.rebuild(true); + }, + + updateSelection: function(object) + { + var previousIndex = this.pathIndex; + var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex]; + + var newPath = this.pathToAppend; + delete this.pathToAppend; + + var pathIndex = this.findPathObject(object); + if (newPath || pathIndex == -1) + { + this.toggles = {}; + + if (newPath) + { + // Remove everything after the point where we are inserting, so we + // essentially replace it with the new path + if (previousView) + { + if (this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + var start = previousIndex + 1, + // Opera needs the length argument in splice(), otherwise + // it will consider that only one element should be removed + length = this.objectPath.length - start; + + this.objectPath.splice(start, length); + this.propertyPath.splice(start, length); + this.viewPath.splice(start, length); + } + + var value = this.getPathObject(previousIndex); + if (!value) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection no pathObject for "+previousIndex+"\n"); + return; + } + + for (var i = 0, length = newPath.length; i < length; ++i) + { + var name = newPath[i]; + var object = value; + try + { + value = value[name]; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection FAILS at path_i="+i+" for name:"+name+"\n"); + return; + } + + ++this.pathIndex; + this.objectPath.push(new Property(object, name)); + this.propertyPath.push(name); + this.viewPath.push({toggles: this.toggles, scrollTop: 0}); + } + } + else + { + this.toggles = {}; + + var win = Firebug.browser.window; + //var win = this.context.getGlobalScope(); + if (object === win) + { + this.pathIndex = 0; + this.objectPath = [win]; + this.propertyPath = [null]; + this.viewPath = [{toggles: this.toggles, scrollTop: 0}]; + } + else + { + this.pathIndex = 1; + this.objectPath = [win, object]; + this.propertyPath = [null, null]; + this.viewPath = [ + {toggles: {}, scrollTop: 0}, + {toggles: this.toggles, scrollTop: 0} + ]; + } + } + + this.panelNode.scrollTop = 0; + this.rebuild(); + } + else + { + this.pathIndex = pathIndex; + + var view = this.viewPath[pathIndex]; + this.toggles = view.toggles; + + // Persist the current scroll location + if (previousView && this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + this.rebuild(false, view.scrollTop); + } + }, + + getObjectPath: function(object) + { + return this.objectPath; + }, + + getDefaultSelection: function() + { + return Firebug.browser.window; + //return this.context.getGlobalScope(); + }/*, + + updateOption: function(name, value) + { + const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1, + showDOMFuncs: 1, showDOMConstants: 1}; + if ( optionMap.hasOwnProperty(name) ) + this.rebuild(true); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowUserProps", "showUserProps"), + optionMenu("ShowUserFuncs", "showUserFuncs"), + optionMenu("ShowDOMProps", "showDOMProps"), + optionMenu("ShowDOMFuncs", "showDOMFuncs"), + optionMenu("ShowDOMConstants", "showDOMConstants"), + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ]; + }, + + getContextMenuItems: function(object, target) + { + var row = getAncestorByClass(target, "memberRow"); + + var items = []; + + if (row) + { + var rowName = getRowName(row); + var rowObject = this.getRowObject(row); + var rowValue = this.getRowPropertyValue(row); + + var isWatch = hasClass(row, "watchRow"); + var isStackFrame = rowObject instanceof jsdIStackFrame; + + if (typeof(rowValue) == "string" || typeof(rowValue) == "number") + { + // Functions already have a copy item in their context menu + items.push( + "-", + {label: "CopyValue", + command: bindFixed(this.copyProperty, this, row) } + ); + } + + items.push( + "-", + {label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"), + command: bindFixed(this.editProperty, this, row) } + ); + + if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName))) + { + items.push( + {label: isWatch ? "DeleteWatch" : "DeleteProperty", + command: bindFixed(this.deleteProperty, this, row) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ); + + return items; + }, + + getEditor: function(target, value) + { + if (!this.editor) + this.editor = new DOMEditor(this.document); + + return this.editor; + }/**/ +}); + +// ************************************************************************************************ + +// TODO: xxxpedro statusbar +var updateStatusBar = function(panel) +{ + var path = panel.propertyPath; + var index = panel.pathIndex; + + var r = []; + + for (var i=0, l=path.length; i'); + r.push(i==0 ? "window" : path[i] || "Object"); + r.push('
      '); + + if(i < l-1) + r.push('>'); + } + panel.statusBarNode.innerHTML = r.join(""); +}; + + +var DOMMainPanel = Firebug.DOMPanel = function () {}; + +Firebug.DOMPanel.DirTable = DirTablePlate; + +DOMMainPanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + onClickStatusBar: function(event) + { + var target = event.srcElement || event.target; + var element = getAncestorByClass(target, "fbHover"); + + if(element) + { + var pathIndex = element.getAttribute("pathIndex"); + + if(pathIndex) + { + this.select(this.getPathObject(pathIndex)); + } + } + }, + + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + this.select(target.repObject, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOM", + title: "DOM", + searchable: true, + statusSeparator: ">", + + options: { + hasToolButtons: true, + hasStatusBar: true + }, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + + //TODO: xxxpedro + this.onClickStatusBar = bind(this.onClickStatusBar, this); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(oldPanelNode) + { + //this.panelNode.addEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'console']); + + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro dom + this.ishow(); + + //TODO: xxxpedro + addEvent(this.statusBarNode, "click", this.onClickStatusBar); + }, + + shutdown: function() + { + //this.panelNode.removeEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'console']); + + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }/*, + + search: function(text, reverse) + { + if (!text) + { + delete this.currentSearch; + this.highlightRow(null); + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + row = this.currentSearch.findNext(true, undefined, reverse, Firebug.searchCaseSensitive); + else + { + function findRow(node) { return getAncestorByClass(node, "memberRow"); } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.searchCaseSensitive); + } + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + + scrollIntoCenterView(row, this.panelNode); + + this.highlightRow(row); + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, null]); + return false; + } + }/**/ +}); + +Firebug.registerPanel(DOMMainPanel); + + +// ************************************************************************************************ + + + +// ************************************************************************************************ +// Local Helpers + +var getMembers = function getMembers(object, level) // we expect object to be user-level object wrapped in security blanket +{ + if (!level) + level = 0; + + var ordinals = [], userProps = [], userClasses = [], userFuncs = [], + domProps = [], domFuncs = [], domConstants = []; + + try + { + var domMembers = getDOMMembers(object); + //var domMembers = {}; // TODO: xxxpedro + //var domConstantMap = {}; // TODO: xxxpedro + + if (object.wrappedJSObject) + var insecureObject = object.wrappedJSObject; + else + var insecureObject = object; + + // IE function prototype is not listed in (for..in) + if (isIE && isFunction(object)) + addMember("user", userProps, "prototype", object.prototype, level); + + for (var name in insecureObject) // enumeration is safe + { + if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined. + continue; + + var val; + try + { + val = insecureObject[name]; // getter is safe + } + catch (exc) + { + // Sometimes we get exceptions trying to access certain members + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers cannot access "+name, exc); + } + + var ordinal = parseInt(name); + if (ordinal || ordinal == 0) + { + addMember("ordinal", ordinals, name, val, level); + } + else if (isFunction(val)) + { + if (isClassFunction(val) && !(name in domMembers)) + addMember("userClass", userClasses, name, val, level); + else if (name in domMembers) + addMember("domFunction", domFuncs, name, val, level, domMembers[name]); + else + addMember("userFunction", userFuncs, name, val, level); + } + else + { + //TODO: xxxpedro + /* + var getterFunction = insecureObject.__lookupGetter__(name), + setterFunction = insecureObject.__lookupSetter__(name), + prefix = ""; + + if(getterFunction && !setterFunction) + prefix = "get "; + /**/ + + var prefix = ""; + + if (name in domMembers && !(name in domConstantMap)) + addMember("dom", domProps, (prefix+name), val, level, domMembers[name]); + else if (name in domConstantMap) + addMember("dom", domConstants, (prefix+name), val, level); + else + addMember("user", userProps, (prefix+name), val, level); + } + } + } + catch (exc) + { + // Sometimes we get exceptions just from trying to iterate the members + // of certain objects, like StorageList, but don't let that gum up the works + throw exc; + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers FAILS: ", exc); + //throw exc; + } + + function sortName(a, b) { return a.name > b.name ? 1 : -1; } + function sortOrder(a, b) { return a.order > b.order ? 1 : -1; } + + var members = []; + + members.push.apply(members, ordinals); + + Firebug.showUserProps = true; // TODO: xxxpedro + Firebug.showUserFuncs = true; // TODO: xxxpedro + Firebug.showDOMProps = true; + Firebug.showDOMFuncs = true; + Firebug.showDOMConstants = true; + + if (Firebug.showUserProps) + { + userProps.sort(sortName); + members.push.apply(members, userProps); + } + + if (Firebug.showUserFuncs) + { + userClasses.sort(sortName); + members.push.apply(members, userClasses); + + userFuncs.sort(sortName); + members.push.apply(members, userFuncs); + } + + if (Firebug.showDOMProps) + { + domProps.sort(sortName); + members.push.apply(members, domProps); + } + + if (Firebug.showDOMFuncs) + { + domFuncs.sort(sortName); + members.push.apply(members, domFuncs); + } + + if (Firebug.showDOMConstants) + members.push.apply(members, domConstants); + + return members; +} + +function expandMembers(members, toggles, offset, level) // recursion starts with offset=0, level=0 +{ + var expanded = 0; + for (var i = offset; i < members.length; ++i) + { + var member = members[i]; + if (member.level > level) + break; + + if ( toggles.hasOwnProperty(member.name) ) + { + member.open = "opened"; // member.level <= level && member.name in toggles. + + var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1 + + var args = [i+1, 0]; + args.push.apply(args, newMembers); + members.splice.apply(members, args); + + /* + if (FBTrace.DBG_DOM) + { + FBTrace.sysout("expandMembers member.name", member.name); + FBTrace.sysout("expandMembers toggles", toggles); + FBTrace.sysout("expandMembers toggles[member.name]", toggles[member.name]); + FBTrace.sysout("dom.expandedMembers level: "+level+" member", member); + } + /**/ + + expanded += newMembers.length; + i += newMembers.length + expandMembers(members, toggles[member.name], i+1, level+1); + } + } + + return expanded; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +function isClassFunction(fn) +{ + try + { + for (var name in fn.prototype) + return true; + } catch (exc) {} + return false; +} + +var hasProperties = function hasProperties(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + + // IE function prototype is not listed in (for..in) + if (isFunction(ob)) return true; + + return false; +} + +FBL.ErrorCopy = function(message) +{ + this.message = message; +}; + +var addMember = function addMember(type, props, name, value, level, order) +{ + var rep = Firebug.getRep(value); // do this first in case a call to instanceof reveals contents + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var ErrorCopy = function(){}; //TODO: xxxpedro + + var valueType = typeof(value); + var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) && + (isFunction(value) || (valueType == "object" && value != null) + || (valueType == "string" && value.length > Firebug.stringCropLength)); + + props.push({ + name: name, + value: value, + type: type, + rowClass: "memberRow-"+type, + open: "", + order: order, + level: level, + indent: level*16, + hasChildren: hasChildren, + tag: tag + }); +} + +var getWatchRowIndex = function getWatchRowIndex(row) +{ + var index = -1; + for (; row && hasClass(row, "watchRow"); row = row.previousSibling) + ++index; + return index; +} + +var getRowName = function getRowName(row) +{ + var node = row.firstChild; + return node.textContent ? node.textContent : node.innerText; +} + +var getRowValue = function getRowValue(row) +{ + return row.lastChild.firstChild.repObject; +} + +var getRowOwnerObject = function getRowOwnerObject(row) +{ + var parentRow = getParentRow(row); + if (parentRow) + return getRowValue(parentRow); +} + +var getParentRow = function getParentRow(row) +{ + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + return row; + } +} + +var getPath = function getPath(row) +{ + var name = getRowName(row); + var path = [name]; + + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + { + var name = getRowName(row); + path.splice(0, 0, name); + + --level; + } + } + + return path; +} + +// ************************************************************************************************ + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// DOM Module + +Firebug.DOM = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("DOM") : null; + } +}); + +Firebug.registerModule(Firebug.DOM); + + +// ************************************************************************************************ +// DOM Panel + +var lastHighlightedObject; + +function DOMSidePanel(){}; + +DOMSidePanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + var object = target.repObject; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + /* + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + object = object ? object.repObject : null; + + if(!object) return; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + /**/ + + + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOMSidePanel", + parentPanel: "HTML", + title: "DOM", + + options: { + hasToolButtons: true + }, + + isInitialized: false, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + }, + + initialize: function(){ + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }, + + reattach: function(oldChrome) + { + //this.isInitialized = oldChrome.getPanel("DOM").isInitialized; + this.toggles = oldChrome.getPanel("DOMSidePanel").toggles; + } + +}); + +Firebug.registerPanel(DOMSidePanel); + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.FBTrace = {}; + +(function() { +// ************************************************************************************************ + +var traceOptions = { + DBG_TIMESTAMP: 1, + DBG_INITIALIZE: 1, + DBG_CHROME: 1, + DBG_ERRORS: 1, + DBG_DISPATCH: 1, + DBG_CSS: 1 +}; + +this.module = null; + +this.initialize = function() +{ + if (!this.messageQueue) + this.messageQueue = []; + + for (var name in traceOptions) + this[name] = traceOptions[name]; +}; + +// ************************************************************************************************ +// FBTrace API + +this.sysout = function() +{ + return this.logFormatted(arguments, ""); +}; + +this.dumpProperties = function(title, object) +{ + return this.logFormatted("dumpProperties() not supported.", "warning"); +}; + +this.dumpStack = function() +{ + return this.logFormatted("dumpStack() not supported.", "warning"); +}; + +this.flush = function(module) +{ + this.module = module; + + var queue = this.messageQueue; + this.messageQueue = []; + + for (var i = 0; i < queue.length; ++i) + this.writeMessage(queue[i][0], queue[i][1], queue[i][2]); +}; + +this.getPanel = function() +{ + return this.module ? this.module.getPanel() : null; +}; + +//************************************************************************************************* + +this.logFormatted = function(objects, className) +{ + var html = this.DBG_TIMESTAMP ? [getTimestamp(), " | "] : []; + var length = objects.length; + + for (var i = 0; i < length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + + if (i == 0) + { + html.push(""); + appendText(object, html); + html.push(""); + } + else + appendText(object, html); + } + + return this.logRow(html, className); +}; + +this.logRow = function(message, className) +{ + var panel = this.getPanel(); + + if (panel && panel.panelNode) + this.writeMessage(message, className); + else + { + this.messageQueue.push([message, className]); + } + + return this.LOG_COMMAND; +}; + +this.writeMessage = function(message, className) +{ + var container = this.getPanel().containerNode; + var isScrolledToBottom = + container.scrollTop + container.offsetHeight >= container.scrollHeight; + + this.writeRow.call(this, message, className); + + if (isScrolledToBottom) + container.scrollTop = container.scrollHeight - container.offsetHeight; +}; + +this.appendRow = function(row) +{ + var container = this.getPanel().panelNode; + container.appendChild(row); +}; + +this.writeRow = function(message, className) +{ + var row = this.getPanel().panelNode.ownerDocument.createElement("div"); + row.className = "logRow" + (className ? " logRow-"+className : ""); + row.innerHTML = message.join(""); + this.appendRow(row); +}; + +//************************************************************************************************* + +function appendText(object, html) +{ + html.push(escapeHTML(objectToString(object))); +}; + +function getTimestamp() +{ + var now = new Date(); + var ms = "" + (now.getMilliseconds() / 1000).toFixed(3); + ms = ms.substr(2); + + return now.toLocaleTimeString() + "." + ms; +}; + +//************************************************************************************************* + +var HTMLtoEntity = +{ + "<": "<", + ">": ">", + "&": "&", + "'": "'", + '"': """ +}; + +function replaceChars(ch) +{ + return HTMLtoEntity[ch]; +}; + +function escapeHTML(value) +{ + return (value+"").replace(/[<>&"']/g, replaceChars); +}; + +//************************************************************************************************* + +function objectToString(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +}).apply(FBL.FBTrace); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// If application isn't in trace mode, the FBTrace panel won't be loaded +if (!Env.Options.enableTrace) return; + +// ************************************************************************************************ +// FBTrace Module + +Firebug.Trace = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Trace") : null; + }, + + clear: function() + { + this.getPanel().panelNode.innerHTML = ""; + } +}); + +Firebug.registerModule(Firebug.Trace); + + +// ************************************************************************************************ +// FBTrace Panel + +function TracePanel(){}; + +TracePanel.prototype = extend(Firebug.Panel, +{ + name: "Trace", + title: "Trace", + + options: { + hasToolButtons: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.clearButton = new Button({ + caption: "Clear", + title: "Clear FBTrace logs", + owner: Firebug.Trace, + onClick: Firebug.Trace.clear + }); + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + this.clearButton.initialize(); + } + +}); + +Firebug.registerPanel(TracePanel); + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; + +var parentPanelMap = {}; + + +var registerModule = Firebug.registerModule; +var registerPanel = Firebug.registerPanel; + +// ************************************************************************************************ +append(Firebug, +{ + extend: function(fn) + { + if (Firebug.chrome && Firebug.chrome.addPanel) + { + var namespace = ns(fn); + fn.call(namespace, FBL); + } + else + { + setTimeout(function(){Firebug.extend(fn);},100); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + registerModule.apply(Firebug, arguments); + + modules.push.apply(modules, arguments); + + dispatch(modules, "initialize", []); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + registerPanel.apply(Firebug, arguments); + + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + // TODO: xxxpedro investigate why Dev Panel throws an error + if (panelType.prototype.name == "Dev") continue; + + panelTypeMap[panelType.prototype.name] = arguments[i]; + + var parentPanelName = panelType.prototype.parentPanel; + if (parentPanelName) + { + parentPanelMap[parentPanelName] = 1; + } + else + { + var panelName = panelType.prototype.name; + var chrome = Firebug.chrome; + chrome.addPanel(panelName); + + // tab click handler + var onTabClick = function onTabClick() + { + chrome.selectPanel(panelName); + return false; + }; + + chrome.addController([chrome.panelMap[panelName].tabNode, "mousedown", onTabClick]); + } + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + } + +}); + + + + +// ************************************************************************************************ +}}); + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +FirebugChrome.Skin = +{ + CSS: '.collapsed{display:none;}[collapsed="true"]{display:none;}#fbCSS{padding:0 !important;}.cssPropDisable{float:left;display:block;width:2em;cursor:default;}.infoTip{z-index:2147483647;position:fixed;padding:2px 3px;border:1px solid #CBE087;background:LightYellow;font-family:Monaco,monospace;color:#000000;display:none;white-space:nowrap;pointer-events:none;}.infoTip[active="true"]{display:block;}.infoTipLoading{width:16px;height:16px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/loading_16.gif) no-repeat;}.infoTipImageBox{font-size:11px;min-width:100px;text-align:center;}.infoTipCaption{font-size:11px;font:Monaco,monospace;}.infoTipLoading > .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorBorders.png) repeat-y;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.png) no-repeat;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/disable.png) no-repeat 2px 1px;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/errorIcon.png) no-repeat !important;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;}#fbPanelBarBox{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/infoIcon.png) !important;background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/warningIcon.png) !important;background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/errorIcon.png) !important;background-image:url(chrome-extension://bmagokdooijbeehmkpknfglimnifench/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}', + HTML: '
       
       
      >>>
      2 errors' +}; + +// ************************************************************************************************ +}}); + +// ************************************************************************************************ +FBL.initialize(); +// ************************************************************************************************ + +})(); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug.jpg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug.jpg new file mode 100755 index 0000000..2a18aa0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug.jpg differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug128.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug128.png new file mode 100755 index 0000000..dbca545 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug128.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug16.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug16.png new file mode 100755 index 0000000..d8d0c24 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug16.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug24.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug24.png new file mode 100755 index 0000000..f50ff92 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug24.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug24_disabled.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug24_disabled.png new file mode 100755 index 0000000..16d4dcd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug24_disabled.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug32.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug32.png new file mode 100755 index 0000000..c02f4f5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug32.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug48.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug48.png new file mode 100755 index 0000000..b443132 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/firebug48.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/googleChrome.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/googleChrome.js new file mode 100755 index 0000000..26c8af3 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/googleChrome.js @@ -0,0 +1,106 @@ +/* See license.txt for terms of usage */ + +Firebug.extend(function(FBL) { with (FBL) { +// ************************************************************************************************ + +if (!Env.isChromeExtension) return; + +// ************************************************************************************************ +// local variables + +var channel; +var channelEvent; + +// ************************************************************************************************ +// GoogleChrome Module + +Firebug.GoogleChrome = extend(Firebug.Module, +{ + initialize: function() + { + var doc = FBL.Env.browser.document; + + if (!doc.getElementById("FirebugChannel")) + { + channel = doc.createElement("div"); + channel.id = "FirebugChannel"; + channel.firebugIgnore = true; + channel.style.display = "none"; + doc.documentElement.insertBefore(channel, doc.documentElement.firstChild); + + channelEvent = document.createEvent("Event"); + channelEvent.initEvent("FirebugChannelEvent", true, true); + + channel.addEventListener("FirebugChannelEvent", onFirebugChannelEvent); + } + }, + + dispatch: function(message) + { + channel.innerText = message; + channel.dispatchEvent(channelEvent); + } +}); + +// ************************************************************************************************ +// internals + +var onFirebugChannelEvent = function() +{ + var name = channel.innerText; + + if (name.indexOf("FB_contextMenuClick") == 0) + { + var doc = FBL.Env.browser.document; + var contextMenuElementXPath = name.split(",")[1]; + var contextMenuElement = getElementsByXPath(doc, contextMenuElementXPath)[0]; + + // If not open, open it first + Firebug.chrome.toggle(true); + + setTimeout(function(){ + + // Select the HTML panel + Firebug.chrome.selectPanel("HTML"); + + // Select the clicked element in the HTML tree + Firebug.HTML.select(contextMenuElement); + + },50); + } + else if (name == "FB_toggle") + { + Firebug.chrome.toggle(); + } + else if (name == "FB_openInNewWindow") + { + setTimeout(function(){ + Firebug.chrome.toggle(true, true); + },0); + } +}; + +var getElementsByXPath = function(doc, xpath) +{ + var nodes = []; + + try { + var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + for (var item = result.iterateNext(); item; item = result.iterateNext()) + nodes.push(item); + } + catch (exc) + { + // Invalid xpath expressions make their way here sometimes. If that happens, + // we still want to return an empty set without an exception. + } + + return nodes; +}; + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.GoogleChrome); + +// ************************************************************************************************ +}}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/license.txt b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/license.txt new file mode 100755 index 0000000..ba43b75 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/license.txt @@ -0,0 +1,30 @@ +Software License Agreement (BSD License) + +Copyright (c) 2007, Parakey Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Parakey Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Parakey Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/manifest.json b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/manifest.json new file mode 100755 index 0000000..4d624bb --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/manifest.json @@ -0,0 +1,34 @@ +{ + "name": "Firebug Lite for Google Chrome", + "version": "1.3.2.9760", + "description": "Firebug Lite for Google Chrome, supported by the Firebug Working Group.", + "background_page": "background.html", + "browser_action": + { + "default_icon": "firebug24_disabled.png", + "default_title": "Firebug Lite 1.3.2" + }, + "icons": + { + "128": "firebug128.png", + "16": "firebug16.png", + "32": "firebug32.png", + "48": "firebug48.png" + }, + "content_scripts": + [ + { + "matches": ["http://*/*", "https://*/*"], + "js": ["contentScript.js"], + "run_at": "document_start" + } + ], + "permissions": + [ + "tabs", + "http://*/*", + "https://*/*", + "http://127.0.0.1/*", + "http://localhost/*" + ] +} \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/blank.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/blank.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/blank.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/buttonBg.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/buttonBg.png new file mode 100755 index 0000000..f367b42 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/buttonBg.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/buttonBgHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/buttonBgHover.png new file mode 100755 index 0000000..cd37a0d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/buttonBgHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/detach.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/detach.png new file mode 100755 index 0000000..0ddb9a1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/detach.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/detachHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/detachHover.png new file mode 100755 index 0000000..e419272 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/detachHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disable.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disable.gif new file mode 100755 index 0000000..dd9eb0e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disable.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disable.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disable.png new file mode 100755 index 0000000..c28bcdf Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disable.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disableHover.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disableHover.gif new file mode 100755 index 0000000..70565a8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disableHover.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disableHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disableHover.png new file mode 100755 index 0000000..26fe375 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/disableHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/down.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/down.png new file mode 100755 index 0000000..acbbd30 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/down.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/downActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/downActive.png new file mode 100755 index 0000000..f4312b2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/downActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/downHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/downHover.png new file mode 100755 index 0000000..8144e63 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/downHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon-sm.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon-sm.png new file mode 100755 index 0000000..0c377e3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon-sm.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon.gif new file mode 100755 index 0000000..8ee8116 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon.png new file mode 100755 index 0000000..2d75261 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/errorIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug-1.3a2.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug-1.3a2.css new file mode 100755 index 0000000..b5dd5dd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug-1.3a2.css @@ -0,0 +1,817 @@ +.fbBtnPressed { + background: #ECEBE3; + padding: 3px 6px 2px 7px !important; + margin: 1px 0 0 1px; + _margin: 1px -1px 0 1px; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +.fbToolbarButtons { + display: none; +} + +#fbStatusBarBox { + display: none; +} + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +html, body { + margin: 0; + padding: 0; + overflow: hidden; +} + +body { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + position: fixed; + overflow: hidden; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; +} + +#fbTop { + height: 49px; +} + +#fbToolbar { + position: absolute; + z-index: 5; + width: 100%; + top: 0; + background: url(sprite.png) #f1f2ee 0 0; + height: 27px; + font-size: 11px; + overflow: hidden; +} + +#fbPanelBarBox { + top: 27px; + position: absolute; + z-index: 8; + width: 100%; + background: url(sprite.png) #dbd9c9 0 -27px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 4px 5px 0; +} + +#fbToolbarIcon a { + display: block; + height: 20px; + width: 20px; + background: url(sprite.png) 0 -135px; + text-decoration: none; + cursor: default; +} + +#fbToolbarButtons { + float: left; + padding: 4px 2px 0 5px; +} + +#fbToolbarButtons a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 8px 4px; + cursor: default; +} + +#fbToolbarButtons a:hover { + color: #333; + padding: 3px 7px 3px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +#fbStatusBarBox { + position: relative; + top: 5px; + line-height: 19px; + cursor: default; +} + +.fbToolbarSeparator{ + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 10px 6px 0 0; + float: left; +} + +.fbStatusBar span { + color: #808080; + padding: 0 4px 0 0; +} + +.fbStatusBar span a { + text-decoration: none; + color: black; +} + +.fbStatusBar span a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + _width: 50px; + padding: 5px 0 5px 5px; + z-index: 6; + background: url(sprite.png) #f1f2ee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 255px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 22px; + padding-left: 10px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 11px; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + padding-left: 6px; + background: #fff; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 7px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; +} + +div.fbFitHeight { + overflow: auto; + _position: absolute; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +#fbWindowButtons a { + font-size: 1px; + width: 16px; + height: 16px; + display: block; + float: right; + margin-right: 4px; + text-decoration: none; + cursor: default; +} + +#fbWindow_btClose { + background: url(sprite.png) 0 -119px; +} + +#fbWindow_btClose:hover { + background: url(sprite.png) -16px -119px; +} + +#fbWindow_btDetach { + background: url(sprite.png) -32px -119px; +} + +#fbWindow_btDetach:hover { + background: url(sprite.png) -48px -119px; +} + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + display: block; + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #f1f2ee 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #ece9d8; + color: #000; + border: 1px solid #716f64; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 9; + position: absolute; + height: 100%; + top: 27px; + _width: 6px; +} + +/************************************************************************************************/ +div.lineNo { + font: 11px Monaco, monospace; + float: left; + display: inline; + position: relative; + margin: 0; + padding: 0 5px 0 20px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +pre.nodeCode { + font: 11px Monaco, monospace; + margin: 0; + padding-left: 10px; + overflow: hidden; + /* + _width: 100%; + /**/ +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 11px; +} + +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; +} + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + white-space: pre; +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warning { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png); +} + +.logRow-warning { + background-color: cyan; + background-image: url(warningIcon.png); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +} + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.IE6.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.IE6.css new file mode 100755 index 0000000..14f8aa8 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.IE6.css @@ -0,0 +1,20 @@ +/************************************************************************************************/ +#fbToolbarSearch { + background-image: url(search.gif) !important; +} +/************************************************************************************************/ +.fbErrors { + background-image: url(errorIcon.gif) !important; +} +/************************************************************************************************/ +.logRow-info { + background-image: url(infoIcon.gif) !important; +} + +.logRow-warning { + background-image: url(warningIcon.gif) !important; +} + +.logRow-error { + background-image: url(errorIcon.gif) !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.css new file mode 100755 index 0000000..decd591 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.css @@ -0,0 +1,3056 @@ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Loose */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* +.netInfoResponseHeadersTitle, netInfoResponseHeadersBody { + display: none; +} +/**/ + +/* IE6 need a separated rule, otherwise it will not recognize it */ +.collapsed { + display: none; +} + +[collapsed="true"] { + display: none; +} + +#fbCSS { + padding: 0 !important; +} + +.cssPropDisable { + float: left; + display: block; + width: 2em; + cursor: default; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* panelBase */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/************************************************************************************************/ + +.infoTip { + z-index: 2147483647; + position: fixed; + padding: 2px 3px; + border: 1px solid #CBE087; + background: LightYellow; + font-family: Monaco, monospace; + color: #000000; + display: none; + white-space: nowrap; + pointer-events: none; +} + +.infoTip[active="true"] { + display: block; +} + +.infoTipLoading { + width: 16px; + height: 16px; + background: url(chrome://firebug/skin/loading_16.gif) no-repeat; +} + +.infoTipImageBox { + min-width: 100px; + text-align: center; +} + +.infoTipCaption { + font: message-box; +} + +.infoTipLoading > .infoTipImage, +.infoTipLoading > .infoTipCaption { + display: none; +} + +/************************************************************************************************/ + +h1.groupHeader { + padding: 2px 4px; + margin: 0 0 4px 0; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + background: #eee url(group.gif) repeat-x; + font-size: 11px; + font-weight: bold; + _position: relative; +} + +/************************************************************************************************/ + +.inlineEditor, +.fixedWidthEditor { + z-index: 2147483647; + position: absolute; + display: none; +} + +.inlineEditor { + margin-left: -6px; + margin-top: -3px; + /* + _margin-left: -7px; + _margin-top: -5px; + /**/ +} + +.textEditorInner, +.fixedWidthEditor { + margin: 0 0 0 0 !important; + padding: 0; + border: none !important; + font: inherit; + text-decoration: inherit; + background-color: #FFFFFF; +} + +.fixedWidthEditor { + border-top: 1px solid #888888 !important; + border-bottom: 1px solid #888888 !important; +} + +.textEditorInner { + position: relative; + top: -7px; + left: -5px; + + outline: none; + resize: none; + + /* + _border: 1px solid #999 !important; + _padding: 1px !important; + _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040"); + /**/ +} + +.textEditorInner1 { + padding-left: 11px; + background: url(textEditorBorders.png) repeat-y; + _background: url(textEditorBorders.gif) repeat-y; + _overflow: hidden; +} + +.textEditorInner2 { + position: relative; + padding-right: 2px; + background: url(textEditorBorders.png) repeat-y 100% 0; + _background: url(textEditorBorders.gif) repeat-y 100% 0; + _position: fixed; +} + +.textEditorTop1 { + background: url(textEditorCorners.png) no-repeat 100% 0; + margin-left: 11px; + height: 10px; + _background: url(textEditorCorners.gif) no-repeat 100% 0; + _overflow: hidden; +} + +.textEditorTop2 { + position: relative; + left: -11px; + width: 11px; + height: 10px; + background: url(textEditorCorners.png) no-repeat; + _background: url(textEditorCorners.gif) no-repeat; +} + +.textEditorBottom1 { + position: relative; + background: url(textEditorCorners.png) no-repeat 100% 100%; + margin-left: 11px; + height: 12px; + _background: url(textEditorCorners.gif) no-repeat 100% 100%; +} + +.textEditorBottom2 { + position: relative; + left: -11px; + width: 11px; + height: 12px; + background: url(textEditorCorners.png) no-repeat 0 100%; + _background: url(textEditorCorners.gif) no-repeat 0 100%; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* CSS */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-css { + overflow-x: hidden; +} + +.cssSheet > .insertBefore { + height: 1.5em; +} + +.cssRule { + position: relative; + margin: 0; + padding: 1em 0 0 6px; + font-family: Monaco, monospace; + color: #000000; +} + +.cssRule:first-child { + padding-top: 6px; +} + +.cssElementRuleContainer { + position: relative; +} + +.cssHead { + padding-right: 150px; +} + +.cssProp { + /*padding-left: 2em;*/ +} + +.cssPropName { + color: DarkGreen; +} + +.cssPropValue { + margin-left: 8px; + color: DarkBlue; +} + +.cssOverridden span { + text-decoration: line-through; +} + +.cssInheritedRule { +} + +.cssInheritLabel { + margin-right: 0.5em; + font-weight: bold; +} + +.cssRule .objectLink-sourceLink { + top: 0; +} + +.cssProp.editGroup:hover { + background: url(disable.png) no-repeat 2px 1px; + _background: url(disable.gif) no-repeat 2px 1px; +} + +.cssProp.editGroup.editing { + background: none; +} + +.cssProp.disabledStyle { + background: url(disableHover.png) no-repeat 2px 1px; + _background: url(disableHover.gif) no-repeat 2px 1px; + opacity: 1; + color: #CCCCCC; +} + +.disabledStyle .cssPropName, +.disabledStyle .cssPropValue { + color: #CCCCCC; +} + +.cssPropValue.editing + .cssSemi, +.inlineExpander + .cssSemi { + display: none; +} + +.cssPropValue.editing { + white-space: nowrap; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.stylePropName { + font-weight: bold; + padding: 0 4px 4px 4px; + width: 50%; +} + +.stylePropValue { + width: 50%; +} +/* +.useA11y .a11yCSSView .focusRow:focus { + outline: none; + background-color: transparent + } + + .useA11y .a11yCSSView .focusRow:focus .cssSelector, + .useA11y .a11yCSSView .focusRow:focus .cssPropName, + .useA11y .a11yCSSView .focusRow:focus .cssPropValue, + .useA11y .a11yCSSView .computedStyleRow:focus, + .useA11y .a11yCSSView .groupHeader:focus { + outline: 2px solid #FF9933; + outline-offset: -2px; + background-color: #FFFFD6; + } + + .useA11y .a11yCSSView .groupHeader:focus { + outline-offset: -2px; + } +/**/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Net */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-net { + overflow-x: hidden; +} + +.netTable { + width: 100%; +} + +/************************************************************************************************/ + +.hideCategory-undefined .category-undefined, +.hideCategory-html .category-html, +.hideCategory-css .category-css, +.hideCategory-js .category-js, +.hideCategory-image .category-image, +.hideCategory-xhr .category-xhr, +.hideCategory-flash .category-flash, +.hideCategory-txt .category-txt, +.hideCategory-bin .category-bin { + display: none; +} + +/************************************************************************************************/ + +.netHeadRow { + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netHeadCol { + border-bottom: 1px solid #CCCCCC; + padding: 2px 4px 2px 18px; + font-weight: bold; +} + +.netHeadLabel { + white-space: nowrap; + overflow: hidden; +} + +/************************************************************************************************/ +/* Header for Net panel table */ + +.netHeaderRow { + height: 16px; +} + +.netHeaderCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x; + white-space: nowrap; +} + +.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox { + padding: 2px 14px 2px 18px; +} + +.netHeaderCellBox { + padding: 2px 14px 2px 10px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.netHeaderCell:hover:active { + background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x; +} + +.netHeaderSorted { + background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x; +} + +.netHeaderSorted > .netHeaderCellBox { + border-right-color: #6B7C93; + background: url(chrome://firebug/skin/arrowDown.png) no-repeat right; +} + +.netHeaderSorted.sortedAscending > .netHeaderCellBox { + background-image: url(chrome://firebug/skin/arrowUp.png); +} + +.netHeaderSorted:hover:active { + background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x; +} + +/************************************************************************************************/ +/* Breakpoints */ + +.panelNode-net .netRowHeader { + display: block; +} + +.netRowHeader { + cursor: pointer; + display: none; + height: 15px; + margin-right: 0 !important; +} + +/* Display brekpoint disc */ +.netRow .netRowHeader { + background-position: 5px 1px; +} + +.netRow[breakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpoint.png); +} + +.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpointDisabled.png); +} + +.netRow.category-xhr:hover .netRowHeader { + background-color: #F6F6F6; +} + +#netBreakpointBar { + max-width: 38px; +} + +#netHrefCol > .netHeaderCellBox { + border-left: 0px; +} + +.netRow .netRowHeader { + width: 3px; +} + +.netInfoRow .netRowHeader { + display: table-cell; +} + +/************************************************************************************************/ +/* Column visibility */ + +.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"], +.netTable[hiddenCols~=netHrefCol] TD.netHrefCol, +.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"], +.netTable[hiddenCols~=netStatusCol] TD.netStatusCol, +.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"], +.netTable[hiddenCols~=netDomainCol] TD.netDomainCol, +.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"], +.netTable[hiddenCols~=netSizeCol] TD.netSizeCol, +.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"], +.netTable[hiddenCols~=netTimeCol] TD.netTimeCol { + display: none; +} + +/************************************************************************************************/ + +.netRow { + background: LightYellow; +} + +.netRow.loaded { + background: #FFFFFF; +} + +.netRow.loaded:hover { + background: #EFEFEF; +} + +.netCol { + padding: 0; + vertical-align: top; + border-bottom: 1px solid #EFEFEF; + white-space: nowrap; + height: 17px; +} + +.netLabel { + width: 100%; +} + +.netStatusCol { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.responseError > .netStatusCol { + color: red; +} + +.netDomainCol { + padding-left: 5px; +} + +.netSizeCol { + text-align: right; + padding-right: 10px; +} + +.netHrefLabel { + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 10; + position: absolute; + padding-left: 18px; + padding-top: 1px; + max-width: 15%; + font-weight: bold; +} + +.netFullHrefLabel { + display: none; + -moz-user-select: none; + padding-right: 10px; + padding-bottom: 3px; + max-width: 100%; + background: #FFFFFF; + z-index: 200; +} + +.netHrefCol:hover > .netFullHrefLabel { + display: block; +} + +.netRow.loaded:hover .netCol > .netFullHrefLabel { + background-color: #EFEFEF; +} + +.useA11y .a11yShowFullLabel { + display: block; + background-image: none !important; + border: 1px solid #CBE087; + background-color: LightYellow; + font-family: Monaco, monospace; + color: #000000; + font-size: 10px; + z-index: 2147483647; +} + +.netSizeLabel { + padding-left: 6px; +} + +.netStatusLabel, +.netDomainLabel, +.netSizeLabel, +.netBar { + padding: 1px 0 2px 0 !important; +} + +.responseError { + color: red; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.hasHeaders .netHrefLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/************************************************************************************************/ + +.netLoadingIcon { + position: absolute; + border: 0; + margin-left: 14px; + width: 16px; + height: 16px; + background: transparent no-repeat 0 0; + background-image: url(chrome://firebug/skin/loading_16.gif); + display:inline-block; +} + +.loaded .netLoadingIcon { + display: none; +} + +/************************************************************************************************/ + +.netBar, .netSummaryBar { + position: relative; + border-right: 50px solid transparent; +} + +.netResolvingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x; + z-index:60; +} + +.netConnectingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x; + z-index:50; +} + +.netBlockingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x; + z-index:40; +} + +.netSendingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x; + z-index:30; +} + +.netWaitingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x; + z-index:20; + min-width: 1px; +} + +.netReceivingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x; + z-index:10; +} + +.netWindowLoadBar, +.netContentLoadBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 1px; + background-color: red; + z-index: 70; + opacity: 0.5; + display: none; + margin-bottom:-1px; +} + +.netContentLoadBar { + background-color: Blue; +} + +.netTimeLabel { + -moz-box-sizing: padding-box; + position: absolute; + top: 1px; + left: 100%; + padding-left: 6px; + color: #444444; + min-width: 16px; +} + +/* + * Timing info tip is reusing net timeline styles to display the same + * colors for individual request phases. Notice that the info tip must + * respect also loaded and fromCache styles that also modify the + * actual color. These are used both on the same element in case + * of the tooltip. + */ +.loaded .netReceivingBar, +.loaded.netReceivingBar { + background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x; + border-color: #B6B6B6; +} + +.fromCache .netReceivingBar, +.fromCache.netReceivingBar { + background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x; + border-color: #D6D6D6; +} + +.netSummaryRow .netTimeLabel, +.loaded .netTimeLabel { + background: transparent; +} + +/************************************************************************************************/ +/* Time Info tip */ + +.timeInfoTip { + width: 150px; + height: 40px +} + +.timeInfoTipBar, +.timeInfoTipEventBar { + position: relative; + display: block; + margin: 0; + opacity: 1; + height: 15px; + width: 4px; +} + +.timeInfoTipEventBar { + width: 1px !important; +} + +.timeInfoTipCell.startTime { + padding-right: 8px; +} + +.timeInfoTipCell.elapsedTime { + text-align: right; + padding-right: 8px; +} + +/************************************************************************************************/ +/* Size Info tip */ + +.sizeInfoLabelCol { + font-weight: bold; + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; +} + +.sizeInfoSizeCol { + font-weight: bold; +} + +.sizeInfoDetailCol { + color: gray; + text-align: right; +} + +.sizeInfoDescCol { + font-style: italic; +} + +/************************************************************************************************/ +/* Summary */ + +.netSummaryRow .netReceivingBar { + background: #BBBBBB; + border: none; +} + +.netSummaryLabel { + color: #222222; +} + +.netSummaryRow { + background: #BBBBBB !important; + font-weight: bold; +} + +.netSummaryRow .netBar { + border-right-color: #BBBBBB; +} + +.netSummaryRow > .netCol { + border-top: 1px solid #999999; + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 1px; + padding-bottom: 2px; +} + +.netSummaryRow > .netHrefCol:hover { + background: transparent !important; +} + +.netCountLabel { + padding-left: 18px; +} + +.netTotalSizeCol { + text-align: right; + padding-right: 10px; +} + +.netTotalTimeCol { + text-align: right; +} + +.netCacheSizeLabel { + position: absolute; + z-index: 1000; + left: 0; + top: 0; +} + +/************************************************************************************************/ + +.netLimitRow { + background: rgb(255, 255, 225) !important; + font-weight:normal; + color: black; + font-weight:normal; +} + +.netLimitLabel { + padding-left: 18px; +} + +.netLimitRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + vertical-align: middle !important; + padding-top: 2px; + padding-bottom: 2px; +} + +.netLimitButton { + font-size: 11px; + padding-top: 1px; + padding-bottom: 1px; +} + +/************************************************************************************************/ + +.netInfoCol { + border-top: 1px solid #EEEEEE; + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netInfoBody { + margin: 10px 0 4px 10px; +} + +.netInfoTabs { + position: relative; + padding-left: 17px; +} + +.netInfoTab { + position: relative; + top: -3px; + margin-top: 10px; + padding: 4px 6px; + border: 1px solid transparent; + border-bottom: none; + _border: none; + font-weight: bold; + color: #565656; + cursor: pointer; +} + +/*.netInfoTab:hover { + cursor: pointer; +}*/ + +/* replaced by .netInfoTabSelected for IE6 support +.netInfoTab[selected="true"] { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} +/**/ +.netInfoTabSelected { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} + +.logRow-netInfo.error .netInfoTitle { + color: red; +} + +.logRow-netInfo.loading .netInfoResponseText { + font-style: italic; + color: #888888; +} + +.loading .netInfoResponseHeadersTitle { + display: none; +} + +.netInfoResponseSizeLimit { + font-family: Lucida Grande, Tahoma, sans-serif; + padding-top: 10px; + font-size: 11px; +} + +.netInfoText { + display: none; + margin: 0; + border: 1px solid #D7D7D7; + border-right: none; + padding: 8px; + background-color: #FFFFFF; + font-family: Monaco, monospace; + /* white-space: pre; */ + /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */ +} + +/* replaced by .netInfoTextSelected for IE6 support +.netInfoText[selected="true"] { + display: block; +} +/**/ +.netInfoTextSelected { + display: block; +} + +.netInfoParamName { + padding: 0 10px 0 0; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + vertical-align: top; + text-align: right; + white-space: nowrap; +} + +.netInfoParamValue { + width: 100%; +} + +.netInfoHeadersText, +.netInfoPostText, +.netInfoPutText { + padding-top: 0; +} + +.netInfoHeadersGroup, +.netInfoPostParams, +.netInfoPostSource { + margin-bottom: 4px; + border-bottom: 1px solid #D7D7D7; + padding-top: 8px; + padding-bottom: 2px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #565656; +} + +.netInfoPostParamsTable, +.netInfoPostPartsTable, +.netInfoPostJSONTable, +.netInfoPostXMLTable, +.netInfoPostSourceTable { + margin-bottom: 10px; + width: 100%; +} + +.netInfoPostContentType { + color: #bdbdbd; + padding-left: 50px; + font-weight: normal; +} + +.netInfoHtmlPreview { + border: 0; + width: 100%; + height:100%; +} + +/************************************************************************************************/ +/* Request & Response Headers */ + +.netHeadersViewSource { + color: #bdbdbd; + margin-left: 200px; + font-weight: normal; +} + +.netHeadersViewSource:hover { + color: blue; + cursor: pointer; +} + +/************************************************************************************************/ + +.netActivationRow, +.netPageSeparatorRow { + background: rgb(229, 229, 229) !important; + font-weight: normal; + color: black; +} + +.netActivationLabel { + background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px; + padding-left: 22px; +} + +/************************************************************************************************/ + +.netPageSeparatorRow { + height: 5px !important; +} + +.netPageSeparatorLabel { + padding-left: 22px; + height: 5px !important; +} + +.netPageRow { + background-color: rgb(255, 255, 255); +} + +.netPageRow:hover { + background: #EFEFEF; +} + +.netPageLabel { + padding: 1px 0 2px 18px !important; + font-weight: bold; +} + +/************************************************************************************************/ + +.netActivationRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 2px; + padding-bottom: 3px; +} +/* +.useA11y .panelNode-net .a11yFocus:focus, +.useA11y .panelNode-net .focusRow:focus { + outline-offset: -2px; + background-color: #FFFFD6 !important; +} + +.useA11y .panelNode-net .netHeaderCell:focus, +.useA11y .panelNode-net :focus .netHeaderCell, +.useA11y .panelNode-net :focus .netReceivingBar, +.useA11y .netSummaryRow :focus .netBar, +.useA11y .netSummaryRow:focus .netBar { + background-color: #FFFFD6; + background-image: none; + border-color: #FFFFD6; +} +/**/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Windows */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/************************************************************************************************/ +/* Twisties */ + +/* IE6 has problems with > operator, and multiple classes */ +/*.twisty, +.logRow-errorMessage > .hasTwisty > .errorTitle, + /* avoid rule not being parsed IE6 */ +.logRow-spy .spyHead .spyTitle, +.logGroup .logGroupLabel, +.hasChildren .memberLabelCell .memberLabel, +.hasHeaders .netHrefLabel { + background-image: url(tree_open.gif); + background-repeat: no-repeat; + background-position: 2px 2px; +} +/* +.logRow-errorMessage > .hasTwisty.opened > .errorTitle, +/* avoid rule not being parsed IE6 */ +.opened .spyHead .spyTitle, +.opened .logGroupLabel, +.opened .memberLabelCell .memberLabel/*, +.nodeBox.highlightOpen > .nodeLabel > .twisty, +.nodeBox.open > .nodeLabel > .twisty, +.netRow.opened > .netCol > .netHrefLabel /* avoid rule not being parsed IE6 */ { + background-image: url(tree_close.gif); +} + +.twisty { + background-position: 2px 0; +} + + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Console */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-console { + overflow-x: hidden; +} + +.objectLink { + text-decoration: none; +} + +.objectLink:hover { + cursor: pointer; + text-decoration: underline; +} + +.logRow { + position: relative; + margin: 0; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; + overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */ +} + +.useA11y .logRow:focus { + border-bottom: 1px solid #000000 !important; + outline: none !important; + background-color: #FFFFAD !important; +} + +.useA11y .logRow:focus a.objectLink-sourceLink { + background-color: #FFFFAD; +} + +.useA11y .a11yFocus:focus, .useA11y .objectBox:focus { + outline: 2px solid #FF9933; + background-color: #FFFFAD; +} + +.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{ + background-color: #888888 !important; +} + +.useA11y .logGroup.opened > .logRow { + border-bottom: 1px solid #ffffff; +} + +.logGroup { + background: url(group.gif) repeat-x #FFFFFF; + padding: 0 !important; + border: none !important; +} + +.logGroupBody { + display: none; + margin-left: 16px; + border-left: 1px solid #D7D7D7; + border-top: 1px solid #D7D7D7; + background: #FFFFFF; +} + +.logGroup > .logRow { + background-color: transparent !important; + font-weight: bold; +} + +.logGroup.opened > .logRow { + border-bottom: none; +} + +.logGroup.opened > .logGroupBody { + display: block; +} + +/*****************************************************************************************/ + +.logRow-command > .objectBox-text { + font-family: Monaco, monospace; + color: #0000FF; + white-space: pre-wrap; +} + +.logRow-info, +.logRow-warn, +.logRow-error, +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-left: 22px; + background-repeat: no-repeat; + background-position: 4px 2px; +} + +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-top: 0; + padding-bottom: 0; +} + +.logRow-info, +.logRow-info .objectLink-sourceLink { + background-color: #FFFFFF; +} + +.logRow-warn, +.logRow-warningMessage, +.logRow-warn .objectLink-sourceLink, +.logRow-warningMessage .objectLink-sourceLink { + background-color: cyan; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage, +.logRow-error .objectLink-sourceLink, +.logRow-errorMessage .objectLink-sourceLink { + background-color: LightYellow; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + color: #FF0000; +} + +.logRow-info { + /*background-image: url(chrome://firebug/skin/infoIcon.png);*/ +} + +.logRow-warn, +.logRow-warningMessage { + /*background-image: url(chrome://firebug/skin/warningIcon.png);*/ +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + /*background-image: url(chrome://firebug/skin/errorIcon.png);*/ +} + +/*****************************************************************************************/ + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-string, +.objectBox-text, +.objectLink-textNode { + white-space: pre-wrap; +} + +.objectBox-number, +.objectLink-styleRule, +.objectLink-element, +.objectLink-textNode { + color: #000088; +} + +.objectBox-string { + color: #FF0000; +} + +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + color: DarkGreen; +} + +.objectBox-null, +.objectBox-undefined { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-exception { + padding: 0 2px 0 18px; + /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/ + color: red; +} + +.objectLink-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ + +.errorTitle { + margin-top: 0px; + margin-bottom: 1px; + padding-top: 2px; + padding-bottom: 2px; +} + +.errorTrace { + margin-left: 17px; +} + +.errorSourceBox { + margin: 2px 0; +} + +.errorSource-none { + display: none; +} + +.errorSource-syntax > .errorBreak { + visibility: hidden; +} + +.errorSource { + cursor: pointer; + font-family: Monaco, monospace; + color: DarkGreen; +} + +.errorSource:hover { + text-decoration: underline; +} + +.errorBreak { + cursor: pointer; + display: none; + margin: 0 6px 0 0; + width: 13px; + height: 14px; + vertical-align: bottom; + /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/ + opacity: 0.1; +} + +.hasBreakSwitch .errorBreak { + display: inline; +} + +.breakForError .errorBreak { + opacity: 1; +} + +.assertDescription { + margin: 0; +} + +/************************************************************************************************/ + +.logRow-profile > .logRow > .objectBox-text { + font-family: Lucida Grande, Tahoma, sans-serif; + color: #000000; +} + +.logRow-profile > .logRow > .objectBox-text:last-child { + color: #555555; + font-style: italic; +} + +.logRow-profile.opened > .logRow { + padding-bottom: 4px; +} + +.profilerRunning > .logRow { + /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/ + padding-left: 22px !important; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.profileSizer { + width:100%; + overflow-x:auto; + overflow-y: scroll; +} + +.profileTable { + border-bottom: 1px solid #D7D7D7; + padding: 0 0 4px 0; +} + +.profileTable tr[odd="1"] { + background-color: #F5F5F5; + vertical-align:middle; +} + +.profileTable a { + vertical-align:middle; +} + +.profileTable td { + padding: 1px 4px 0 4px; +} + +.headerCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/ +} + +.headerCellBox { + padding: 2px 4px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.headerCell:hover:active { + /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/ +} + +.headerSorted { + /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/ +} + +.headerSorted > .headerCellBox { + border-right-color: #6B7C93; + /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/ +} + +.headerSorted.sortedAscending > .headerCellBox { + /*background-image: url(chrome://firebug/skin/arrowUp.png);*/ +} + +.headerSorted:hover:active { + /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/ +} + +.linkCell { + text-align: right; +} + +.linkCell > .objectLink-sourceLink { + position: static; +} + +/*****************************************************************************************/ + +.logRow-stackTrace { + padding-top: 0; +} + +.logRow-stackTrace > .objectBox-stackFrame { + position: relative; + padding-top: 2px; +} + +/************************************************************************************************/ + +.objectLink-object { + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: DarkGreen; + white-space: pre-wrap; +} + +.objectPropValue { + font-weight: normal; + font-style: italic; + color: #555555; +} + +/************************************************************************************************/ + +.selectorTag, +.selectorId, +.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +.selectorHidden > .selectorTag { + color: #5F82D9; +} + +.selectorHidden > .selectorId { + color: #888888; +} + +.selectorHidden > .selectorClass { + color: #D86060; +} + +.selectorValue { + font-family: Lucida Grande, sans-serif; + font-style: italic; + color: #555555; +} + +/*****************************************************************************************/ + +.panelNode.searching .logRow { + display: none; +} + +.logRow.matched { + display: block !important; +} + +.logRow.matching { + position: absolute; + left: -1000px; + top: -1000px; + max-width: 0; + max-height: 0; + overflow: hidden; +} + +/*****************************************************************************************/ + +.arrayLeftBracket, +.arrayRightBracket, +.arrayComma { + font-family: Monaco, monospace; +} + +.arrayLeftBracket, +.arrayRightBracket { + font-weight: bold; +} + +.arrayLeftBracket { + margin-right: 4px; +} + +.arrayRightBracket { + margin-left: 4px; +} + +/*****************************************************************************************/ + +.logRow-dir { + padding: 0; +} + +/************************************************************************************************/ + +/* +.logRow-errorMessage > .hasTwisty > .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup > .logRow +*/ +.logRow-errorMessage .hasTwisty .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup .logRow { + cursor: pointer; + padding-left: 18px; + background-repeat: no-repeat; + background-position: 3px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle { + background-position: 2px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle:hover, +.logRow-spy .spyHead .spyTitle:hover, +.logGroup > .logRow:hover { + text-decoration: underline; +} + +/*****************************************************************************************/ + +.logRow-spy { + padding: 0 !important; +} + +.logRow-spy, +.logRow-spy .objectLink-sourceLink { + background: url(group.gif) repeat-x #FFFFFF; + padding-right: 4px; + right: 0; +} + +.logRow-spy.opened { + padding-bottom: 4px; + border-bottom: none; +} + +.spyTitle { + color: #000000; + font-weight: bold; + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 100; + padding-left: 18px; +} + +.spyCol { + padding: 0; + white-space: nowrap; + height: 16px; +} + +.spyTitleCol:hover > .objectLink-sourceLink, +.spyTitleCol:hover > .spyTime, +.spyTitleCol:hover > .spyStatus, +.spyTitleCol:hover > .spyTitle { + display: none; +} + +.spyFullTitle { + display: none; + -moz-user-select: none; + max-width: 100%; + background-color: Transparent; +} + +.spyTitleCol:hover > .spyFullTitle { + display: block; +} + +.spyStatus { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.spyTime { + margin-left:4px; + margin-right:4px; + color: rgb(128, 128, 128); +} + +.spyIcon { + margin-right: 4px; + margin-left: 4px; + width: 16px; + height: 16px; + vertical-align: middle; + background: transparent no-repeat 0 0; + display: none; +} + +.loading .spyHead .spyRow .spyIcon { + background-image: url(loading_16.gif); + display: block; +} + +.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon { + width: 0; + margin: 0; +} + +.logRow-spy.error .spyHead .spyRow .spyIcon { + background-image: url(errorIcon-sm.png); + display: block; + background-position: 2px 2px; +} + +.logRow-spy .spyHead .netInfoBody { + display: none; +} + +.logRow-spy.opened .spyHead .netInfoBody { + margin-top: 10px; + display: block; +} + +.logRow-spy.error .spyTitle, +.logRow-spy.error .spyStatus, +.logRow-spy.error .spyTime { + color: red; +} + +.logRow-spy.loading .spyResponseText { + font-style: italic; + color: #888888; +} + +/************************************************************************************************/ + +.caption { + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #444444; +} + +.warning { + padding: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #888888; +} + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* DOM */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-dom { + overflow-x: hidden !important; +} + +.domTable { + font-size: 1em; + width: 100%; + table-layout: fixed; + background: #fff; +} + +.domTableIE { + width: auto; +} + +.memberLabelCell { + padding: 2px 0 2px 0; + vertical-align: top; +} + +.memberValueCell { + padding: 1px 0 1px 5px; + display: block; + overflow: hidden; +} + +.memberLabel { + display: block; + cursor: default; + -moz-user-select: none; + overflow: hidden; + /*position: absolute;*/ + padding-left: 18px; + /*max-width: 30%;*/ + /*white-space: nowrap;*/ + background-color: #FFFFFF; + text-decoration: none; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.memberRow.hasChildren .memberLabelCell .memberLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.userLabel { + color: #000000; + font-weight: bold; +} + +.userClassLabel { + color: #E90000; + font-weight: bold; +} + +.userFunctionLabel { + color: #025E2A; + font-weight: bold; +} + +.domLabel { + color: #000000; +} + +.domFunctionLabel { + color: #025E2A; +} + +.ordinalLabel { + color: SlateBlue; + font-weight: bold; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +.scopesRow { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 5px solid #BEBEBE; + color: #666666; +} +.scopesLabel { + background-color: LightYellow; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchEditCell { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 1px solid #BEBEBE; + color: #666666; +} + +.editor-watchNewRow, +.editor-memberRow { + font-family: Monaco, monospace !important; +} + +.editor-memberRow { + padding: 1px 0 !important; +} + +.editor-watchRow { + padding-bottom: 0 !important; +} + +.watchRow > .memberLabelCell { + font-family: Monaco, monospace; + padding-top: 1px; + padding-bottom: 1px; +} + +.watchRow > .memberLabelCell > .memberLabel { + background-color: transparent; +} + +.watchRow > .memberValueCell { + padding-top: 2px; + padding-bottom: 2px; +} + +.watchRow > .memberLabelCell, +.watchRow > .memberValueCell { + background-color: #F5F5F5; + border-bottom: 1px solid #BEBEBE; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchToolbox { + z-index: 2147483647; + position: absolute; + right: 0; + padding: 1px 2px; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* FROM ORIGINAL FIREBUG */ + + + + +/************************************************************************************************ + CSS Not organized +*************************************************************************************************/ +#fbConsole { + overflow-x: hidden !important; +} + +#fbCSS { + font: 1em Monaco, monospace; + padding: 0 7px; +} + +#fbstylesheetButtons select, #fbScriptButtons select { + font: 11px Lucida Grande, Tahoma, sans-serif; + margin-top: 1px; + padding-left: 3px; + background: #fafafa; + border: 1px inset #fff; + width: 220px; + outline: none; +} + +.Selector { margin-top:10px } +.CSSItem {margin-left: 4% } +.CSSText { padding-left:20px; } +.CSSProperty { color:#005500; } +.CSSValue { padding-left:5px; color:#000088; } + + +/************************************************************************************************ + Not organized +*************************************************************************************************/ + +#fbHTMLStatusBar { + display: inline; +} + +.fbToolbarButtons { + display: none; +} + +.fbStatusSeparator{ + display: block; + float: left; + padding-top: 4px; +} + +#fbStatusBarBox { + display: none; +} + +#fbToolbarContent { + display: block; + position: absolute; + _position: absolute; + top: 0; + padding-top: 4px; + height: 23px; + clip: rect(0, 2048px, 27px, 0); +} + +.fbTabMenuTarget { + display: none !important; + float: left; + width: 10px; + height: 10px; + margin-top: 6px; + background: url(tabMenuTarget.png); +} + +.fbTabMenuTarget:hover { + background: url(tabMenuTargetHover.png); +} + +.fbShadow { + float: left; + background: url(shadowAlpha.png) no-repeat bottom right !important; + background: url(shadow2.gif) no-repeat bottom right; + margin: 10px 0 0 10px !important; + margin: 10px 0 0 5px; +} + +.fbShadowContent { + display: block; + position: relative; + background-color: #fff; + border: 1px solid #a9a9a9; + top: -6px; + left: -6px; +} + +.fbMenu { + display: none; + position: absolute; + font-size: 11px; + z-index: 2147483647; +} + +.fbMenuContent { + padding: 2px; +} + +.fbMenuSeparator { + display: block; + position: relative; + padding: 1px 18px 0; + text-decoration: none; + color: #000; + cursor: default; + background: #ACA899; + margin: 4px 0; +} + +.fbMenuOption +{ + display: block; + position: relative; + padding: 2px 18px; + text-decoration: none; + color: #000; + cursor: default; +} + +.fbMenuOption:hover +{ + color: #fff; + background: #316AC5; +} + +.fbMenuGroup { + background: transparent url(tabMenuPin.png) no-repeat right 0; +} + +.fbMenuGroup:hover { + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuGroupSelected { + color: #fff; + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuChecked { + background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0; +} + +.fbMenuChecked:hover { + background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px; +} + +.fbMenuRadioSelected { + background: transparent url(tabMenuRadio.png) no-repeat 4px 0; +} + +.fbMenuRadioSelected:hover { + background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px; +} + +.fbMenuShortcut { + padding-right: 85px; +} + +.fbMenuShortcutKey { + position: absolute; + right: 0; + top: 2px; + width: 77px; +} + +#fbFirebugMenu { + top: 22px; + left: 0; +} + +.fbMenuDisabled { + color: #ACA899 !important; +} + +#fbFirebugSettingsMenu { + left: 245px; + top: 99px; +} + +#fbConsoleMenu { + top: 42px; + left: 48px; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; + float: left; + height: 20px; + width: 20px; + color: #000; + margin-right: 2px; + text-decoration: none; + cursor: default; +} + +.fbIconButton:hover { + position: relative; + top: -1px; + left: -1px; + margin-right: 0; + _margin-right: 1px; + color: #333; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbIconPressed { + position: relative; + margin-right: 0; + _margin-right: 1px; + top: 0 !important; + left: 0 !important; + height: 19px; + color: #333 !important; + border: 1px solid #bbb !important; + border-bottom: 1px solid #cfcfcf !important; + border-right: 1px solid #ddd !important; +} + + + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +.fbBody { + margin: 0; + padding: 0; + overflow: hidden; + + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px !important; + background: #fff url(search.gif) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat !important; + background: url(errorIcon.gif) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + position: absolute; + _position: static; + top: 0; + left: 0; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; + overflow: hidden; +} + +#fbTop { + height: 49px; +} + +#fbToolbar { + background: url(sprite.png) #f1f2ee 0 0; + height: 27px; + font-size: 11px; +} + +#fbPanelBarBox { + background: url(sprite.png) #dbd9c9 0 -27px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 0 5px 0; +} + +#fbToolbarIcon a { + background: url(sprite.png) 0 -135px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} +/* +#fbStatusBarBox a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 5px; + margin: 0 0 0 1px; + cursor: default; +} + +#fbStatusBarBox a:hover { + color: #333; + padding: 3px 4px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} +/**/ + +.fbButton { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 6px 4px 7px; + cursor: default; +} + +.fbButton:hover { + color: #333; + background: #f5f5ef url(buttonBg.png); + padding: 3px 5px 3px 6px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbBtnPressed { + background: #e3e3db url(buttonBgHover.png) !important; + padding: 3px 4px 2px 6px !important; + margin: 1px 0 0 1px !important; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +#fbStatusBarBox { + top: 4px; + cursor: default; +} + +.fbToolbarSeparator { + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 6px 3px; + float: left; +} + +.fbBtnSelected { + font-weight: bold; +} + +.fbStatusBar { + color: #aca899; +} + +.fbStatusBar a { + text-decoration: none; + color: black; +} + +.fbStatusBar a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + width: 48px; + padding: 5px; + z-index: 6; + background: url(sprite.png) #f1f2ee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 1024px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 22px; + padding-left: 4px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 1em; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + margin-left: 6px; + background: #fff; +} + +#fbLargeCommandLine { + display: none; + position: absolute; + z-index: 9; + top: 27px; + right: 0; + width: 294px; + height: 201px; + border-width: 0; + margin: 0; + padding: 2px 0 0 2px; + resize: none; + outline: none; + font-size: 11px; + overflow: auto; + border-top: 1px solid #B9B7AF; + _right: -1px; + _border-left: 1px solid #fff; +} + +#fbLargeCommandButtons { + display: none; + background: #ECE9D8; + bottom: 0; + right: 0; + width: 294px; + height: 21px; + padding-top: 1px; + position: fixed; + border-top: 1px solid #ACA899; + z-index: 9; +} + +#fbSmallCommandLineIcon { + background: url(down.png) no-repeat; + position: absolute; + right: 2px; + bottom: 3px; + + z-index: 99; +} + +#fbSmallCommandLineIcon:hover { + background: url(downHover.png) no-repeat; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: fixed; + _position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 6px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; + outline: none; +} + +#fbLargeCommandLineIcon { + background: url(up.png) no-repeat; + position: absolute; + right: 1px; + bottom: 1px; + z-index: 10; +} + +#fbLargeCommandLineIcon:hover { + background: url(upHover.png) no-repeat; +} + +div.fbFitHeight { + overflow: auto; + position: relative; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +.fbSmallButton { + overflow: hidden; + width: 16px; + height: 16px; + display: block; + text-decoration: none; + cursor: default; +} + +#fbWindowButtons .fbSmallButton { + float: right; +} + +#fbWindow_btClose { + background: url(min.png); +} + +#fbWindow_btClose:hover { + background: url(minHover.png); +} + +#fbWindow_btDetach { + background: url(detach.png); +} + +#fbWindow_btDetach:hover { + background: url(detachHover.png); +} + +#fbWindow_btDeactivate { + background: url(off.png); +} + +#fbWindow_btDeactivate:hover { + background: url(offHover.png); +} + + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + /*display: block; TODO: safe to remove this? */ + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #f1f2ee 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: fixed; + _position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #ece9d8; + color: #000; + border: 1px solid #716f64; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 10; + position: absolute; + height: 100%; + top: 27px; +} + +/************************************************************************************************/ +div.lineNo { + font: 1em Monaco, monospace; + position: absolute; + top: 0; + left: 0; + margin: 0; + padding: 0 5px 0 20px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +.sourceBox { + position: absolute; +} + +.sourceCode { + font: 1em Monaco, monospace; + overflow: hidden; + white-space: pre; + display: inline; +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* IE6 need this hack */ +* html .selectedElement { + position: relative; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 1em; +} + +/* TODO: remove this? */ +/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to +position. if so, override it at chrome.js initialization when creating the div */ +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + zbackground-color: #FFFFFF; +} +/**/ + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + + /* TODO: xxxpedro make long strings break line */ + /*white-space: pre; */ +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warning { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png) !important; + background-image: url(infoIcon.gif); +} + +.logRow-warning { + background-color: cyan; + background-image: url(warningIcon.png) !important; + background-image: url(warningIcon.gif); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png) !important; + background-image: url(errorIcon.gif); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +/* +//TODO: remove this when console2 is finished +*/ +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +}/**/ + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.html new file mode 100755 index 0000000..4432a32 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.html @@ -0,0 +1,213 @@ + + + + +Firebug Lite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + +
      +   +   +   +
      + + +
      +
      + + + +   + + + + + + + + + Inspect + + + + + Clear + + + + + + + + + + + + + +
      + +
      + + + + + +
       
      + +
      +
      +
      +
      +
      +
      + + +
       
      + + +
      + + +
      +
      +
      + +
      + + + + + +
      + Run + Clear + + +
      + +
      +
      +
      >>>
      + + +
      +
      + + + + 2 errors + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.png new file mode 100755 index 0000000..e10affe Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/firebug.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/group.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/group.gif new file mode 100755 index 0000000..8db97c2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/group.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/infoIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/infoIcon.gif new file mode 100755 index 0000000..0618e20 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/infoIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/infoIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/infoIcon.png new file mode 100755 index 0000000..da1e533 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/infoIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/loading_16.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/loading_16.gif new file mode 100755 index 0000000..085ccae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/loading_16.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/min.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/min.png new file mode 100755 index 0000000..1034d66 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/min.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/minHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/minHover.png new file mode 100755 index 0000000..b0d1e1a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/minHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/off.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/off.png new file mode 100755 index 0000000..b70b1d2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/off.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/offHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/offHover.png new file mode 100755 index 0000000..f3670f1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/offHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/pixel_transparent.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/pixel_transparent.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/pixel_transparent.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/roundCorner.svg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/roundCorner.svg new file mode 100755 index 0000000..be0291f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/roundCorner.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/search.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/search.gif new file mode 100755 index 0000000..2a62098 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/search.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/search.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/search.png new file mode 100755 index 0000000..fba33b8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/search.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadow.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadow.gif new file mode 100755 index 0000000..af7f537 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadow.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadow2.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadow2.gif new file mode 100755 index 0000000..099cbf3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadow2.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadowAlpha.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadowAlpha.png new file mode 100755 index 0000000..a2561df Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/shadowAlpha.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/sprite.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/sprite.png new file mode 100755 index 0000000..33d2c4d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/sprite.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverLeft.png new file mode 100755 index 0000000..0fb24d0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverMid.png new file mode 100755 index 0000000..fbccab5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverRight.png new file mode 100755 index 0000000..3db0f36 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabHoverRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabLeft.png new file mode 100755 index 0000000..a6cc9e9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuCheckbox.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuCheckbox.png new file mode 100755 index 0000000..4726e62 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuCheckbox.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuPin.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuPin.png new file mode 100755 index 0000000..eb4b11e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuPin.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuRadio.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuRadio.png new file mode 100755 index 0000000..55b982d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuRadio.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuTarget.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuTarget.png new file mode 100755 index 0000000..957bd9f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuTarget.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuTargetHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuTargetHover.png new file mode 100755 index 0000000..200a370 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMenuTargetHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMid.png new file mode 100755 index 0000000..68986c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabRight.png new file mode 100755 index 0000000..5011307 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tabRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorBorders.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorBorders.gif new file mode 100755 index 0000000..0ee5497 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorBorders.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorBorders.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorBorders.png new file mode 100755 index 0000000..21682c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorBorders.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorCorners.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorCorners.gif new file mode 100755 index 0000000..04f8421 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorCorners.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorCorners.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorCorners.png new file mode 100755 index 0000000..a0f839d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/textEditorCorners.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/titlebarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/titlebarMid.png new file mode 100755 index 0000000..10998ae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/titlebarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/toolbarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/toolbarMid.png new file mode 100755 index 0000000..aa21dee Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/toolbarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tree_close.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tree_close.gif new file mode 100755 index 0000000..e26728a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tree_close.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tree_open.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tree_open.gif new file mode 100755 index 0000000..edf662f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/tree_open.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/up.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/up.png new file mode 100755 index 0000000..2174d03 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/up.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/upActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/upActive.png new file mode 100755 index 0000000..236cf67 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/upActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/upHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/upHover.png new file mode 100755 index 0000000..cd81317 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/upHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/warningIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/warningIcon.gif new file mode 100755 index 0000000..8497278 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/warningIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/warningIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/warningIcon.png new file mode 100755 index 0000000..de51084 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/chrome-extension/skin/xp/warningIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/compress.bat b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/compress.bat new file mode 100755 index 0000000..ebc54a3 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/compress.bat @@ -0,0 +1,3 @@ +java -jar yuicompressor-2.4.2.jar --line-break 0 -o firebug-lite.js firebug-lite-debug.js + +pause \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite-beta.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite-beta.js new file mode 100755 index 0000000..41c7d58 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite-beta.js @@ -0,0 +1,29624 @@ +(function(){ + +/*!************************************************************* + * + * Firebug Lite 1.3.2 + * + * Copyright (c) 2007, Parakey Inc. + * Released under BSD license. + * More information: http://getfirebug.com/firebuglite + * + **************************************************************/ + +/*! + * CSS selectors powered by: + * + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ + +/** @namespace describe lib */ +var FBL = {}; + +/** @name ns @namespace */ + +( /** @scope ns-lib @this FBL */ function() { +// ************************************************************************************************ + +// ************************************************************************************************ +// Constants + +var productionDir = "http://getfirebug.com/releases/lite/"; +var bookmarkletVersion = 4; + +// ************************************************************************************************ + +var reNotWhitespace = /[^\s]/; +var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; + +// Globals +this.reJavascript = /\s*javascript:\s*(.*)/; +this.reChrome = /chrome:\/\/([^\/]*)\//; +this.reFile = /file:\/\/([^\/]*)\//; + + +// ************************************************************************************************ +// properties + +var userAgent = navigator.userAgent.toLowerCase(); +this.isFirefox = /firefox/.test(userAgent); +this.isOpera = /opera/.test(userAgent); +this.isSafari = /webkit/.test(userAgent); +this.isIE = /msie/.test(userAgent) && !/opera/.test(userAgent); +this.isIE6 = /msie 6/i.test(navigator.appVersion); +this.browserVersion = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]; +this.isIElt8 = this.isIE && (this.browserVersion-0 < 8); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.NS = null; +this.pixelsPerInch = null; + + +// ************************************************************************************************ +// Namespaces + +var namespaces = []; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.ns = function(fn) +{ + var ns = {}; + namespaces.push(fn, ns); + return ns; +}; + +var FBTrace = null; + +this.initialize = function() +{ + // Firebug Lite is already running in persistent mode so we just quit + if (window.firebug && firebug.firebuglite || window.console && console.firebuglite) + return; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize environment + + // point the FBTrace object to the local variable + if (FBL.FBTrace) + FBTrace = FBL.FBTrace; + else + FBTrace = FBL.FBTrace = {}; + + FBL.Ajax.initialize(); + + // check if the actual window is a persisted chrome context + var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object"; + + // chrome context of the persistent application + if (isChromeContext) + { + // TODO: xxxpedro persist - make a better synchronization + sharedEnv = window.Firebug.SharedEnv; + delete window.Firebug.SharedEnv; + + FBL.Env = sharedEnv; + FBL.Env.isChromeContext = true; + FBTrace.messageQueue = FBL.Env.traceMessageQueue; + } + // non-persistent application + else + { + FBL.NS = document.documentElement.namespaceURI; + FBL.Env.browser = window; + FBL.Env.destroy = destroyEnvironment; + + if (document.documentElement.getAttribute("debug") == "true") + FBL.Env.Options.startOpened = true; + + // find the URL location of the loaded application + findLocation(); + + // TODO: get preferences here... + var prefs = eval("(" + FBL.readCookie("FirebugLite") + ")"); + if (prefs) + { + FBL.Env.Options.startOpened = prefs.startOpened; + FBL.Env.Options.enableTrace = prefs.enableTrace; + FBL.Env.Options.enablePersistent = prefs.enablePersistent; + FBL.Env.Options.disableXHRListener = prefs.disableXHRListener; + } + + if (FBL.isFirefox && + typeof FBL.Env.browser.console == "object" && + FBL.Env.browser.console.firebug && + FBL.Env.Options.disableWhenFirebugActive) + return; + } + + // exposes the FBL to the global namespace when in debug mode + if (FBL.Env.isDebugMode) + { + FBL.Env.browser.FBL = FBL; + } + + // check browser compatibilities + this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat"; + this.isIEQuiksMode = this.isIE && this.isQuiksMode; + this.isIEStantandMode = this.isIE && !this.isQuiksMode; + + this.noFixedPosition = this.isIE6 || this.isIEQuiksMode; + + // after creating/synchronizing the environment, initialize the FBTrace module + if (FBL.Env.Options.enableTrace) FBTrace.initialize(); + + if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize namespaces + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN"); + + for (var i = 0; i < namespaces.length; i += 2) + { + var fn = namespaces[i]; + var ns = namespaces[i+1]; + fn.apply(ns); + } + + if (FBTrace.DBG_INITIALIZE) { + FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END"); + FBTrace.sysout("FBL waitForDocument", "waiting document load"); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // finish environment initialization + + FBL.Firebug.loadPrefs(prefs); + + if (FBL.Env.Options.enablePersistent) + { + // TODO: xxxpedro persist - make a better synchronization + if (isChromeContext) + { + FBL.FirebugChrome.clone(FBL.Env.FirebugChrome); + } + else + { + FBL.Env.FirebugChrome = FBL.FirebugChrome; + FBL.Env.traceMessageQueue = FBTrace.messageQueue; + } + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // wait document load + + waitForDocument(); +}; + +var waitForDocument = function waitForDocument() +{ + // document.body not available in XML+XSL documents in Firefox + var doc = FBL.Env.browser.document; + var body = doc.getElementsByTagName("body")[0]; + + if (body) + { + calculatePixelsPerInch(doc, body); + onDocumentLoad(); + } + else + setTimeout(waitForDocument, 50); +}; + +var onDocumentLoad = function onDocumentLoad() +{ + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded"); + + // fix IE6 problem with cache of background images, causing a lot of flickering + if (FBL.isIE6) + fixIE6BackgroundImageCache(); + + // chrome context of the persistent application + if (FBL.Env.Options.enablePersistent && FBL.Env.isChromeContext) + { + // finally, start the application in the chrome context + FBL.Firebug.initialize(); + + // if is not development mode, remove the shared environment cache object + // used to synchronize the both persistent contexts + if (!FBL.Env.isDevelopmentMode) + { + sharedEnv.destroy(); + sharedEnv = null; + } + } + // non-persistent application + else + { + FBL.FirebugChrome.create(); + } +}; + +// ************************************************************************************************ +// Env + +var sharedEnv; + +this.Env = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env Options (will be transported to Firebug options) + Options: + { + saveCookies: false, + + saveWindowPosition: false, + saveCommandLineHistory: false, + + startOpened: false, + startInNewWindow: false, + showIconWhenHidden: true, + + overrideConsole: true, + ignoreFirebugElements: true, + disableWhenFirebugActive: true, + + disableXHRListener: false, + + enableTrace: false, + enablePersistent: false + + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Library location + Location: + { + sourceDir: null, + baseDir: null, + skinDir: null, + skin: null, + app: null + }, + + skin: "xp", + useLocalSkin: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env states + isDevelopmentMode: false, + isDebugMode: false, + isChromeContext: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env references + browser: null, + chrome: null +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var destroyEnvironment = function destroyEnvironment() +{ + setTimeout(function() + { + FBL = null; + }, 100); +}; + +// ************************************************************************************************ +// Library location + +var findLocation = function findLocation() +{ + var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/; + + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = document; + + // Firebug Lite 1.3.0 bookmarklet identification + var script = doc.getElementById("FirebugLite"); + + if (script) + { + file = reFirebugFile.exec(script.src); + + var version = script.getAttribute("FirebugLite"); + var number = version ? parseInt(version) : 0; + + if (!version || !number || number < bookmarkletVersion) + { + FBL.Env.bookmarkletOutdated = true; + } + } + else + { + for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++) + { + var file = null; + if ( si.nodeName.toLowerCase() == "script" && (file = reFirebugFile.exec(si.src)) ) + { + script = si; + break; + } + } + } + + if (script) + script.firebugIgnore = true; + + if (file) + { + var fileName = file[1]; + var fileOptions = file[2]; + + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; + + } + // relative path + else + { + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(location.href)[1]; + + // "../some/path" + if (backDir) + { + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; + if (FBL.Env.isChromeExtension) + { + path = productionDir; + FBL.Env.bookmarkletOutdated = false; + script = {innerHTML: "{showIconWhenHidden:false}"}; + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + var Env = FBL.Env; + + // Always use the local skin when running in the same domain + // See Issue 3554: Firebug Lite should use local images when loaded locally + Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0; + + // detecting development and debug modes via file name + if (fileName == "firebug-lite-dev.js") + { + Env.isDevelopmentMode = true; + Env.isDebugMode = true; + } + else if (fileName == "firebug-lite-debug.js") + { + Env.isDebugMode = true; + } + + // process the + if (Env.browser.document.documentElement.getAttribute("debug") == "true") + { + Env.Options.startOpened = true; + } + + // process the Script URL Options + if (fileOptions) + { + var options = fileOptions.split(","); + + for (var i = 0, length = options.length; i < length; i++) + { + var option = options[i]; + var name, value; + + if (option.indexOf("=") != -1) + { + var parts = option.split("="); + name = parts[0]; + value = eval(unescape(parts[1])); + } + else + { + name = option; + value = true; + } + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Script JSON Options + var innerOptions = FBL.trim(script.innerHTML); + if (innerOptions) + { + var innerOptionsObject = eval("(" + innerOptions + ")"); + + for (var name in innerOptionsObject) + { + var value = innerOptionsObject[name]; + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Debug Mode + if (Env.isDebugMode) + { + Env.Options.startOpened = true; + Env.Options.enableTrace = true; + Env.Options.disableWhenFirebugActive = false; + } + + var loc = Env.Location; + var isProductionRelease = path.indexOf(productionDir) != -1; + + loc.sourceDir = path; + loc.baseDir = path.substr(0, path.length - m[1].length - 1); + loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/"; + loc.skin = loc.skinDir + "firebug.html"; + loc.app = path + fileName; + } + else + { + throw new Error("Firebug Error: Library path not found"); + } +}; + +// ************************************************************************************************ +// Basics + +this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }; +}; + +this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, args); }; +}; + +this.extend = function(l, r) +{ + var newOb = {}; + for (var n in l) + newOb[n] = l[n]; + for (var n in r) + newOb[n] = r[n]; + return newOb; +}; + +this.descend = function(prototypeParent, childProperties) +{ + function protoSetter() {}; + protoSetter.prototype = prototypeParent; + var newOb = new protoSetter(); + for (var n in childProperties) + newOb[n] = childProperties[n]; + return newOb; +}; + +this.append = function(l, r) +{ + for (var n in r) + l[n] = r[n]; + + return l; +}; + +this.keys = function(map) // At least sometimes the keys will be on user-level window objects +{ + var keys = []; + try + { + for (var name in map) // enumeration is safe + keys.push(name); // name is string, safe + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + } + + return keys; // return is safe +}; + +this.values = function(map) +{ + var values = []; + try + { + for (var name in map) + { + try + { + values.push(map[name]); + } + catch (exc) + { + // Sometimes we get exceptions trying to access properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + } + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + return values; +}; + +this.remove = function(list, item) +{ + for (var i = 0; i < list.length; ++i) + { + if (list[i] == item) + { + list.splice(i, 1); + break; + } + } +}; + +this.sliceArray = function(array, index) +{ + var slice = []; + for (var i = index; i < array.length; ++i) + slice.push(array[i]); + + return slice; +}; + +function cloneArray(array, fn) +{ + var newArray = []; + + if (fn) + for (var i = 0; i < array.length; ++i) + newArray.push(fn(array[i])); + else + for (var i = 0; i < array.length; ++i) + newArray.push(array[i]); + + return newArray; +} + +function extendArray(array, array2) +{ + var newArray = []; + newArray.push.apply(newArray, array); + newArray.push.apply(newArray, array2); + return newArray; +} + +this.extendArray = extendArray; +this.cloneArray = cloneArray; + +function arrayInsert(array, index, other) +{ + for (var i = 0; i < other.length; ++i) + array.splice(i+index, 0, other[i]); + + return array; +} + +// ************************************************************************************************ + +this.createStyleSheet = function(doc, url) +{ + //TODO: xxxpedro + //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + var style = this.createElement("link"); + style.setAttribute("charset","utf-8"); + style.firebugIgnore = true; + style.setAttribute("rel", "stylesheet"); + style.setAttribute("type", "text/css"); + style.setAttribute("href", url); + + //TODO: xxxpedro + //style.innerHTML = this.getResource(url); + return style; +}; + +this.addStyleSheet = function(doc, style) +{ + var heads = doc.getElementsByTagName("head"); + if (heads.length) + heads[0].appendChild(style); + else + doc.documentElement.appendChild(style); +}; + +this.appendStylesheet = function(doc, uri) +{ + // Make sure the stylesheet is not appended twice. + if (this.$(uri, doc)) + return; + + var styleSheet = this.createStyleSheet(doc, uri); + styleSheet.setAttribute("id", uri); + this.addStyleSheet(doc, styleSheet); +}; + +this.addScript = function(doc, id, src) +{ + var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script"); + element.setAttribute("type", "text/javascript"); + element.setAttribute("id", id); + if (!FBTrace.DBG_CONSOLE) + FBL.unwrapObject(element).firebugIgnore = true; + + element.innerHTML = src; + if (doc.documentElement) + doc.documentElement.appendChild(element); + else + { + // See issue 1079, the svg test case gives this error + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.addScript doc has no documentElement:", doc); + } + return element; +}; + + +// ************************************************************************************************ + +this.getStyle = this.isIE ? + function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : + function(el, name) + { + return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + }; + + +// ************************************************************************************************ +// Whitespace and Entity conversions + +var entityConversionLists = this.entityConversionLists = { + normal : { + whitespace : { + '\t' : '\u200c\u2192', + '\n' : '\u200c\u00b6', + '\r' : '\u200c\u00ac', + ' ' : '\u200c\u00b7' + } + }, + reverse : { + whitespace : { + ' ' : '\t', + ' ' : '\n', + '\u200c\u2192' : '\t', + '\u200c\u00b6' : '\n', + '\u200c\u00ac' : '\r', + '\u200c\u00b7' : ' ' + } + } +}; + +var normal = entityConversionLists.normal, + reverse = entityConversionLists.reverse; + +function addEntityMapToList(ccode, entity) +{ + var lists = Array.prototype.slice.call(arguments, 2), + len = lists.length, + ch = String.fromCharCode(ccode); + for (var i = 0; i < len; i++) + { + var list = lists[i]; + normal[list]=normal[list] || {}; + normal[list][ch] = '&' + entity + ';'; + reverse[list]=reverse[list] || {}; + reverse[list]['&' + entity + ';'] = ch; + } +}; + +var e = addEntityMapToList, + white = 'whitespace', + text = 'text', + attr = 'attributes', + css = 'css', + editor = 'editor'; + +e(0x0022, 'quot', attr, css); +e(0x0026, 'amp', attr, text, css); +e(0x0027, 'apos', css); +e(0x003c, 'lt', attr, text, css); +e(0x003e, 'gt', attr, text, css); +e(0xa9, 'copy', text, editor); +e(0xae, 'reg', text, editor); +e(0x2122, 'trade', text, editor); + +// See http://en.wikipedia.org/wiki/Dash +e(0x2012, '#8210', attr, text, editor); // figure dash +e(0x2013, 'ndash', attr, text, editor); // en dash +e(0x2014, 'mdash', attr, text, editor); // em dash +e(0x2015, '#8213', attr, text, editor); // horizontal bar + +e(0x00a0, 'nbsp', attr, text, white, editor); +e(0x2002, 'ensp', attr, text, white, editor); +e(0x2003, 'emsp', attr, text, white, editor); +e(0x2009, 'thinsp', attr, text, white, editor); +e(0x200c, 'zwnj', attr, text, white, editor); +e(0x200d, 'zwj', attr, text, white, editor); +e(0x200e, 'lrm', attr, text, white, editor); +e(0x200f, 'rlm', attr, text, white, editor); +e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP) + +//************************************************************************************************ +// Entity escaping + +var entityConversionRegexes = { + normal : {}, + reverse : {} + }; + +var escapeEntitiesRegEx = { + normal : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('([' + chars.join('') + '])', 'gm'); + }, + reverse : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('(' + chars.join('|') + ')', 'gm'); + } +}; + +function getEscapeRegexp(direction, lists) +{ + var name = '', re; + var groups = [].concat(lists); + for (i = 0; i < groups.length; i++) + { + name += groups[i].group; + } + re = entityConversionRegexes[direction][name]; + if (!re) + { + var list = {}; + if (groups.length > 1) + { + for ( var i = 0; i < groups.length; i++) + { + var aList = entityConversionLists[direction][groups[i].group]; + for ( var item in aList) + list[item] = aList[item]; + } + } else if (groups.length==1) + { + list = entityConversionLists[direction][groups[0].group]; // faster for special case + } else { + list = {}; // perhaps should print out an error here? + } + re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list); + } + return re; +}; + +function createSimpleEscape(name, direction) +{ + return function(value) + { + var list = entityConversionLists[direction][name]; + return String(value).replace( + getEscapeRegexp(direction, { + group : name, + list : list + }), + function(ch) + { + return list[ch]; + } + ); + }; +}; + +function escapeGroupsForEntities(str, lists) +{ + lists = [].concat(lists); + var re = getEscapeRegexp('normal', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list, last = ''; + if (!len) + return [ { + str : String(str), + group : '', + name : '' + } ]; + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.normal[list.group][cur]; + // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space + // r = ' '; + if (r) + { + results[ri] = { + 'str' : r, + 'class' : list['class'], + 'extra' : list.extra[cur] ? list['class'] + + list.extra[cur] : '' + }; + break; + } + } + // last=cur; + if (!r) + results[ri] = { + 'str' : cur, + 'class' : '', + 'extra' : '' + }; + ri++; + } + return results; +}; + +this.escapeGroupsForEntities = escapeGroupsForEntities; + + +function unescapeEntities(str, lists) +{ + var re = getEscapeRegexp('reverse', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list; + if (!len) + return str; + lists = [].concat(lists); + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.reverse[list.group][cur]; + if (r) + { + results[ri] = r; + break; + } + } + if (!r) + results[ri] = cur; + ri++; + } + return results.join('') || ''; +}; + + +// ************************************************************************************************ +// String escaping + +var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal'); +var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal'); +var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal'); +var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal'); + +// deprecated compatibility functions +//this.deprecateEscapeHTML = createSimpleEscape('text', 'normal'); +//this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse'); +//this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML); +//this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML); + +var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); + +var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); + +this.unescapeForTextNode = function(str) +{ + if (Firebug.showTextNodesWithWhitespace) + str = unescapeWhitespace(str); + if (!Firebug.showTextNodesWithEntities) + str = escapeForElementAttribute(str); + return str; +}; + +this.escapeNewLines = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); +}; + +this.stripNewLines = function(value) +{ + return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; +}; + +this.escapeJS = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); +}; + +function escapeHTMLAttribute(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "&": + return "&"; + case "'": + return apos; + case '"': + return quot; + } + return "?"; + }; + var apos = "'", quot = """, around = '"'; + if( value.indexOf('"') == -1 ) { + quot = '"'; + apos = "'"; + } else if( value.indexOf("'") == -1 ) { + quot = '"'; + around = "'"; + } + return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; +} + + +function escapeHTML(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); +} + +this.escapeHTML = escapeHTML; + +this.cropString = function(text, limit) +{ + text = text + ""; + + if (!limit) + var halfLimit = 50; + else + var halfLimit = limit / 2; + + if (text.length > limit) + return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); + else + return this.escapeNewLines(text); +}; + +this.isWhitespace = function(text) +{ + return !reNotWhitespace.exec(text); +}; + +this.splitLines = function(text) +{ + var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; + var lines; + if (text.match) + { + lines = text.match(reSplitLines2); + } + else + { + var str = text+""; + lines = str.match(reSplitLines2); + } + lines.pop(); + return lines; +}; + + +// ************************************************************************************************ + +this.safeToString = function(ob) +{ + if (this.isIE) + return ob + ""; + + try + { + if (ob && "toString" in ob && typeof ob.toString == "function") + return ob.toString(); + } + catch (exc) + { + // xxxpedro it is not safe to use ob+""? + return ob + ""; + ///return "[an object with no toString() function]"; + } +}; + +// ************************************************************************************************ + +this.hasProperties = function(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + return false; +}; + +// ************************************************************************************************ +// String Util + +var reTrim = /^\s+|\s+$/g; +this.trim = function(s) +{ + return s.replace(reTrim, ""); +}; + + +// ************************************************************************************************ +// Empty + +this.emptyFn = function(){}; + + + +// ************************************************************************************************ +// Visibility + +this.isVisible = function(elt) +{ + /* + if (elt instanceof XULElement) + { + //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); + return (!elt.hidden && !elt.collapsed); + } + /**/ + + return this.getStyle(elt, "visibility") != "hidden" && + ( elt.offsetWidth > 0 || elt.offsetHeight > 0 + || elt.tagName in invisibleTags + || elt.namespaceURI == "http://www.w3.org/2000/svg" + || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" ); +}; + +this.collapse = function(elt, collapsed) +{ + // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector, + // but it is causing a bug (the element disappears when you set the "collapsed" + // attribute, but it doesn't appear when you remove the attribute. So, for those + // cases, we need to use the class attribute. + if (this.isIElt8) + { + if (collapsed) + this.setClass(elt, "collapsed"); + else + this.removeClass(elt, "collapsed"); + } + else + elt.setAttribute("collapsed", collapsed ? "true" : "false"); +}; + +this.obscure = function(elt, obscured) +{ + if (obscured) + this.setClass(elt, "obscured"); + else + this.removeClass(elt, "obscured"); +}; + +this.hide = function(elt, hidden) +{ + elt.style.visibility = hidden ? "hidden" : "visible"; +}; + +this.clearNode = function(node) +{ + var nodeName = " " + node.nodeName.toLowerCase() + " "; + var ignoreTags = " table tbody thead tfoot th tr td "; + + // IE can't use innerHTML of table elements + if (this.isIE && ignoreTags.indexOf(nodeName) != -1) + this.eraseNode(node); + else + node.innerHTML = ""; +}; + +this.eraseNode = function(node) +{ + while (node.lastChild) + node.removeChild(node.lastChild); +}; + +// ************************************************************************************************ +// Window iteration + +this.iterateWindows = function(win, handler) +{ + if (!win || !win.document) + return; + + handler(win); + + if (win == top || !win.frames) return; // XXXjjb hack for chromeBug + + for (var i = 0; i < win.frames.length; ++i) + { + var subWin = win.frames[i]; + if (subWin != win) + this.iterateWindows(subWin, handler); + } +}; + +this.getRootWindow = function(win) +{ + for (; win; win = win.parent) + { + if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) + return win; + } + return null; +}; + +// ************************************************************************************************ +// Graphics + +this.getClientOffset = function(elt) +{ + var addOffset = function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + + var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, ""); + + if (elt.offsetLeft) + coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth); + if (elt.offsetTop) + coords.y += elt.offsetTop + parseInt(style.borderTopWidth); + + if (p) + { + if (p.nodeType == 1) + addOffset(p, coords, view); + } + else + { + var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + if (otherView.frameElement) + addOffset(otherView.frameElement, coords, otherView); + } + }; + + var isIE = this.isIE; + var coords = {x: 0, y: 0}; + if (elt) + { + var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + addOffset(elt, coords, view); + } + + return coords; +}; + +this.getViewOffset = function(elt, singleFrame) +{ + function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); + coords.y += elt.offsetTop - (p ? p.scrollTop : 0); + + if (p) + { + if (p.nodeType == 1) + { + var parentStyle = view.getComputedStyle(p, ""); + if (parentStyle.position != "static") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + + if (p.localName == "TABLE") + { + coords.x += parseInt(parentStyle.paddingLeft); + coords.y += parseInt(parentStyle.paddingTop); + } + else if (p.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.marginLeft); + coords.y += parseInt(style.marginTop); + } + } + else if (p.localName == "BODY") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + } + + var parent = elt.parentNode; + while (p != parent) + { + coords.x -= parent.scrollLeft; + coords.y -= parent.scrollTop; + parent = parent.parentNode; + } + addOffset(p, coords, view); + } + } + else + { + if (elt.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.borderLeftWidth); + coords.y += parseInt(style.borderTopWidth); + + var htmlStyle = view.getComputedStyle(elt.parentNode, ""); + coords.x -= parseInt(htmlStyle.paddingLeft); + coords.y -= parseInt(htmlStyle.paddingTop); + } + + if (elt.scrollLeft) + coords.x += elt.scrollLeft; + if (elt.scrollTop) + coords.y += elt.scrollTop; + + var win = elt.ownerDocument.defaultView; + if (win && (!singleFrame && win.frameElement)) + addOffset(win.frameElement, coords, win); + } + + } + + var coords = {x: 0, y: 0}; + if (elt) + addOffset(elt, coords, elt.ownerDocument.defaultView); + + return coords; +}; + +this.getLTRBWH = function(elt) +{ + var bcrect, + dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; + + if (elt) + { + bcrect = elt.getBoundingClientRect(); + dims.left = bcrect.left; + dims.top = bcrect.top; + dims.right = bcrect.right; + dims.bottom = bcrect.bottom; + + if(bcrect.width) + { + dims.width = bcrect.width; + dims.height = bcrect.height; + } + else + { + dims.width = dims.right - dims.left; + dims.height = dims.bottom - dims.top; + } + } + return dims; +}; + +this.applyBodyOffsets = function(elt, clientRect) +{ + var od = elt.ownerDocument; + if (!od.body) + return clientRect; + + var style = od.defaultView.getComputedStyle(od.body, null); + + var pos = style.getPropertyValue('position'); + if(pos === 'absolute' || pos === 'relative') + { + var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0; + var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0; + var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0; + var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0; + var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0; + var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0; + + var offsetX = borderLeft + paddingLeft + marginLeft; + var offsetY = borderTop + paddingTop + marginTop; + + clientRect.left -= offsetX; + clientRect.top -= offsetY; + clientRect.right -= offsetX; + clientRect.bottom -= offsetY; + } + + return clientRect; +}; + +this.getOffsetSize = function(elt) +{ + return {width: elt.offsetWidth, height: elt.offsetHeight}; +}; + +this.getOverflowParent = function(element) +{ + for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) + { + if (scrollParent.scrollHeight > scrollParent.offsetHeight) + return scrollParent; + } +}; + +this.isScrolledToBottom = function(element) +{ + var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight; + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom); + return onBottom; +}; + +this.scrollToBottom = function(element) +{ + element.scrollTop = element.scrollHeight; + + if (FBTrace.DBG_CONSOLE) + { + FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); + if (element.scrollHeight == element.offsetHeight) + FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element); + } + + return (element.scrollTop == element.scrollHeight); +}; + +this.move = function(element, x, y) +{ + element.style.left = x + "px"; + element.style.top = y + "px"; +}; + +this.resize = function(element, w, h) +{ + element.style.width = w + "px"; + element.style.height = h + "px"; +}; + +this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} +{ + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var split = (scrollBox.clientHeight/2); + var centerY = offset.y - split; + scrollBox.scrollTop = centerY; + topSpace = split; + bottomSpace = split - element.offsetHeight; + } + + return {before: Math.round((topSpace/element.offsetHeight) + 0.5), + after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; +}; + +this.scrollIntoCenterView = function(element, scrollBox, notX, notY) +{ + if (!element) + return; + + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + if (!notY) + { + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var centerY = offset.y - (scrollBox.clientHeight/2); + scrollBox.scrollTop = centerY; + } + } + + if (!notX) + { + var leftSpace = offset.x - scrollBox.scrollLeft; + var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) + - (offset.x + element.clientWidth); + + if (leftSpace < 0 || rightSpace < 0) + { + var centerX = offset.x - (scrollBox.clientWidth/2); + scrollBox.scrollLeft = centerX; + } + } + if (FBTrace.DBG_SOURCEFILES) + FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); +}; + + +// ************************************************************************************************ +// CSS + +var cssKeywordMap = null; +var cssPropNames = null; +var cssColorNames = null; +var imageRules = null; + +this.getCSSKeywordsByProperty = function(propName) +{ + if (!cssKeywordMap) + { + cssKeywordMap = {}; + + for (var name in this.cssInfo) + { + var list = []; + + var types = this.cssInfo[name]; + for (var i = 0; i < types.length; ++i) + { + var keywords = this.cssKeywords[types[i]]; + if (keywords) + list.push.apply(list, keywords); + } + + cssKeywordMap[name] = list; + } + } + + return propName in cssKeywordMap ? cssKeywordMap[propName] : []; +}; + +this.getCSSPropertyNames = function() +{ + if (!cssPropNames) + { + cssPropNames = []; + + for (var name in this.cssInfo) + cssPropNames.push(name); + } + + return cssPropNames; +}; + +this.isColorKeyword = function(keyword) +{ + if (keyword == "transparent") + return false; + + if (!cssColorNames) + { + cssColorNames = []; + + var colors = this.cssKeywords["color"]; + for (var i = 0; i < colors.length; ++i) + cssColorNames.push(colors[i].toLowerCase()); + + var systemColors = this.cssKeywords["systemColor"]; + for (var i = 0; i < systemColors.length; ++i) + cssColorNames.push(systemColors[i].toLowerCase()); + } + + return cssColorNames.indexOf ? // Array.indexOf is not available in IE + cssColorNames.indexOf(keyword.toLowerCase()) != -1 : + (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; +}; + +this.isImageRule = function(rule) +{ + if (!imageRules) + { + imageRules = []; + + for (var i in this.cssInfo) + { + var r = i.toLowerCase(); + var suffix = "image"; + if (r.match(suffix + "$") == suffix || r == "background") + imageRules.push(r); + } + } + + return imageRules.indexOf ? // Array.indexOf is not available in IE + imageRules.indexOf(rule.toLowerCase()) != -1 : + (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; +}; + +this.copyTextStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.fontFamily = style.fontFamily; + + // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE + // returns wrong computed styles for inherited properties (like font-*) + // + // Also would be good to create a FBL.getStyle() + toNode.style.fontSize = style.fontSize; + toNode.style.fontWeight = style.fontWeight; + toNode.style.fontStyle = style.fontStyle; + + return style; + } +}; + +this.copyBoxStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.marginTop = style.marginTop; + toNode.style.marginRight = style.marginRight; + toNode.style.marginBottom = style.marginBottom; + toNode.style.marginLeft = style.marginLeft; + toNode.style.borderTopWidth = style.borderTopWidth; + toNode.style.borderRightWidth = style.borderRightWidth; + toNode.style.borderBottomWidth = style.borderBottomWidth; + toNode.style.borderLeftWidth = style.borderLeftWidth; + + return style; + } +}; + +this.readBoxStyles = function(style) +{ + var styleNames = { + "margin-top": "marginTop", "margin-right": "marginRight", + "margin-left": "marginLeft", "margin-bottom": "marginBottom", + "border-top-width": "borderTop", "border-right-width": "borderRight", + "border-left-width": "borderLeft", "border-bottom-width": "borderBottom", + "padding-top": "paddingTop", "padding-right": "paddingRight", + "padding-left": "paddingLeft", "padding-bottom": "paddingBottom", + "z-index": "zIndex" + }; + + var styles = {}; + for (var styleName in styleNames) + styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0; + if (FBTrace.DBG_INSPECT) + FBTrace.sysout("readBoxStyles ", styles); + return styles; +}; + +this.getBoxFromStyles = function(style, element) +{ + var args = this.readBoxStyles(style); + args.width = element.offsetWidth + - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight); + args.height = element.offsetHeight + - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom); + return args; +}; + +this.getElementCSSSelector = function(element) +{ + var label = element.localName.toLowerCase(); + if (element.id) + label += "#" + element.id; + if (element.hasAttribute("class")) + label += "." + element.getAttribute("class").split(" ")[0]; + + return label; +}; + +this.getURLForStyleSheet= function(styleSheet) +{ + //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null. + return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL); +}; + +this.getDocumentForStyleSheet = function(styleSheet) +{ + while (styleSheet.parentStyleSheet && !styleSheet.ownerNode) + { + styleSheet = styleSheet.parentStyleSheet; + } + if (styleSheet.ownerNode) + return styleSheet.ownerNode.ownerDocument; +}; + +/** + * Retrieves the instance number for a given style sheet. The instance number + * is sheet's index within the set of all other sheets whose URL is the same. + */ +this.getInstanceForStyleSheet = function(styleSheet, ownerDocument) +{ + // System URLs are always unique (or at least we are making this assumption) + if (FBL.isSystemStyleSheet(styleSheet)) + return 0; + + // ownerDocument is an optional hint for performance + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument); + ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet); + + var ret = 0, + styleSheets = ownerDocument.styleSheets, + href = styleSheet.href; + for (var i = 0; i < styleSheets.length; i++) + { + var curSheet = styleSheets[i]; + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode))); + if (curSheet == styleSheet) + break; + if (curSheet.href == href) + ret++; + } + return ret; +}; + +// ************************************************************************************************ +// HTML and XML Serialization + + +var getElementType = this.getElementType = function(node) +{ + if (isElementXUL(node)) + return 'xul'; + else if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else if (isElementXHTML(node)) + return 'xhtml'; + else if (isElementHTML(node)) + return 'html'; +} + +var getElementSimpleType = this.getElementSimpleType = function(node) +{ + if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else + return 'html'; +} + +var isElementHTML = this.isElementHTML = function(node) +{ + return node.nodeName == node.nodeName.toUpperCase(); +} + +var isElementXHTML = this.isElementXHTML = function(node) +{ + return node.nodeName == node.nodeName.toLowerCase(); +} + +var isElementMathML = this.isElementMathML = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; +} + +var isElementSVG = this.isElementSVG = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/2000/svg'; +} + +var isElementXUL = this.isElementXUL = function(node) +{ + return node instanceof XULElement; +} + +this.isSelfClosing = function(element) +{ + if (isElementSVG(element) || isElementMathML(element)) + return true; + var tag = element.localName.toLowerCase(); + return (this.selfClosingTags.hasOwnProperty(tag)); +}; + +this.getElementHTML = function(element) +{ + var self=this; + function toHTML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + html.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + html.push('>'); + + var pureText=true; + for (var child = element.firstChild; child; child = child.nextSibling) + pureText=pureText && (child.nodeType == Node.TEXT_NODE); + + if (pureText) + html.push(escapeForHtmlEditor(elt.textContent)); + else { + for (var child = elt.firstChild; child; child = child.nextSibling) + toHTML(child); + } + + html.push(''); + } + else if (isElementSVG(elt) || isElementMathML(elt)) + { + html.push('/>'); + } + else if (self.isSelfClosing(elt)) + { + html.push((isElementXHTML(elt))?'/>':'>'); + } + else + { + html.push('>'); + } + } + else if (elt.nodeType == Node.TEXT_NODE) + html.push(escapeForTextNode(elt.textContent)); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + html.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + html.push(''); + } + + var html = []; + toHTML(element); + return html.join(""); +}; + +this.getElementXML = function(element) +{ + function toXML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + xml.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + xml.push('>'); + + for (var child = elt.firstChild; child; child = child.nextSibling) + toXML(child); + + xml.push(''); + } + else + xml.push('/>'); + } + else if (elt.nodeType == Node.TEXT_NODE) + xml.push(elt.nodeValue); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + xml.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + xml.push(''); + } + + var xml = []; + toXML(element); + return xml.join(""); +}; + + +// ************************************************************************************************ +// CSS classes + +this.hasClass = function(node, name) // className, className, ... +{ + // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments? + // this function can be optimized a lot if assumed 2 arguments only, + // which seems to be what happens 99% of the time + if (arguments.length == 2) + return (' '+node.className+' ').indexOf(' '+name+' ') != -1; + + if (!node || node.nodeType != 1) + return false; + else + { + for (var i=1; i= 0) + { + var size = name.length; + node.className = node.className.substr(0,index-1) + node.className.substr(index+size); + } + } +}; + +this.toggleClass = function(elt, name) +{ + if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1) + ///if (this.hasClass(elt, name)) + this.removeClass(elt, name); + else + this.setClass(elt, name); +}; + +this.setClassTimed = function(elt, name, context, timeout) +{ + if (!timeout) + timeout = 1300; + + if (elt.__setClassTimeout) + context.clearTimeout(elt.__setClassTimeout); + else + this.setClass(elt, name); + + elt.__setClassTimeout = context.setTimeout(function() + { + delete elt.__setClassTimeout; + + FBL.removeClass(elt, name); + }, timeout); +}; + +this.cancelClassTimed = function(elt, name, context) +{ + if (elt.__setClassTimeout) + { + FBL.removeClass(elt, name); + context.clearTimeout(elt.__setClassTimeout); + delete elt.__setClassTimeout; + } +}; + + +// ************************************************************************************************ +// DOM queries + +this.$ = function(id, doc) +{ + if (doc) + return doc.getElementById(id); + else + { + return FBL.Firebug.chrome.document.getElementById(id); + } +}; + +this.$$ = function(selector, doc) +{ + if (doc || !FBL.Firebug.chrome) + return FBL.Firebug.Selector(selector, doc); + else + { + return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document); + } +}; + +this.getChildByClass = function(node) // ,classname, classname, classname... +{ + for (var i = 1; i < arguments.length; ++i) + { + var className = arguments[i]; + var child = node.firstChild; + node = null; + for (; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + { + node = child; + break; + } + } + } + + return node; +}; + +this.getAncestorByClass = function(node, className) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (this.hasClass(parent, className)) + return parent; + } + + return null; +}; + + +this.getElementsByClass = function(node, className) +{ + var result = []; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + result.push(child); + } + + return result; +}; + +this.getElementByClass = function(node, className) // className, className, ... +{ + var args = cloneArray(arguments); args.splice(0, 1); + for (var child = node.firstChild; child; child = child.nextSibling) + { + var args1 = cloneArray(args); args1.unshift(child); + if (FBL.hasClass.apply(null, args1)) + return child; + else + { + var found = FBL.getElementByClass.apply(null, args1); + if (found) + return found; + } + } + + return null; +}; + +this.isAncestor = function(node, potentialAncestor) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (parent == potentialAncestor) + return true; + } + + return false; +}; + +this.getNextElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.nextSibling; + + return node; +}; + +this.getPreviousElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.previousSibling; + + return node; +}; + +this.getBody = function(doc) +{ + if (doc.body) + return doc.body; + + var body = doc.getElementsByTagName("body")[0]; + if (body) + return body; + + return doc.firstChild; // For non-HTML docs +}; + +this.findNextDown = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (criteria(child)) + return child; + + var next = this.findNextDown(child, criteria); + if (next) + return next; + } +}; + +this.findPreviousUp = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.lastChild; child; child = child.previousSibling) + { + var next = this.findPreviousUp(child, criteria); + if (next) + return next; + + if (criteria(child)) + return child; + } +}; + +this.findNext = function(node, criteria, upOnly, maxRoot) +{ + if (!node) + return null; + + if (!upOnly) + { + var next = this.findNextDown(node, criteria); + if (next) + return next; + } + + for (var sib = node.nextSibling; sib; sib = sib.nextSibling) + { + if (criteria(sib)) + return sib; + + var next = this.findNextDown(sib, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + return this.findNext(node.parentNode, criteria, true); +}; + +this.findPrevious = function(node, criteria, downOnly, maxRoot) +{ + if (!node) + return null; + + for (var sib = node.previousSibling; sib; sib = sib.previousSibling) + { + var prev = this.findPreviousUp(sib, criteria); + if (prev) + return prev; + + if (criteria(sib)) + return sib; + } + + if (!downOnly) + { + var next = this.findPreviousUp(node, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + { + if (criteria(node.parentNode)) + return node.parentNode; + + return this.findPrevious(node.parentNode, criteria, true); + } +}; + +this.getNextByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findNext(root, iter); +}; + +this.getPreviousByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findPrevious(root, iter); +}; + +this.isElement = function(o) +{ + try { + return o && this.instanceOf(o, "Element"); + } + catch (ex) { + return false; + } +}; + + +// ************************************************************************************************ +// DOM Modification + +// TODO: xxxpedro use doc fragments in Context API +var appendFragment = null; + +this.appendInnerHTML = function(element, html, referenceElement) +{ + // if undefined, we must convert it to null otherwise it will throw an error in IE + // when executing element.insertBefore(firstChild, referenceElement) + referenceElement = referenceElement || null; + + var doc = element.ownerDocument; + + // doc.createRange not available in IE + if (doc.createRange) + { + var range = doc.createRange(); // a helper object + range.selectNodeContents(element); // the environment to interpret the html + + var fragment = range.createContextualFragment(html); // parse + var firstChild = fragment.firstChild; + element.insertBefore(fragment, referenceElement); + } + else + { + if (!appendFragment || appendFragment.ownerDocument != doc) + appendFragment = doc.createDocumentFragment(); + + var div = doc.createElement("div"); + div.innerHTML = html; + + var firstChild = div.firstChild; + while (div.firstChild) + appendFragment.appendChild(div.firstChild); + + element.insertBefore(appendFragment, referenceElement); + + div = null; + } + + return firstChild; +}; + + +// ************************************************************************************************ +// DOM creation + +this.createElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = properties.document || FBL.Firebug.chrome.document; + + var element = doc.createElement(tagName); + + for(var name in properties) + { + if (name != "document") + { + element[name] = properties[name]; + } + } + + return element; +}; + +this.createGlobalElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = FBL.Env.browser.document; + + var element = this.NS && doc.createElementNS ? + doc.createElementNS(FBL.NS, tagName) : + doc.createElement(tagName); + + for(var name in properties) + { + var propname = name; + if (FBL.isIE && name == "class") propname = "className"; + + if (name != "document") + { + element.setAttribute(propname, properties[name]); + } + } + + return element; +}; + +//************************************************************************************************ + +this.safeGetWindowLocation = function(window) +{ + try + { + if (window) + { + if (window.closed) + return "(window.closed)"; + if ("location" in window) + return window.location+""; + else + return "(no window.location)"; + } + else + return "(no context.window)"; + } + catch(exc) + { + if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS) + FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc); + FBTrace.sysout("TabContext.getWindowLocation failed window:", window); + return "(getWindowLocation: "+exc+")"; + } +}; + +// ************************************************************************************************ +// Events + +this.isLeftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && // others + this.noKeyModifiers(event); +}; + +this.isMiddleClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 4 : // IE "click" and "dblclick" button model + event.button == 1) && + this.noKeyModifiers(event); +}; + +this.isRightClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 2 : // IE "click" and "dblclick" button model + event.button == 2) && + this.noKeyModifiers(event); +}; + +this.noKeyModifiers = function(event) +{ + return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey; +}; + +this.isControlClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isControl(event); +}; + +this.isShiftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isShift(event); +}; + +this.isControl = function(event) +{ + return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; +}; + +this.isAlt = function(event) +{ + return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey; +}; + +this.isAltClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isAlt(event); +}; + +this.isControlShift = function(event) +{ + return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey; +}; + +this.isShift = function(event) +{ + return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey; +}; + +this.addEvent = function(object, name, handler, useCapture) +{ + if (object.addEventListener) + object.addEventListener(name, handler, useCapture); + else + object.attachEvent("on"+name, handler); +}; + +this.removeEvent = function(object, name, handler, useCapture) +{ + try + { + if (object.removeEventListener) + object.removeEventListener(name, handler, useCapture); + else + object.detachEvent("on"+name, handler); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("FBL.removeEvent error: ", object, name); + } +}; + +this.cancelEvent = function(e, preventDefault) +{ + if (!e) return; + + if (preventDefault) + { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + } + + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.addGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.addEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.addEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.addEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +this.removeGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.removeEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.removeEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.removeEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.dispatch = function(listeners, name, args) +{ + if (!listeners) return; + + try + {/**/ + if (typeof listeners.length != "undefined") + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); + + for (var i = 0; i < listeners.length; ++i) + { + var listener = listeners[i]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + else + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object"); + + for (var prop in listeners) + { + var listener = listeners[prop]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout(" Exception in lib.dispatch "+ name, exc); + //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener); + } + } + /**/ +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var disableTextSelectionHandler = function(event) +{ + FBL.cancelEvent(event, true); + + return false; +}; + +this.disableTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.addEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.addEvent(e, "mousedown", disableTextSelectionHandler); + } + + e.style.cursor = "default"; +}; + +this.restoreTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.removeEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "cursor: default;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.removeEvent(e, "mousedown", disableTextSelectionHandler); + } +}; + +// ************************************************************************************************ +// DOM Events + +var eventTypes = +{ + composition: [ + "composition", + "compositionstart", + "compositionend" ], + contextmenu: [ + "contextmenu" ], + drag: [ + "dragenter", + "dragover", + "dragexit", + "dragdrop", + "draggesture" ], + focus: [ + "focus", + "blur" ], + form: [ + "submit", + "reset", + "change", + "select", + "input" ], + key: [ + "keydown", + "keyup", + "keypress" ], + load: [ + "load", + "beforeunload", + "unload", + "abort", + "error" ], + mouse: [ + "mousedown", + "mouseup", + "click", + "dblclick", + "mouseover", + "mouseout", + "mousemove" ], + mutation: [ + "DOMSubtreeModified", + "DOMNodeInserted", + "DOMNodeRemoved", + "DOMNodeRemovedFromDocument", + "DOMNodeInsertedIntoDocument", + "DOMAttrModified", + "DOMCharacterDataModified" ], + paint: [ + "paint", + "resize", + "scroll" ], + scroll: [ + "overflow", + "underflow", + "overflowchanged" ], + text: [ + "text" ], + ui: [ + "DOMActivate", + "DOMFocusIn", + "DOMFocusOut" ], + xul: [ + "popupshowing", + "popupshown", + "popuphiding", + "popuphidden", + "close", + "command", + "broadcast", + "commandupdate" ] +}; + +this.getEventFamily = function(eventType) +{ + if (!this.families) + { + this.families = {}; + + for (var family in eventTypes) + { + var types = eventTypes[family]; + for (var i = 0; i < types.length; ++i) + this.families[types[i]] = family; + } + } + + return this.families[eventType]; +}; + + +// ************************************************************************************************ +// URLs + +this.getFileName = function(url) +{ + var split = this.splitURLBase(url); + return split.name; +}; + +this.splitURLBase = function(url) +{ + if (this.isDataURL(url)) + return this.splitDataURL(url); + return this.splitURLTrue(url); +}; + +this.splitDataURL = function(url) +{ + var mark = url.indexOf(':', 3); + if (mark != 4) + return false; // the first 5 chars must be 'data:' + + var point = url.indexOf(',', mark+1); + if (point < mark) + return false; // syntax error + + var props = { encodedContent: url.substr(point+1) }; + + var metadataBuffer = url.substr(mark+1, point); + var metadata = metadataBuffer.split(';'); + for (var i = 0; i < metadata.length; i++) + { + var nv = metadata[i].split('='); + if (nv.length == 2) + props[nv[0]] = nv[1]; + } + + // Additional Firebug-specific properties + if (props.hasOwnProperty('fileName')) + { + var caller_URL = decodeURIComponent(props['fileName']); + var caller_split = this.splitURLTrue(caller_URL); + + if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval() + { + props['path'] = caller_split.path; + props['line'] = props['baseLineNumber']; + var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + props['name'] = 'eval->'+hint; + } + else + { + props['name'] = caller_split.name; + props['path'] = caller_split.path; + } + } + else + { + if (!props.hasOwnProperty('path')) + props['path'] = "data:"; + if (!props.hasOwnProperty('name')) + props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + } + + return props; +}; + +this.splitURLTrue = function(url) +{ + var m = reSplitFile.exec(url); + if (!m) + return {name: url, path: url}; + else if (!m[2]) + return {path: m[1], name: m[1]}; + else + return {path: m[1], name: m[2]+m[3]}; +}; + +this.getFileExtension = function(url) +{ + if (!url) + return null; + + // Remove query string from the URL if any. + var queryString = url.indexOf("?"); + if (queryString != -1) + url = url.substr(0, queryString); + + // Now get the file extension. + var lastDot = url.lastIndexOf("."); + return url.substr(lastDot+1); +}; + +this.isSystemURL = function(url) +{ + if (!url) return true; + if (url.length == 0) return true; + if (url[0] == 'h') return false; + if (url.substr(0, 9) == "resource:") + return true; + else if (url.substr(0, 16) == "chrome://firebug") + return true; + else if (url == "XPCSafeJSObjectWrapper.cpp") + return true; + else if (url.substr(0, 6) == "about:") + return true; + else if (url.indexOf("firebug-service.js") != -1) + return true; + else + return false; +}; + +this.isSystemPage = function(win) +{ + try + { + var doc = win.document; + if (!doc) + return false; + + // Detect pages for pretty printed XML + if ((doc.styleSheets.length && doc.styleSheets[0].href + == "chrome://global/content/xml/XMLPrettyPrint.css") + || (doc.styleSheets.length > 1 && doc.styleSheets[1].href + == "chrome://browser/skin/feeds/subscribe.css")) + return true; + + return FBL.isSystemURL(win.location.href); + } + catch (exc) + { + // Sometimes documents just aren't ready to be manipulated here, but don't let that + // gum up the works + ERROR("tabWatcher.isSystemPage document not ready:"+ exc); + return false; + } +}; + +this.isSystemStyleSheet = function(sheet) +{ + var href = sheet && sheet.href; + return href && FBL.isSystemURL(href); +}; + +this.getURIHost = function(uri) +{ + try + { + if (uri) + return uri.host; + else + return ""; + } + catch (exc) + { + return ""; + } +}; + +this.isLocalURL = function(url) +{ + if (url.substr(0, 5) == "file:") + return true; + else if (url.substr(0, 8) == "wyciwyg:") + return true; + else + return false; +}; + +this.isDataURL = function(url) +{ + return (url && url.substr(0,5) == "data:"); +}; + +this.getLocalPath = function(url) +{ + if (this.isLocalURL(url)) + { + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var file = fileHandler.getFileFromURLSpec(url); + return file.path; + } +}; + +this.getURLFromLocalFile = function(file) +{ + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var URL = fileHandler.getURLSpecFromFile(file); + return URL; +}; + +this.getDataURLForContent = function(content, url) +{ + // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10, + var uri = "data:text/html;"; + uri += "fileName="+encodeURIComponent(url)+ ","; + uri += encodeURIComponent(content); + return uri; +}, + +this.getDomain = function(url) +{ + var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url); + return m ? m[1] : ""; +}; + +this.getURLPath = function(url) +{ + var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); + return m ? m[1] : ""; +}; + +this.getPrettyDomain = function(url) +{ + var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); + return m ? m[2] : ""; +}; + +this.absoluteURL = function(url, baseURL) +{ + return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g"); +}; + +this.absoluteURLWithDots = function(url, baseURL) +{ + if (url[0] == "?") + return baseURL + url; + + var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/; + var m = reURL.exec(url); + if (m) + return url; + + var m = reURL.exec(baseURL); + if (!m) + return ""; + + var head = m[1]; + var tail = m[3]; + if (url.substr(0, 2) == "//") + return m[2] + url; + else if (url[0] == "/") + { + return head + url; + } + else if (tail[tail.length-1] == "/") + return baseURL + url; + else + { + var parts = tail.split("/"); + return head + parts.slice(0, parts.length-1).join("/") + "/" + url; + } +}; + +this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome +{ + if (!url) + return ""; + // Replace one or more characters that are not forward-slash followed by /.., by space. + if (url.length < 255) // guard against monsters. + { + // Replace one or more characters that are not forward-slash followed by /.., by space. + url = url.replace(/[^\/]+\/\.\.\//, "", "g"); + // Issue 1496, avoid # + url = url.replace(/#.*/,""); + // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they + // don't match up with the URLs we get back from the DOM + url = url.replace(/file:\/([^\/])/g, "file:///$1"); + if (url.indexOf('chrome:')==0) + { + var m = reChromeCase.exec(url); // 1 is package name, 2 is path + if (m) + { + url = "chrome://"+m[1].toLowerCase()+"/"+m[2]; + } + } + } + return url; +}; + +this.denormalizeURL = function(url) +{ + return url.replace(/file:\/\/\//g, "file:/"); +}; + +this.parseURLParams = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedText(search); +}; + +this.parseURLEncodedText = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: ""}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +// TODO: xxxpedro lib. why loops in domplate are requiring array in parameters +// as in response/request headers and get/post parameters in Net module? +this.parseURLParamsArray = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedTextArray(search); +}; + +this.parseURLEncodedTextArray = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: [""]}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +this.reEncodeURL = function(file, text) +{ + var lines = text.split("\n"); + var params = this.parseURLEncodedText(lines[lines.length-1]); + + var args = []; + for (var i = 0; i < params.length; ++i) + args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); + + var url = file.href; + url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); + + return url; +}; + +this.getResource = function(aURL) +{ + try + { + var channel=ioService.newChannel(aURL,null,null); + var input=channel.open(); + return FBL.readFromStream(input); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getResource FAILS for "+aURL, e); + } +}; + +this.parseJSONString = function(jsonString, originURL) +{ + // See if this is a Prototype style *-secure request. + var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/); + var matches = regex.exec(jsonString); + + if (matches) + { + jsonString = matches[1]; + + if (jsonString[0] == "\\" && jsonString[1] == "n") + jsonString = jsonString.substr(2); + + if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") + jsonString = jsonString.substr(0, jsonString.length-2); + } + + if (jsonString.indexOf("&&&START&&&")) + { + regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); + matches = regex.exec(jsonString); + if (matches) + jsonString = matches[1]; + } + + // throw on the extra parentheses + jsonString = "(" + jsonString + ")"; + + ///var s = Components.utils.Sandbox(originURL); + var jsonObject = null; + + try + { + ///jsonObject = Components.utils.evalInSandbox(jsonString, s); + + //jsonObject = Firebug.context.eval(jsonString); + jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;}); + } + catch(e) + { + /*** + if (e.message.indexOf("is not defined")) + { + var parts = e.message.split(" "); + s[parts[0]] = function(str){ return str; }; + try { + jsonObject = Components.utils.evalInSandbox(jsonString, s); + } catch(ex) { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + } + } + else + {/**/ + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + ///} + } + + return jsonObject; +}; + +// ************************************************************************************************ + +this.objectToString = function(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +// Input Caret Position + +this.setSelectionRange = function(input, start, length) +{ + if (input.createTextRange) + { + var range = input.createTextRange(); + range.moveStart("character", start); + range.moveEnd("character", length - input.value.length); + range.select(); + } + else if (input.setSelectionRange) + { + input.setSelectionRange(start, length); + input.focus(); + } +}; + +// ************************************************************************************************ +// Input Selection Start / Caret Position + +this.getInputSelectionStart = function(input) +{ + if (document.selection) + { + var range = input.ownerDocument.selection.createRange(); + var text = range.text; + + //console.log("range", range.text); + + // if there is a selection, find the start position + if (text) + { + return input.value.indexOf(text); + } + // if there is no selection, find the caret position + else + { + range.moveStart("character", -input.value.length); + + return range.text.length; + } + } + else if (typeof input.selectionStart != "undefined") + return input.selectionStart; + + return 0; +}; + +// ************************************************************************************************ +// Opera Tab Fix + +function onOperaTabBlur(e) +{ + if (this.lastKey == 9) + this.focus(); +}; + +function onOperaTabKeyDown(e) +{ + this.lastKey = e.keyCode; +}; + +function onOperaTabFocus(e) +{ + this.lastKey = null; +}; + +this.fixOperaTabKey = function(el) +{ + el.onfocus = onOperaTabFocus; + el.onblur = onOperaTabBlur; + el.onkeydown = onOperaTabKeyDown; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.Property = function(object, name) +{ + this.object = object; + this.name = name; + + this.getObject = function() + { + return object[name]; + }; +}; + +this.ErrorCopy = function(message) +{ + this.message = message; +}; + +function EventCopy(event) +{ + // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to + // represent them long term in the inspector. + for (var name in event) + { + try { + this[name] = event[name]; + } catch (exc) { } + } +} + +this.EventCopy = EventCopy; + + +// ************************************************************************************************ +// Type Checking + +var toString = Object.prototype.toString; +var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; + +this.isArray = function(object) { + return toString.call(object) === '[object Array]'; +}; + +this.isFunction = function(object) { + if (!object) return false; + + return toString.call(object) === "[object Function]" || + this.isIE && typeof object != "string" && reFunction.test(""+object); +}; + + +// ************************************************************************************************ +// Instance Checking + +this.instanceOf = function(object, className) +{ + if (!object || typeof object != "object") + return false; + + // Try to use the native instanceof operator. We can only use it when we know + // exactly the window where the object is located at + if (object.ownerDocument) + { + // find the correct window of the object + var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow; + + // if the class is accessible in the window, uses the native instanceof operator + // if the instanceof evaluates to "true" we can assume it is a instance, but if it + // evaluates to "false" we must continue with the duck type detection below because + // the native object may be extended, thus breaking the instanceof result + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (className in win && object instanceof win[className]) + return true; + } + // If the object doesn't have the ownerDocument property, we'll try to look at + // the current context's window + else + { + // TODO: xxxpedro context + // Since we're not using yet a Firebug.context, we'll just use the top window + // (browser) as a reference + var win = Firebug.browser.window; + if (className in win) + return object instanceof win[className]; + } + + // get the duck type model from the cache + var cache = instanceCheckMap[className]; + if (!cache) + return false; + + // starts the hacky duck type detection + for(var n in cache) + { + var obj = cache[n]; + var type = typeof obj; + obj = type == "object" ? obj : [obj]; + + for(var name in obj) + { + // avoid problems with extended native objects + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (!obj.hasOwnProperty(name)) + continue; + + var value = obj[name]; + + if( n == "property" && !(value in object) || + n == "method" && !this.isFunction(object[value]) || + n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) + return false; + } + } + + return true; +}; + +var instanceCheckMap = +{ + // DuckTypeCheck: + // { + // property: ["window", "document"], + // method: "setTimeout", + // value: {nodeType: 1} + // }, + + Window: + { + property: ["window", "document"], + method: "setTimeout" + }, + + Document: + { + property: ["body", "cookie"], + method: "getElementById" + }, + + Node: + { + property: "ownerDocument", + method: "appendChild" + }, + + Element: + { + property: "tagName", + value: {nodeType: 1} + }, + + Location: + { + property: ["hostname", "protocol"], + method: "assign" + }, + + HTMLImageElement: + { + property: "useMap", + value: + { + nodeType: 1, + tagName: "img" + } + }, + + HTMLAnchorElement: + { + property: "hreflang", + value: + { + nodeType: 1, + tagName: "a" + } + }, + + HTMLInputElement: + { + property: "form", + value: + { + nodeType: 1, + tagName: "input" + } + }, + + HTMLButtonElement: + { + // ? + }, + + HTMLFormElement: + { + method: "submit", + value: + { + nodeType: 1, + tagName: "form" + } + }, + + HTMLBodyElement: + { + + }, + + HTMLHtmlElement: + { + + }, + + CSSStyleRule: + { + property: ["selectorText", "style"] + } + +}; + + +// ************************************************************************************************ +// DOM Constants + +/* + +Problems: + + - IE does not have window.Node, window.Element, etc + - for (var name in Node.prototype) return nothing on FF + +*/ + + +var domMemberMap2 = {}; + +var domMemberMap2Sandbox = null; + +var getDomMemberMap2 = function(name) +{ + if (!domMemberMap2Sandbox) + { + var doc = Firebug.chrome.document; + var frame = doc.createElement("iframe"); + + frame.id = "FirebugSandbox"; + frame.style.display = "none"; + frame.src = "about:blank"; + + doc.body.appendChild(frame); + + domMemberMap2Sandbox = frame.window || frame.contentWindow; + } + + var props = []; + + //var object = domMemberMap2Sandbox[name]; + //object = object.prototype || object; + + var object = null; + + if (name == "Window") + object = domMemberMap2Sandbox.window; + + else if (name == "Document") + object = domMemberMap2Sandbox.document; + + else if (name == "HTMLScriptElement") + object = domMemberMap2Sandbox.document.createElement("script"); + + else if (name == "HTMLAnchorElement") + object = domMemberMap2Sandbox.document.createElement("a"); + + else if (name.indexOf("Element") != -1) + { + object = domMemberMap2Sandbox.document.createElement("div"); + } + + if (object) + { + //object = object.prototype || object; + + //props = 'addEventListener,document,location,navigator,window'.split(','); + + for (var n in object) + props.push(n); + } + /**/ + + return props; + return extendArray(props, domMemberMap[name]); +}; + +// xxxpedro experimental get DOM members +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + FBL.domMemberCache = domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = getDomMemberMap2(name); + var cache = domMemberCache[name] = {}; + + /* + if (name.indexOf("Element") != -1) + { + this.append(cache, this.getDOMMembers("Node")); + this.append(cache, this.getDOMMembers("Element")); + } + /**/ + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument")) + { return domMemberCache.Document; } + else if (this.instanceOf(object, "Location")) + { return domMemberCache.Location; } + else if (this.instanceOf(object, "HTMLImageElement")) + { return domMemberCache.HTMLImageElement; } + else if (this.instanceOf(object, "HTMLAnchorElement")) + { return domMemberCache.HTMLAnchorElement; } + else if (this.instanceOf(object, "HTMLInputElement")) + { return domMemberCache.HTMLInputElement; } + else if (this.instanceOf(object, "HTMLButtonElement")) + { return domMemberCache.HTMLButtonElement; } + else if (this.instanceOf(object, "HTMLFormElement")) + { return domMemberCache.HTMLFormElement; } + else if (this.instanceOf(object, "HTMLBodyElement")) + { return domMemberCache.HTMLBodyElement; } + else if (this.instanceOf(object, "HTMLHtmlElement")) + { return domMemberCache.HTMLHtmlElement; } + else if (this.instanceOf(object, "HTMLScriptElement")) + { return domMemberCache.HTMLScriptElement; } + else if (this.instanceOf(object, "HTMLTableElement")) + { return domMemberCache.HTMLTableElement; } + else if (this.instanceOf(object, "HTMLTableRowElement")) + { return domMemberCache.HTMLTableRowElement; } + else if (this.instanceOf(object, "HTMLTableCellElement")) + { return domMemberCache.HTMLTableCellElement; } + else if (this.instanceOf(object, "HTMLIFrameElement")) + { return domMemberCache.HTMLIFrameElement; } + else if (this.instanceOf(object, "SVGSVGElement")) + { return domMemberCache.SVGSVGElement; } + else if (this.instanceOf(object, "SVGElement")) + { return domMemberCache.SVGElement; } + else if (this.instanceOf(object, "Element")) + { return domMemberCache.Element; } + else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection")) + { return domMemberCache.Text; } + else if (this.instanceOf(object, "Attr")) + { return domMemberCache.Attr; } + else if (this.instanceOf(object, "Node")) + { return domMemberCache.Node; } + else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy")) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getDOMMembers FAILED ", E); + + return {}; + } +}; + + +/* +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = domMemberMap[name]; + var cache = domMemberCache[name] = {}; + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (object instanceof Document || object instanceof XMLDocument) + { return domMemberCache.Document; } + else if (object instanceof Location) + { return domMemberCache.Location; } + else if (object instanceof HTMLImageElement) + { return domMemberCache.HTMLImageElement; } + else if (object instanceof HTMLAnchorElement) + { return domMemberCache.HTMLAnchorElement; } + else if (object instanceof HTMLInputElement) + { return domMemberCache.HTMLInputElement; } + else if (object instanceof HTMLButtonElement) + { return domMemberCache.HTMLButtonElement; } + else if (object instanceof HTMLFormElement) + { return domMemberCache.HTMLFormElement; } + else if (object instanceof HTMLBodyElement) + { return domMemberCache.HTMLBodyElement; } + else if (object instanceof HTMLHtmlElement) + { return domMemberCache.HTMLHtmlElement; } + else if (object instanceof HTMLScriptElement) + { return domMemberCache.HTMLScriptElement; } + else if (object instanceof HTMLTableElement) + { return domMemberCache.HTMLTableElement; } + else if (object instanceof HTMLTableRowElement) + { return domMemberCache.HTMLTableRowElement; } + else if (object instanceof HTMLTableCellElement) + { return domMemberCache.HTMLTableCellElement; } + else if (object instanceof HTMLIFrameElement) + { return domMemberCache.HTMLIFrameElement; } + else if (object instanceof SVGSVGElement) + { return domMemberCache.SVGSVGElement; } + else if (object instanceof SVGElement) + { return domMemberCache.SVGElement; } + else if (object instanceof Element) + { return domMemberCache.Element; } + else if (object instanceof Text || object instanceof CDATASection) + { return domMemberCache.Text; } + else if (object instanceof Attr) + { return domMemberCache.Attr; } + else if (object instanceof Node) + { return domMemberCache.Node; } + else if (object instanceof Event || object instanceof EventCopy) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + return {}; + } +}; +/**/ + +this.isDOMMember = function(object, propName) +{ + var members = this.getDOMMembers(object); + return members && propName in members; +}; + +var domMemberCache = null; +var domMemberMap = {}; + +domMemberMap.Window = +[ + "document", + "frameElement", + + "innerWidth", + "innerHeight", + "outerWidth", + "outerHeight", + "screenX", + "screenY", + "pageXOffset", + "pageYOffset", + "scrollX", + "scrollY", + "scrollMaxX", + "scrollMaxY", + + "status", + "defaultStatus", + + "parent", + "opener", + "top", + "window", + "content", + "self", + + "location", + "history", + "frames", + "navigator", + "screen", + "menubar", + "toolbar", + "locationbar", + "personalbar", + "statusbar", + "directories", + "scrollbars", + "fullScreen", + "netscape", + "java", + "console", + "Components", + "controllers", + "closed", + "crypto", + "pkcs11", + + "name", + "property", + "length", + + "sessionStorage", + "globalStorage", + + "setTimeout", + "setInterval", + "clearTimeout", + "clearInterval", + "addEventListener", + "removeEventListener", + "dispatchEvent", + "getComputedStyle", + "captureEvents", + "releaseEvents", + "routeEvent", + "enableExternalCapture", + "disableExternalCapture", + "moveTo", + "moveBy", + "resizeTo", + "resizeBy", + "scroll", + "scrollTo", + "scrollBy", + "scrollByLines", + "scrollByPages", + "sizeToContent", + "setResizable", + "getSelection", + "open", + "openDialog", + "close", + "alert", + "confirm", + "prompt", + "dump", + "focus", + "blur", + "find", + "back", + "forward", + "home", + "stop", + "print", + "atob", + "btoa", + "updateCommands", + "XPCNativeWrapper", + "GeckoActiveXObject", + "applicationCache" // FF3 +]; + +domMemberMap.Location = +[ + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + + "assign", + "reload", + "replace" +]; + +domMemberMap.Node = +[ + "id", + "className", + + "nodeType", + "tagName", + "nodeName", + "localName", + "prefix", + "namespaceURI", + "nodeValue", + + "ownerDocument", + "parentNode", + "offsetParent", + "nextSibling", + "previousSibling", + "firstChild", + "lastChild", + "childNodes", + "attributes", + + "dir", + "baseURI", + "textContent", + "innerHTML", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]; + +domMemberMap.Document = extendArray(domMemberMap.Node, +[ + "documentElement", + "body", + "title", + "location", + "referrer", + "cookie", + "contentType", + "lastModified", + "characterSet", + "inputEncoding", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "strictErrorChecking", + "documentURI", + "URL", + + "defaultView", + "doctype", + "implementation", + "styleSheets", + "images", + "links", + "forms", + "anchors", + "embeds", + "plugins", + "applets", + + "width", + "height", + + "designMode", + "compatMode", + "async", + "preferredStylesheetSet", + + "alinkColor", + "linkColor", + "vlinkColor", + "bgColor", + "fgColor", + "domain", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "captureEvents", + "releaseEvents", + "routeEvent", + "clear", + "open", + "close", + "execCommand", + "execCommandShowHelp", + "getElementsByName", + "getSelection", + "queryCommandEnabled", + "queryCommandIndeterm", + "queryCommandState", + "queryCommandSupported", + "queryCommandText", + "queryCommandValue", + "write", + "writeln", + "adoptNode", + "appendChild", + "removeChild", + "renameNode", + "cloneNode", + "compareDocumentPosition", + "createAttribute", + "createAttributeNS", + "createCDATASection", + "createComment", + "createDocumentFragment", + "createElement", + "createElementNS", + "createEntityReference", + "createEvent", + "createExpression", + "createNSResolver", + "createNodeIterator", + "createProcessingInstruction", + "createRange", + "createTextNode", + "createTreeWalker", + "domConfig", + "evaluate", + "evaluateFIXptr", + "evaluateXPointer", + "getAnonymousElementByAttribute", + "getAnonymousNodes", + "addBinding", + "removeBinding", + "getBindingParent", + "getBoxObjectFor", + "setBoxObjectFor", + "getElementById", + "getElementsByTagName", + "getElementsByTagNameNS", + "hasAttributes", + "hasChildNodes", + "importNode", + "insertBefore", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "load", + "loadBindingDocument", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "normalizeDocument", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.Element = extendArray(domMemberMap.Node, +[ + "clientWidth", + "clientHeight", + "offsetLeft", + "offsetTop", + "offsetWidth", + "offsetHeight", + "scrollLeft", + "scrollTop", + "scrollWidth", + "scrollHeight", + + "style", + + "tabIndex", + "title", + "lang", + "align", + "spellcheck", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "focus", + "blur", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "getElementsByTagName", + "getElementsByTagNameNS", + "getAttribute", + "getAttributeNS", + "getAttributeNode", + "getAttributeNodeNS", + "setAttribute", + "setAttributeNS", + "setAttributeNode", + "setAttributeNodeNS", + "removeAttribute", + "removeAttributeNS", + "removeAttributeNode", + "hasAttribute", + "hasAttributeNS", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.SVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + "href", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getPresentationAttribute", + "preserveAspectRatio" +]); + +domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + + "viewBox", + "viewport", + "currentView", + "useCurrentView", + "pixelUnitToMillimeterX", + "pixelUnitToMillimeterY", + "screenPixelToMillimeterX", + "screenPixelToMillimeterY", + "currentScale", + "currentTranslate", + "zoomAndPan", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + "contentScriptType", + "contentStyleType", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getEnclosureList", + "getIntersectionList", + "getViewboxToViewportTransform", + "getPresentationAttribute", + "getElementById", + "checkEnclosure", + "checkIntersection", + "createSVGAngle", + "createSVGLength", + "createSVGMatrix", + "createSVGNumber", + "createSVGPoint", + "createSVGRect", + "createSVGString", + "createSVGTransform", + "createSVGTransformFromMatrix", + "deSelectAll", + "preserveAspectRatio", + "forceRedraw", + "suspendRedraw", + "unsuspendRedraw", + "unsuspendRedrawAll", + "getCurrentTime", + "setCurrentTime", + "animationsPaused", + "pauseAnimations", + "unpauseAnimations" +]); + +domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element, +[ + "src", + "naturalWidth", + "naturalHeight", + "width", + "height", + "x", + "y", + "name", + "alt", + "longDesc", + "lowsrc", + "border", + "complete", + "hspace", + "vspace", + "isMap", + "useMap" +]); + +domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element, +[ + "name", + "target", + "accessKey", + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + "hreflang", + "coords", + "shape", + "text", + "type", + "rel", + "rev", + "charset" +]); + +domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element, +[ + "contentDocument", + "contentWindow", + "frameBorder", + "height", + "longDesc", + "marginHeight", + "marginWidth", + "name", + "scrolling", + "src", + "width" +]); + +domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "border", + "caption", + "cellPadding", + "cellSpacing", + "frame", + "rows", + "rules", + "summary", + "tBodies", + "tFoot", + "tHead", + "width", + + "createCaption", + "createTFoot", + "createTHead", + "deleteCaption", + "deleteRow", + "deleteTFoot", + "deleteTHead", + "insertRow" +]); + +domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "cells", + "ch", + "chOff", + "rowIndex", + "sectionRowIndex", + "vAlign", + + "deleteCell", + "insertCell" +]); + +domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element, +[ + "abbr", + "axis", + "bgColor", + "cellIndex", + "ch", + "chOff", + "colSpan", + "headers", + "height", + "noWrap", + "rowSpan", + "scope", + "vAlign", + "width" + +]); + +domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element, +[ + "src" +]); + +domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element, +[ + "accessKey", + "disabled", + "form", + "name", + "type", + "value", + + "click" +]); + +domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element, +[ + "type", + "value", + "checked", + "accept", + "accessKey", + "alt", + "controllers", + "defaultChecked", + "defaultValue", + "disabled", + "form", + "maxLength", + "name", + "readOnly", + "selectionEnd", + "selectionStart", + "size", + "src", + "textLength", + "useMap", + + "click", + "select", + "setSelectionRange" +]); + +domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element, +[ + "acceptCharset", + "action", + "author", + "elements", + "encoding", + "enctype", + "entry_id", + "length", + "method", + "name", + "post", + "target", + "text", + "url", + + "reset", + "submit" +]); + +domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element, +[ + "aLink", + "background", + "bgColor", + "link", + "text", + "vLink" +]); + +domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element, +[ + "version" +]); + +domMemberMap.Text = extendArray(domMemberMap.Node, +[ + "data", + "length", + + "appendData", + "deleteData", + "insertData", + "replaceData", + "splitText", + "substringData" +]); + +domMemberMap.Attr = extendArray(domMemberMap.Node, +[ + "name", + "value", + "specified", + "ownerElement" +]); + +domMemberMap.Event = +[ + "type", + "target", + "currentTarget", + "originalTarget", + "explicitOriginalTarget", + "relatedTarget", + "rangeParent", + "rangeOffset", + "view", + + "keyCode", + "charCode", + "screenX", + "screenY", + "clientX", + "clientY", + "layerX", + "layerY", + "pageX", + "pageY", + + "detail", + "button", + "which", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + + "eventPhase", + "timeStamp", + "bubbles", + "cancelable", + "cancelBubble", + + "isTrusted", + "isChar", + + "getPreventDefault", + "initEvent", + "initMouseEvent", + "initKeyEvent", + "initUIEvent", + "preventBubble", + "preventCapture", + "preventDefault", + "stopPropagation" +]; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.domConstantMap = +{ + "ELEMENT_NODE": 1, + "ATTRIBUTE_NODE": 1, + "TEXT_NODE": 1, + "CDATA_SECTION_NODE": 1, + "ENTITY_REFERENCE_NODE": 1, + "ENTITY_NODE": 1, + "PROCESSING_INSTRUCTION_NODE": 1, + "COMMENT_NODE": 1, + "DOCUMENT_NODE": 1, + "DOCUMENT_TYPE_NODE": 1, + "DOCUMENT_FRAGMENT_NODE": 1, + "NOTATION_NODE": 1, + + "DOCUMENT_POSITION_DISCONNECTED": 1, + "DOCUMENT_POSITION_PRECEDING": 1, + "DOCUMENT_POSITION_FOLLOWING": 1, + "DOCUMENT_POSITION_CONTAINS": 1, + "DOCUMENT_POSITION_CONTAINED_BY": 1, + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1, + + "UNKNOWN_RULE": 1, + "STYLE_RULE": 1, + "CHARSET_RULE": 1, + "IMPORT_RULE": 1, + "MEDIA_RULE": 1, + "FONT_FACE_RULE": 1, + "PAGE_RULE": 1, + + "CAPTURING_PHASE": 1, + "AT_TARGET": 1, + "BUBBLING_PHASE": 1, + + "SCROLL_PAGE_UP": 1, + "SCROLL_PAGE_DOWN": 1, + + "MOUSEUP": 1, + "MOUSEDOWN": 1, + "MOUSEOVER": 1, + "MOUSEOUT": 1, + "MOUSEMOVE": 1, + "MOUSEDRAG": 1, + "CLICK": 1, + "DBLCLICK": 1, + "KEYDOWN": 1, + "KEYUP": 1, + "KEYPRESS": 1, + "DRAGDROP": 1, + "FOCUS": 1, + "BLUR": 1, + "SELECT": 1, + "CHANGE": 1, + "RESET": 1, + "SUBMIT": 1, + "SCROLL": 1, + "LOAD": 1, + "UNLOAD": 1, + "XFER_DONE": 1, + "ABORT": 1, + "ERROR": 1, + "LOCATE": 1, + "MOVE": 1, + "RESIZE": 1, + "FORWARD": 1, + "HELP": 1, + "BACK": 1, + "TEXT": 1, + + "ALT_MASK": 1, + "CONTROL_MASK": 1, + "SHIFT_MASK": 1, + "META_MASK": 1, + + "DOM_VK_TAB": 1, + "DOM_VK_PAGE_UP": 1, + "DOM_VK_PAGE_DOWN": 1, + "DOM_VK_UP": 1, + "DOM_VK_DOWN": 1, + "DOM_VK_LEFT": 1, + "DOM_VK_RIGHT": 1, + "DOM_VK_CANCEL": 1, + "DOM_VK_HELP": 1, + "DOM_VK_BACK_SPACE": 1, + "DOM_VK_CLEAR": 1, + "DOM_VK_RETURN": 1, + "DOM_VK_ENTER": 1, + "DOM_VK_SHIFT": 1, + "DOM_VK_CONTROL": 1, + "DOM_VK_ALT": 1, + "DOM_VK_PAUSE": 1, + "DOM_VK_CAPS_LOCK": 1, + "DOM_VK_ESCAPE": 1, + "DOM_VK_SPACE": 1, + "DOM_VK_END": 1, + "DOM_VK_HOME": 1, + "DOM_VK_PRINTSCREEN": 1, + "DOM_VK_INSERT": 1, + "DOM_VK_DELETE": 1, + "DOM_VK_0": 1, + "DOM_VK_1": 1, + "DOM_VK_2": 1, + "DOM_VK_3": 1, + "DOM_VK_4": 1, + "DOM_VK_5": 1, + "DOM_VK_6": 1, + "DOM_VK_7": 1, + "DOM_VK_8": 1, + "DOM_VK_9": 1, + "DOM_VK_SEMICOLON": 1, + "DOM_VK_EQUALS": 1, + "DOM_VK_A": 1, + "DOM_VK_B": 1, + "DOM_VK_C": 1, + "DOM_VK_D": 1, + "DOM_VK_E": 1, + "DOM_VK_F": 1, + "DOM_VK_G": 1, + "DOM_VK_H": 1, + "DOM_VK_I": 1, + "DOM_VK_J": 1, + "DOM_VK_K": 1, + "DOM_VK_L": 1, + "DOM_VK_M": 1, + "DOM_VK_N": 1, + "DOM_VK_O": 1, + "DOM_VK_P": 1, + "DOM_VK_Q": 1, + "DOM_VK_R": 1, + "DOM_VK_S": 1, + "DOM_VK_T": 1, + "DOM_VK_U": 1, + "DOM_VK_V": 1, + "DOM_VK_W": 1, + "DOM_VK_X": 1, + "DOM_VK_Y": 1, + "DOM_VK_Z": 1, + "DOM_VK_CONTEXT_MENU": 1, + "DOM_VK_NUMPAD0": 1, + "DOM_VK_NUMPAD1": 1, + "DOM_VK_NUMPAD2": 1, + "DOM_VK_NUMPAD3": 1, + "DOM_VK_NUMPAD4": 1, + "DOM_VK_NUMPAD5": 1, + "DOM_VK_NUMPAD6": 1, + "DOM_VK_NUMPAD7": 1, + "DOM_VK_NUMPAD8": 1, + "DOM_VK_NUMPAD9": 1, + "DOM_VK_MULTIPLY": 1, + "DOM_VK_ADD": 1, + "DOM_VK_SEPARATOR": 1, + "DOM_VK_SUBTRACT": 1, + "DOM_VK_DECIMAL": 1, + "DOM_VK_DIVIDE": 1, + "DOM_VK_F1": 1, + "DOM_VK_F2": 1, + "DOM_VK_F3": 1, + "DOM_VK_F4": 1, + "DOM_VK_F5": 1, + "DOM_VK_F6": 1, + "DOM_VK_F7": 1, + "DOM_VK_F8": 1, + "DOM_VK_F9": 1, + "DOM_VK_F10": 1, + "DOM_VK_F11": 1, + "DOM_VK_F12": 1, + "DOM_VK_F13": 1, + "DOM_VK_F14": 1, + "DOM_VK_F15": 1, + "DOM_VK_F16": 1, + "DOM_VK_F17": 1, + "DOM_VK_F18": 1, + "DOM_VK_F19": 1, + "DOM_VK_F20": 1, + "DOM_VK_F21": 1, + "DOM_VK_F22": 1, + "DOM_VK_F23": 1, + "DOM_VK_F24": 1, + "DOM_VK_NUM_LOCK": 1, + "DOM_VK_SCROLL_LOCK": 1, + "DOM_VK_COMMA": 1, + "DOM_VK_PERIOD": 1, + "DOM_VK_SLASH": 1, + "DOM_VK_BACK_QUOTE": 1, + "DOM_VK_OPEN_BRACKET": 1, + "DOM_VK_BACK_SLASH": 1, + "DOM_VK_CLOSE_BRACKET": 1, + "DOM_VK_QUOTE": 1, + "DOM_VK_META": 1, + + "SVG_ZOOMANDPAN_DISABLE": 1, + "SVG_ZOOMANDPAN_MAGNIFY": 1, + "SVG_ZOOMANDPAN_UNKNOWN": 1 +}; + +this.cssInfo = +{ + "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"], + "background-attachment": ["bgAttachment"], + "background-color": ["color", "systemColor"], + "background-image": ["none"], + "background-position": ["bgPosition"], + "background-repeat": ["bgRepeat"], + + "border": ["borderStyle", "thickness", "color", "systemColor", "none"], + "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-collapse": ["borderCollapse"], + "border-color": ["color", "systemColor"], + "border-top-color": ["color", "systemColor"], + "border-right-color": ["color", "systemColor"], + "border-bottom-color": ["color", "systemColor"], + "border-left-color": ["color", "systemColor"], + "border-spacing": [], + "border-style": ["borderStyle"], + "border-top-style": ["borderStyle"], + "border-right-style": ["borderStyle"], + "border-bottom-style": ["borderStyle"], + "border-left-style": ["borderStyle"], + "border-width": ["thickness"], + "border-top-width": ["thickness"], + "border-right-width": ["thickness"], + "border-bottom-width": ["thickness"], + "border-left-width": ["thickness"], + + "bottom": ["auto"], + "caption-side": ["captionSide"], + "clear": ["clear", "none"], + "clip": ["auto"], + "color": ["color", "systemColor"], + "content": ["content"], + "counter-increment": ["none"], + "counter-reset": ["none"], + "cursor": ["cursor", "none"], + "direction": ["direction"], + "display": ["display", "none"], + "empty-cells": [], + "float": ["float", "none"], + "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"], + + "font-family": ["fontFamily"], + "font-size": ["fontSize"], + "font-size-adjust": [], + "font-stretch": [], + "font-style": ["fontStyle"], + "font-variant": ["fontVariant"], + "font-weight": ["fontWeight"], + + "height": ["auto"], + "left": ["auto"], + "letter-spacing": [], + "line-height": [], + + "list-style": ["listStyleType", "listStylePosition", "none"], + "list-style-image": ["none"], + "list-style-position": ["listStylePosition"], + "list-style-type": ["listStyleType", "none"], + + "margin": [], + "margin-top": [], + "margin-right": [], + "margin-bottom": [], + "margin-left": [], + + "marker-offset": ["auto"], + "min-height": ["none"], + "max-height": ["none"], + "min-width": ["none"], + "max-width": ["none"], + + "outline": ["borderStyle", "color", "systemColor", "none"], + "outline-color": ["color", "systemColor"], + "outline-style": ["borderStyle"], + "outline-width": [], + + "overflow": ["overflow", "auto"], + "overflow-x": ["overflow", "auto"], + "overflow-y": ["overflow", "auto"], + + "padding": [], + "padding-top": [], + "padding-right": [], + "padding-bottom": [], + "padding-left": [], + + "position": ["position"], + "quotes": ["none"], + "right": ["auto"], + "table-layout": ["tableLayout", "auto"], + "text-align": ["textAlign"], + "text-decoration": ["textDecoration", "none"], + "text-indent": [], + "text-shadow": [], + "text-transform": ["textTransform", "none"], + "top": ["auto"], + "unicode-bidi": [], + "vertical-align": ["verticalAlign"], + "white-space": ["whiteSpace"], + "width": ["auto"], + "word-spacing": [], + "z-index": [], + + "-moz-appearance": ["mozAppearance"], + "-moz-border-radius": [], + "-moz-border-radius-bottomleft": [], + "-moz-border-radius-bottomright": [], + "-moz-border-radius-topleft": [], + "-moz-border-radius-topright": [], + "-moz-border-top-colors": ["color", "systemColor"], + "-moz-border-right-colors": ["color", "systemColor"], + "-moz-border-bottom-colors": ["color", "systemColor"], + "-moz-border-left-colors": ["color", "systemColor"], + "-moz-box-align": ["mozBoxAlign"], + "-moz-box-direction": ["mozBoxDirection"], + "-moz-box-flex": [], + "-moz-box-ordinal-group": [], + "-moz-box-orient": ["mozBoxOrient"], + "-moz-box-pack": ["mozBoxPack"], + "-moz-box-sizing": ["mozBoxSizing"], + "-moz-opacity": [], + "-moz-user-focus": ["userFocus", "none"], + "-moz-user-input": ["userInput"], + "-moz-user-modify": [], + "-moz-user-select": ["userSelect", "none"], + "-moz-background-clip": [], + "-moz-background-inline-policy": [], + "-moz-background-origin": [], + "-moz-binding": [], + "-moz-column-count": [], + "-moz-column-gap": [], + "-moz-column-width": [], + "-moz-image-region": [] +}; + +this.inheritedStyleNames = +{ + "border-collapse": 1, + "border-spacing": 1, + "border-style": 1, + "caption-side": 1, + "color": 1, + "cursor": 1, + "direction": 1, + "empty-cells": 1, + "font": 1, + "font-family": 1, + "font-size-adjust": 1, + "font-size": 1, + "font-style": 1, + "font-variant": 1, + "font-weight": 1, + "letter-spacing": 1, + "line-height": 1, + "list-style": 1, + "list-style-image": 1, + "list-style-position": 1, + "list-style-type": 1, + "quotes": 1, + "text-align": 1, + "text-decoration": 1, + "text-indent": 1, + "text-shadow": 1, + "text-transform": 1, + "white-space": 1, + "word-spacing": 1 +}; + +this.cssKeywords = +{ + "appearance": + [ + "button", + "button-small", + "checkbox", + "checkbox-container", + "checkbox-small", + "dialog", + "listbox", + "menuitem", + "menulist", + "menulist-button", + "menulist-textfield", + "menupopup", + "progressbar", + "radio", + "radio-container", + "radio-small", + "resizer", + "scrollbar", + "scrollbarbutton-down", + "scrollbarbutton-left", + "scrollbarbutton-right", + "scrollbarbutton-up", + "scrollbartrack-horizontal", + "scrollbartrack-vertical", + "separator", + "statusbar", + "tab", + "tab-left-edge", + "tabpanels", + "textfield", + "toolbar", + "toolbarbutton", + "toolbox", + "tooltip", + "treeheadercell", + "treeheadersortarrow", + "treeitem", + "treetwisty", + "treetwistyopen", + "treeview", + "window" + ], + + "systemColor": + [ + "ActiveBorder", + "ActiveCaption", + "AppWorkspace", + "Background", + "ButtonFace", + "ButtonHighlight", + "ButtonShadow", + "ButtonText", + "CaptionText", + "GrayText", + "Highlight", + "HighlightText", + "InactiveBorder", + "InactiveCaption", + "InactiveCaptionText", + "InfoBackground", + "InfoText", + "Menu", + "MenuText", + "Scrollbar", + "ThreeDDarkShadow", + "ThreeDFace", + "ThreeDHighlight", + "ThreeDLightShadow", + "ThreeDShadow", + "Window", + "WindowFrame", + "WindowText", + "-moz-field", + "-moz-fieldtext", + "-moz-workspace", + "-moz-visitedhyperlinktext", + "-moz-use-text-color" + ], + + "color": + [ + "AliceBlue", + "AntiqueWhite", + "Aqua", + "Aquamarine", + "Azure", + "Beige", + "Bisque", + "Black", + "BlanchedAlmond", + "Blue", + "BlueViolet", + "Brown", + "BurlyWood", + "CadetBlue", + "Chartreuse", + "Chocolate", + "Coral", + "CornflowerBlue", + "Cornsilk", + "Crimson", + "Cyan", + "DarkBlue", + "DarkCyan", + "DarkGoldenRod", + "DarkGray", + "DarkGreen", + "DarkKhaki", + "DarkMagenta", + "DarkOliveGreen", + "DarkOrange", + "DarkOrchid", + "DarkRed", + "DarkSalmon", + "DarkSeaGreen", + "DarkSlateBlue", + "DarkSlateGray", + "DarkTurquoise", + "DarkViolet", + "DeepPink", + "DarkSkyBlue", + "DimGray", + "DodgerBlue", + "Feldspar", + "FireBrick", + "FloralWhite", + "ForestGreen", + "Fuchsia", + "Gainsboro", + "GhostWhite", + "Gold", + "GoldenRod", + "Gray", + "Green", + "GreenYellow", + "HoneyDew", + "HotPink", + "IndianRed", + "Indigo", + "Ivory", + "Khaki", + "Lavender", + "LavenderBlush", + "LawnGreen", + "LemonChiffon", + "LightBlue", + "LightCoral", + "LightCyan", + "LightGoldenRodYellow", + "LightGrey", + "LightGreen", + "LightPink", + "LightSalmon", + "LightSeaGreen", + "LightSkyBlue", + "LightSlateBlue", + "LightSlateGray", + "LightSteelBlue", + "LightYellow", + "Lime", + "LimeGreen", + "Linen", + "Magenta", + "Maroon", + "MediumAquaMarine", + "MediumBlue", + "MediumOrchid", + "MediumPurple", + "MediumSeaGreen", + "MediumSlateBlue", + "MediumSpringGreen", + "MediumTurquoise", + "MediumVioletRed", + "MidnightBlue", + "MintCream", + "MistyRose", + "Moccasin", + "NavajoWhite", + "Navy", + "OldLace", + "Olive", + "OliveDrab", + "Orange", + "OrangeRed", + "Orchid", + "PaleGoldenRod", + "PaleGreen", + "PaleTurquoise", + "PaleVioletRed", + "PapayaWhip", + "PeachPuff", + "Peru", + "Pink", + "Plum", + "PowderBlue", + "Purple", + "Red", + "RosyBrown", + "RoyalBlue", + "SaddleBrown", + "Salmon", + "SandyBrown", + "SeaGreen", + "SeaShell", + "Sienna", + "Silver", + "SkyBlue", + "SlateBlue", + "SlateGray", + "Snow", + "SpringGreen", + "SteelBlue", + "Tan", + "Teal", + "Thistle", + "Tomato", + "Turquoise", + "Violet", + "VioletRed", + "Wheat", + "White", + "WhiteSmoke", + "Yellow", + "YellowGreen", + "transparent", + "invert" + ], + + "auto": + [ + "auto" + ], + + "none": + [ + "none" + ], + + "captionSide": + [ + "top", + "bottom", + "left", + "right" + ], + + "clear": + [ + "left", + "right", + "both" + ], + + "cursor": + [ + "auto", + "cell", + "context-menu", + "crosshair", + "default", + "help", + "pointer", + "progress", + "move", + "e-resize", + "all-scroll", + "ne-resize", + "nw-resize", + "n-resize", + "se-resize", + "sw-resize", + "s-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "text", + "vertical-text", + "wait", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "-moz-alias", + "-moz-cell", + "-moz-copy", + "-moz-grab", + "-moz-grabbing", + "-moz-contextmenu", + "-moz-zoom-in", + "-moz-zoom-out", + "-moz-spinning" + ], + + "direction": + [ + "ltr", + "rtl" + ], + + "bgAttachment": + [ + "scroll", + "fixed" + ], + + "bgPosition": + [ + "top", + "center", + "bottom", + "left", + "right" + ], + + "bgRepeat": + [ + "repeat", + "repeat-x", + "repeat-y", + "no-repeat" + ], + + "borderStyle": + [ + "hidden", + "dotted", + "dashed", + "solid", + "double", + "groove", + "ridge", + "inset", + "outset", + "-moz-bg-inset", + "-moz-bg-outset", + "-moz-bg-solid" + ], + + "borderCollapse": + [ + "collapse", + "separate" + ], + + "overflow": + [ + "visible", + "hidden", + "scroll", + "-moz-scrollbars-horizontal", + "-moz-scrollbars-none", + "-moz-scrollbars-vertical" + ], + + "listStyleType": + [ + "disc", + "circle", + "square", + "decimal", + "decimal-leading-zero", + "lower-roman", + "upper-roman", + "lower-greek", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "hebrew", + "armenian", + "georgian", + "cjk-ideographic", + "hiragana", + "katakana", + "hiragana-iroha", + "katakana-iroha", + "inherit" + ], + + "listStylePosition": + [ + "inside", + "outside" + ], + + "content": + [ + "open-quote", + "close-quote", + "no-open-quote", + "no-close-quote", + "inherit" + ], + + "fontStyle": + [ + "normal", + "italic", + "oblique", + "inherit" + ], + + "fontVariant": + [ + "normal", + "small-caps", + "inherit" + ], + + "fontWeight": + [ + "normal", + "bold", + "bolder", + "lighter", + "inherit" + ], + + "fontSize": + [ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger" + ], + + "fontFamily": + [ + "Arial", + "Comic Sans MS", + "Georgia", + "Tahoma", + "Verdana", + "Times New Roman", + "Trebuchet MS", + "Lucida Grande", + "Helvetica", + "serif", + "sans-serif", + "cursive", + "fantasy", + "monospace", + "caption", + "icon", + "menu", + "message-box", + "small-caption", + "status-bar", + "inherit" + ], + + "display": + [ + "block", + "inline", + "inline-block", + "list-item", + "marker", + "run-in", + "compact", + "table", + "inline-table", + "table-row-group", + "table-column", + "table-column-group", + "table-header-group", + "table-footer-group", + "table-row", + "table-cell", + "table-caption", + "-moz-box", + "-moz-compact", + "-moz-deck", + "-moz-grid", + "-moz-grid-group", + "-moz-grid-line", + "-moz-groupbox", + "-moz-inline-block", + "-moz-inline-box", + "-moz-inline-grid", + "-moz-inline-stack", + "-moz-inline-table", + "-moz-marker", + "-moz-popup", + "-moz-runin", + "-moz-stack" + ], + + "position": + [ + "static", + "relative", + "absolute", + "fixed", + "inherit" + ], + + "float": + [ + "left", + "right" + ], + + "textAlign": + [ + "left", + "right", + "center", + "justify" + ], + + "tableLayout": + [ + "fixed" + ], + + "textDecoration": + [ + "underline", + "overline", + "line-through", + "blink" + ], + + "textTransform": + [ + "capitalize", + "lowercase", + "uppercase", + "inherit" + ], + + "unicodeBidi": + [ + "normal", + "embed", + "bidi-override" + ], + + "whiteSpace": + [ + "normal", + "pre", + "nowrap" + ], + + "verticalAlign": + [ + "baseline", + "sub", + "super", + "top", + "text-top", + "middle", + "bottom", + "text-bottom", + "inherit" + ], + + "thickness": + [ + "thin", + "medium", + "thick" + ], + + "userFocus": + [ + "ignore", + "normal" + ], + + "userInput": + [ + "disabled", + "enabled" + ], + + "userSelect": + [ + "normal" + ], + + "mozBoxSizing": + [ + "content-box", + "padding-box", + "border-box" + ], + + "mozBoxAlign": + [ + "start", + "center", + "end", + "baseline", + "stretch" + ], + + "mozBoxDirection": + [ + "normal", + "reverse" + ], + + "mozBoxOrient": + [ + "horizontal", + "vertical" + ], + + "mozBoxPack": + [ + "start", + "center", + "end" + ] +}; + +this.nonEditableTags = +{ + "HTML": 1, + "HEAD": 1, + "html": 1, + "head": 1 +}; + +this.innerEditableTags = +{ + "BODY": 1, + "body": 1 +}; + +this.selfClosingTags = +{ // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML + "meta": 1, + "link": 1, + "area": 1, + "base": 1, + "col": 1, + "input": 1, + "img": 1, + "br": 1, + "hr": 1, + "param":1, + "embed":1 +}; + +var invisibleTags = this.invisibleTags = +{ + "HTML": 1, + "HEAD": 1, + "TITLE": 1, + "META": 1, + "LINK": 1, + "STYLE": 1, + "SCRIPT": 1, + "NOSCRIPT": 1, + "BR": 1, + "PARAM": 1, + "COL": 1, + + "html": 1, + "head": 1, + "title": 1, + "meta": 1, + "link": 1, + "style": 1, + "script": 1, + "noscript": 1, + "br": 1, + "param": 1, + "col": 1 + /* + "window": 1, + "browser": 1, + "frame": 1, + "tabbrowser": 1, + "WINDOW": 1, + "BROWSER": 1, + "FRAME": 1, + "TABBROWSER": 1, + */ +}; + + +if (typeof KeyEvent == "undefined") { + this.KeyEvent = { + DOM_VK_CANCEL: 3, + DOM_VK_HELP: 6, + DOM_VK_BACK_SPACE: 8, + DOM_VK_TAB: 9, + DOM_VK_CLEAR: 12, + DOM_VK_RETURN: 13, + DOM_VK_ENTER: 14, + DOM_VK_SHIFT: 16, + DOM_VK_CONTROL: 17, + DOM_VK_ALT: 18, + DOM_VK_PAUSE: 19, + DOM_VK_CAPS_LOCK: 20, + DOM_VK_ESCAPE: 27, + DOM_VK_SPACE: 32, + DOM_VK_PAGE_UP: 33, + DOM_VK_PAGE_DOWN: 34, + DOM_VK_END: 35, + DOM_VK_HOME: 36, + DOM_VK_LEFT: 37, + DOM_VK_UP: 38, + DOM_VK_RIGHT: 39, + DOM_VK_DOWN: 40, + DOM_VK_PRINTSCREEN: 44, + DOM_VK_INSERT: 45, + DOM_VK_DELETE: 46, + DOM_VK_0: 48, + DOM_VK_1: 49, + DOM_VK_2: 50, + DOM_VK_3: 51, + DOM_VK_4: 52, + DOM_VK_5: 53, + DOM_VK_6: 54, + DOM_VK_7: 55, + DOM_VK_8: 56, + DOM_VK_9: 57, + DOM_VK_SEMICOLON: 59, + DOM_VK_EQUALS: 61, + DOM_VK_A: 65, + DOM_VK_B: 66, + DOM_VK_C: 67, + DOM_VK_D: 68, + DOM_VK_E: 69, + DOM_VK_F: 70, + DOM_VK_G: 71, + DOM_VK_H: 72, + DOM_VK_I: 73, + DOM_VK_J: 74, + DOM_VK_K: 75, + DOM_VK_L: 76, + DOM_VK_M: 77, + DOM_VK_N: 78, + DOM_VK_O: 79, + DOM_VK_P: 80, + DOM_VK_Q: 81, + DOM_VK_R: 82, + DOM_VK_S: 83, + DOM_VK_T: 84, + DOM_VK_U: 85, + DOM_VK_V: 86, + DOM_VK_W: 87, + DOM_VK_X: 88, + DOM_VK_Y: 89, + DOM_VK_Z: 90, + DOM_VK_CONTEXT_MENU: 93, + DOM_VK_NUMPAD0: 96, + DOM_VK_NUMPAD1: 97, + DOM_VK_NUMPAD2: 98, + DOM_VK_NUMPAD3: 99, + DOM_VK_NUMPAD4: 100, + DOM_VK_NUMPAD5: 101, + DOM_VK_NUMPAD6: 102, + DOM_VK_NUMPAD7: 103, + DOM_VK_NUMPAD8: 104, + DOM_VK_NUMPAD9: 105, + DOM_VK_MULTIPLY: 106, + DOM_VK_ADD: 107, + DOM_VK_SEPARATOR: 108, + DOM_VK_SUBTRACT: 109, + DOM_VK_DECIMAL: 110, + DOM_VK_DIVIDE: 111, + DOM_VK_F1: 112, + DOM_VK_F2: 113, + DOM_VK_F3: 114, + DOM_VK_F4: 115, + DOM_VK_F5: 116, + DOM_VK_F6: 117, + DOM_VK_F7: 118, + DOM_VK_F8: 119, + DOM_VK_F9: 120, + DOM_VK_F10: 121, + DOM_VK_F11: 122, + DOM_VK_F12: 123, + DOM_VK_F13: 124, + DOM_VK_F14: 125, + DOM_VK_F15: 126, + DOM_VK_F16: 127, + DOM_VK_F17: 128, + DOM_VK_F18: 129, + DOM_VK_F19: 130, + DOM_VK_F20: 131, + DOM_VK_F21: 132, + DOM_VK_F22: 133, + DOM_VK_F23: 134, + DOM_VK_F24: 135, + DOM_VK_NUM_LOCK: 144, + DOM_VK_SCROLL_LOCK: 145, + DOM_VK_COMMA: 188, + DOM_VK_PERIOD: 190, + DOM_VK_SLASH: 191, + DOM_VK_BACK_QUOTE: 192, + DOM_VK_OPEN_BRACKET: 219, + DOM_VK_BACK_SLASH: 220, + DOM_VK_CLOSE_BRACKET: 221, + DOM_VK_QUOTE: 222, + DOM_VK_META: 224 + }; +} + + +// ************************************************************************************************ +// Ajax + +/** + * @namespace + */ +this.Ajax = +{ + + requests: [], + transport: null, + states: ["Uninitialized","Loading","Loaded","Interactive","Complete"], + + initialize: function() + { + this.transport = this.getXHRObject(); + }, + + getXHRObject: function() + { + var xhrObj = false; + try + { + xhrObj = new XMLHttpRequest(); + } + catch(e) + { + var progid = [ + "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" + ]; + + for ( var i=0; i < progid.length; ++i ) { + try + { + xhrObj = new ActiveXObject(progid[i]); + } + catch(e) + { + continue; + } + break; + } + } + finally + { + return xhrObj; + } + }, + + + /** + * Create a AJAX request. + * + * @name request + * @param {Object} options request options + * @param {String} options.url URL to be requested + * @param {String} options.type Request type ("get" ou "post"). Default is "get". + * @param {Boolean} options.async Asynchronous flag. Default is "true". + * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text". + * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded". + * @param {Function} options.onLoading onLoading callback + * @param {Function} options.onLoaded onLoaded callback + * @param {Function} options.onInteractive onInteractive callback + * @param {Function} options.onComplete onComplete callback + * @param {Function} options.onUpdate onUpdate callback + * @param {Function} options.onSuccess onSuccess callback + * @param {Function} options.onFailure onFailure callback + */ + request: function(options) + { + // process options + var o = FBL.extend( + { + // default values + type: "get", + async: true, + dataType: "text", + contentType: "application/x-www-form-urlencoded" + }, + options || {} + ); + + this.requests.push(o); + + var s = this.getState(); + if (s == "Uninitialized" || s == "Complete" || s == "Loaded") + this.sendRequest(); + }, + + serialize: function(data) + { + var r = [""], rl = 0; + if (data) { + if (typeof data == "string") r[rl++] = data; + + else if (data.innerHTML && data.elements) { + for (var i=0,el,l=(el=data.elements).length; i < l; i++) + if (el[i].name) { + r[rl++] = encodeURIComponent(el[i].name); + r[rl++] = "="; + r[rl++] = encodeURIComponent(el[i].value); + r[rl++] = "&"; + } + + } else + for(var param in data) { + r[rl++] = encodeURIComponent(param); + r[rl++] = "="; + r[rl++] = encodeURIComponent(data[param]); + r[rl++] = "&"; + } + } + return r.join("").replace(/&$/, ""); + }, + + sendRequest: function() + { + var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; + + // open XHR object + t.open(r.type, r.url, r.async); + + //setRequestHeaders(); + + // indicates that it is a XHR request to the server + t.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // if data is being sent, sets the appropriate content-type + if (data = FBL.Ajax.serialize(r.data)) + t.setRequestHeader("Content-Type", r.contentType); + + /** @ignore */ + // onreadystatechange handler + t.onreadystatechange = function() + { + FBL.Ajax.onStateChange(r); + }; + + // send the request + t.send(data); + }, + + /** + * Handles the state change + */ + onStateChange: function(options) + { + var fn, o = options, t = this.transport; + var state = this.getState(t); + + if (fn = o["on" + state]) fn(this.getResponse(o), o); + + if (state == "Complete") + { + var success = t.status == 200, response = this.getResponse(o); + + if (fn = o["onUpdate"]) + fn(response, o); + + if (fn = o["on" + (success ? "Success" : "Failure")]) + fn(response, o); + + t.onreadystatechange = FBL.emptyFn; + + if (this.requests.length > 0) + setTimeout(this.sendRequest, 10); + } + }, + + /** + * gets the appropriate response value according the type + */ + getResponse: function(options) + { + var t = this.transport, type = options.dataType; + + if (t.status != 200) return t.statusText; + else if (type == "text") return t.responseText; + else if (type == "html") return t.responseText; + else if (type == "xml") return t.responseXML; + else if (type == "json") return eval("(" + t.responseText + ")"); + }, + + /** + * returns the current state of the XHR object + */ + getState: function() + { + return this.states[this.transport.readyState]; + } + +}; + + +// ************************************************************************************************ +// Cookie, from http://www.quirksmode.org/js/cookies.html + +this.createCookie = function(name,value,days) +{ + if ('cookie' in document) + { + if (days) + { + var date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + var expires = "; expires="+date.toGMTString(); + } + else + var expires = ""; + + document.cookie = name+"="+value+expires+"; path=/"; + } +}; + +this.readCookie = function (name) +{ + if ('cookie' in document) + { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + + for(var i=0; i < ca.length; i++) + { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + } + + return null; +}; + +this.removeCookie = function(name) +{ + this.createCookie(name, "", -1); +}; + + +// ************************************************************************************************ +// http://www.mister-pixel.com/#Content__state=is_that_simple +var fixIE6BackgroundImageCache = function(doc) +{ + doc = doc || document; + try + { + doc.execCommand("BackgroundImageCache", false, true); + } + catch(E) + { + + } +}; + +// ************************************************************************************************ +// calculatePixelsPerInch + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; + +var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body) +{ + var inch = FBL.createGlobalElement("div"); + inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;"; + body.appendChild(inch); + + FBL.pixelsPerInch = { + x: inch.offsetWidth, + y: inch.offsetHeight + }; + + body.removeChild(inch); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceLink = function(url, line, type, object, instance) +{ + this.href = url; + this.instance = instance; + this.line = line; + this.type = type; + this.object = object; +}; + +this.SourceLink.prototype = +{ + toString: function() + { + return this.href; + }, + toJSON: function() // until 3.1... + { + return "{\"href\":\""+this.href+"\", "+ + (this.line?("\"line\":"+this.line+","):"")+ + (this.type?(" \"type\":\""+this.type+"\","):"")+ + "}"; + } + +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceText = function(lines, owner) +{ + this.lines = lines; + this.owner = owner; +}; + +this.SourceText.getLineAsHTML = function(lineNo) +{ + return escapeForSourceLine(this.lines[lineNo-1]); +}; + + +// ************************************************************************************************ +}).apply(FBL); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-i18n */ function() { with (FBL) { +// ************************************************************************************************ + +// TODO: xxxpedro localization +var oSTR = +{ + "NoMembersWarning": "There are no properties to show for this object.", + + "EmptyStyleSheet": "There are no rules in this stylesheet.", + "EmptyElementCSS": "This element has no style rules.", + "AccessRestricted": "Access to restricted URI denied.", + + "net.label.Parameters": "Parameters", + "net.label.Source": "Source", + "URLParameters": "Params", + + "EditStyle": "Edit Element Style...", + "NewRule": "New Rule...", + + "NewProp": "New Property...", + "EditProp": 'Edit "%s"', + "DeleteProp": 'Delete "%s"', + "DisableProp": 'Disable "%s"' +}; + +// ************************************************************************************************ + +FBL.$STR = function(name) +{ + return oSTR.hasOwnProperty(name) ? oSTR[name] : name; +}; + +FBL.$STRF = function(name, args) +{ + if (!oSTR.hasOwnProperty(name)) return name; + + var format = oSTR[name]; + var objIndex = 0; + + var parts = parseFormat(format); + var trialIndex = objIndex; + var objects = args; + + for (var i= 0; i < parts.length; i++) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + + var result = []; + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + result.push(""+args.shift()); + } + else + result.push(part); + } + + return result.join(""); +}; + +// ************************************************************************************************ + +var parseFormat = function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-firebug */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; +var reps = []; + +var parentPanelMap = {}; + + +// ************************************************************************************************ +// Firebug + +/** + * @namespace describe Firebug + * @exports window.Firebug as Firebug + */ +window.Firebug = FBL.Firebug = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + version: "Firebug Lite 1.3.2", + revision: "$Revision: 9760 $", + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + modules: modules, + panelTypes: panelTypes, + panelTypeMap: panelTypeMap, + reps: reps, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Initialization + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); + + Firebug.browser = new Context(Env.browser); + Firebug.context = Firebug.browser; + + // Document must be cached before chrome initialization + cacheDocument(); + + if (Firebug.Inspector) + Firebug.Inspector.create(); + + if (FBL.processAllStyleSheets) + processAllStyleSheets(Firebug.browser.document); + + FirebugChrome.initialize(); + + dispatch(modules, "initialize", []); + + if (Env.onLoad) + { + var onLoad = Env.onLoad; + delete Env.onLoad; + + setTimeout(onLoad, 200); + } + }, + + shutdown: function() + { + if (Firebug.Inspector) + Firebug.Inspector.destroy(); + + dispatch(modules, "shutdown", []); + + var chromeMap = FirebugChrome.chromeMap; + + for (var name in chromeMap) + { + if (chromeMap.hasOwnProperty(name)) + { + chromeMap[name].destroy(); + } + } + + Firebug.Lite.Cache.Element.clear(); + Firebug.Lite.Cache.StyleSheet.clear(); + + Firebug.browser = null; + Firebug.context = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + modules.push.apply(modules, arguments); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + panelTypeMap[panelType.prototype.name] = arguments[i]; + + if (panelType.prototype.parentPanel) + parentPanelMap[panelType.prototype.parentPanel] = 1; + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + }, + + registerRep: function() + { + reps.push.apply(reps, arguments); + }, + + unregisterRep: function() + { + for (var i = 0; i < arguments.length; ++i) + remove(reps, arguments[i]); + }, + + setDefaultReps: function(funcRep, rep) + { + FBL.defaultRep = rep; + FBL.defaultFuncRep = funcRep; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Reps + + getRep: function(object) + { + var type = typeof object; + if (isIE && isFunction(object)) + type = "function"; + + for (var i = 0; i < reps.length; ++i) + { + var rep = reps[i]; + try + { + if (rep.supportsObject(object, type)) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("getRep type: "+type+" object: "+object, rep); + return rep; + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc); + FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className); + // TODO: xxxpedro add trace to FBTrace logs like in Firebug + //firebug.trace(); + } + } + } + + return (type == 'function') ? defaultFuncRep : defaultRep; + }, + + getRepObject: function(node) + { + var target = null; + for (var child = node; child; child = child.parentNode) + { + if (hasClass(child, "repTarget")) + target = child; + + if (child.repObject) + { + if (!target && hasClass(child, "repIgnore")) + break; + else + return child.repObject; + } + } + }, + + getRepNode: function(node) + { + for (var child = node; child; child = child.parentNode) + { + if (child.repObject) + return child; + } + }, + + getElementByRepObject: function(element, object) + { + for (var child = element.firstChild; child; child = child.nextSibling) + { + if (child.repObject == object) + return child; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Preferences + + getPref: function(name) + { + return Firebug[name]; + }, + + setPref: function(name, value) + { + Firebug[name] = value; + + this.savePrefs(); + }, + + setPrefs: function(prefs) + { + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + + this.savePrefs(); + }, + + restorePrefs: function() + { + var Options = Env.Options; + + for (var name in Options) + { + Firebug[name] = Options[name]; + } + }, + + loadPrefs: function(prefs) + { + this.restorePrefs(); + + prefs = prefs || eval("(" + readCookie("FirebugLite") + ")"); + + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + }, + + savePrefs: function() + { + var json = ['{'], jl = 0; + var Options = Env.Options; + + for (var name in Options) + { + if (Options.hasOwnProperty(name)) + { + var value = Firebug[name]; + + json[++jl] = '"'; + json[++jl] = name; + + var type = typeof value; + if (type == "boolean" || type == "number") + { + json[++jl] = '":'; + json[++jl] = value; + json[++jl] = ','; + } + else + { + json[++jl] = '":"'; + json[++jl] = value; + json[++jl] = '",'; + } + } + } + + json.length = jl--; + json[++jl] = '}'; + + createCookie("FirebugLite", json.join("")); + }, + + erasePrefs: function() + { + removeCookie("FirebugLite"); + } +}; + +Firebug.restorePrefs(); + +if (!Env.Options.enablePersistent || + Env.Options.enablePersistent && Env.isChromeContext || + Env.isDebugMode) + Env.browser.window.Firebug = FBL.Firebug; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Other methods + +FBL.cacheDocument = function cacheDocument() +{ + var ElementCache = Firebug.Lite.Cache.Element; + var els = Firebug.browser.document.getElementsByTagName("*"); + for (var i=0, l=els.length, el; iFirebug.registerModule method. There is always one instance of a module object + * per browser window. + * @extends Firebug.Listener + */ +Firebug.Module = extend(new Firebug.Listener(), +/** @extend Firebug.Module */ +{ + /** + * Called when the window is opened. + */ + initialize: function() + { + }, + + /** + * Called when the window is closed. + */ + shutdown: function() + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Called when a new context is created but before the page is loaded. + */ + initContext: function(context) + { + }, + + /** + * Called after a context is detached to a separate window; + */ + reattachContext: function(browser, context) + { + }, + + /** + * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. + */ + destroyContext: function(context, persistedState) + { + }, + + // Called when a FF tab is create or activated (user changes FF tab) + // Called after context is created or with context == null (to abort?) + showContext: function(browser, context) + { + }, + + /** + * Called after a context's page gets DOMContentLoaded + */ + loadedContext: function(context) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + showPanel: function(browser, panel) + { + }, + + showSidePanel: function(browser, panel) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateOption: function(name, value) + { + }, + + getObjectByURL: function(context, url) + { + } +}); + +// ************************************************************************************************ +// Panel + +/** + * @panel Base class for all panels. Every derived panel must define a constructor and + * register with "Firebug.registerPanel" method. An instance of the panel + * object is created by the framework for each browser tab where Firebug is activated. + */ +Firebug.Panel = +{ + name: "HelloWorld", + title: "Hello World!", + + parentPanel: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + options: { + hasCommandLine: false, + hasStatusBar: false, + hasToolButtons: false, + + // Pre-rendered panels are those included in the skin file (firebug.html) + isPreRendered: false, + innerHTMLSync: false + + /* + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // To be used by external extensions + panelHTML: "", + panelCSS: "", + + toolButtonsHTML: "" + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + tabNode: null, + panelNode: null, + sidePanelNode: null, + statusBarNode: null, + toolButtonsNode: null, + + panelBarNode: null, + + sidePanelBarBoxNode: null, + sidePanelBarNode: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + sidePanelBar: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + searchable: false, + editable: true, + order: 2147483647, + statusSeparator: "<", + + create: function(context, doc) + { + this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name); + + this.panelBarNode = $("fbPanelBar1"); + this.sidePanelBarBoxNode = $("fbPanelBar2"); + + if (this.hasSidePanel) + { + this.sidePanelBar = extend({}, PanelBar); + this.sidePanelBar.create(this); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + if (options.isPreRendered) + { + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + } + else + { + var containerSufix = this.parentPanel ? "2" : "1"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel + var panelNode = this.panelNode = createElement("div", { + id: panelId, + className: "fbPanel" + }); + + $("fbPanel" + containerSufix).appendChild(panelNode); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel Tab + var tabHTML = '' + + this.title + ''; + + var tabNode = this.tabNode = createElement("a", { + id: panelId + "Tab", + className: "fbTab fbHover", + innerHTML: tabHTML + }); + + if (isIE6) + { + tabNode.href = "javascript:void(0)"; + } + + var panelBarNode = this.parentPanel ? + Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode : + this.panelBarNode; + + panelBarNode.appendChild(tabNode); + tabNode.style.display = "block"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create ToolButtons + if (options.hasToolButtons) + { + this.toolButtonsNode = createElement("span", { + id: panelId + "Buttons", + className: "fbToolbarButtons" + }); + + $("fbToolbarButtons").appendChild(this.toolButtonsNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create StatusBar + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + + this.statusBarNode = createElement("span", { + id: panelId + "StatusBar", + className: "fbToolbarButtons fbStatusBar" + }); + + this.statusBarBox.appendChild(this.statusBarNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create SidePanel + } + + this.containerNode = this.panelNode.parentNode; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name); + + // xxxpedro contextMenu + this.onContextMenu = bind(this.onContextMenu, this); + + /* + this.context = context; + this.document = doc; + + this.panelNode = doc.createElement("div"); + this.panelNode.ownerPanel = this; + + setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); + doc.body.appendChild(this.panelNode); + + if (FBTrace.DBG_INITIALIZE) + FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); + + this.initializeNode(this.panelNode); + /**/ + }, + + destroy: function(state) // Panel may store info on state + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name); + + if (this.hasSidePanel) + { + this.sidePanelBar.destroy(); + this.sidePanelBar = null; + } + + this.options = null; + this.name = null; + this.parentPanel = null; + + this.tabNode = null; + this.panelNode = null; + this.containerNode = null; + + this.toolButtonsNode = null; + this.statusBarBox = null; + this.statusBarNode = null; + + //if (this.panelNode) + // delete this.panelNode.ownerPanel; + + //this.destroyNode(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + this.sidePanelBar.initialize(); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + this.containerNode = this.panelNode.parentNode; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // restore persistent state + this.containerNode.scrollTop = this.lastScrollTop; + + // xxxpedro contextMenu + addEvent(this.containerNode, "contextmenu", this.onContextMenu); + + + /// TODO: xxxpedro infoTip Hack + Firebug.chrome.currentPanel = + Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ? + Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel : + Firebug.chrome.selectedPanel; + + Firebug.showInfoTips = true; + Firebug.InfoTip.initializeBrowser(Firebug.chrome); + }, + + shutdown: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); + + /// TODO: xxxpedro infoTip Hack + Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); + + if (Firebug.chrome.largeCommandLineVisible) + Firebug.chrome.hideLargeCommandLine(); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + // TODO: xxxpedro firebug1.3a6 + // new PanelBar mechanism will need to call shutdown to hide the panels (so it + // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement + // a "remember selected panel" feature in the sidePanelBar + //this.sidePanelBar.shutdown(); + } + + // store persistent state + this.lastScrollTop = this.containerNode.scrollTop; + + // xxxpedro contextMenu + removeEvent(this.containerNode, "contextmenu", this.onContextMenu); + }, + + detach: function(oldChrome, newChrome) + { + if (oldChrome.selectedPanel.name == this.name) + this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop; + }, + + reattach: function(doc) + { + if (this.options.innerHTMLSync) + this.synchronizeUI(); + }, + + synchronizeUI: function() + { + this.containerNode.scrollTop = this.lastScrollTop || 0; + }, + + show: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "inline"; + this.statusBarNode.style.display = "inline"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "inline"; + } + + this.panelNode.style.display = "block"; + + this.visible = true; + + if (!this.parentPanel) + Firebug.chrome.layout(this); + }, + + hide: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "none"; + this.statusBarNode.style.display = "none"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "none"; + } + + this.panelNode.style.display = "none"; + + this.visible = false; + }, + + watchWindow: function(win) + { + }, + + unwatchWindow: function(win) + { + }, + + updateOption: function(name, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Toolbar helpers + */ + showToolbarButtons: function(buttonsId, show) + { + try + { + if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext. + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this); + + return; + } + var buttons = this.context.browser.chrome.$(buttonsId); + if (buttons) + collapse(buttons, show ? "false" : "true"); + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc); + if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser"); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Returns a number indicating the view's ability to inspect the object. + * + * Zero means not supported, and higher numbers indicate specificity. + */ + supportsObject: function(object) + { + return 0; + }, + + hasObject: function(object) // beyond type testing, is this object selectable? + { + return false; + }, + + select: function(object, forceUpdate) + { + if (!object) + object = this.getDefaultSelection(this.context); + + if(FBTrace.DBG_PANELS) + FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); + + if (forceUpdate || object != this.selection) + { + this.selection = object; + this.updateSelection(object); + + // TODO: xxxpedro + // XXXjoe This is kind of cheating, but, feh. + //Firebug.chrome.onPanelSelect(object, this); + //if (uiListeners.length > 0) + // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener + } + }, + + updateSelection: function(object) + { + }, + + markChange: function(skipSelf) + { + if (this.dependents) + { + if (skipSelf) + { + for (var i = 0; i < this.dependents.length; ++i) + { + var panelName = this.dependents[i]; + if (panelName != this.name) + this.context.invalidatePanels(panelName); + } + } + else + this.context.invalidatePanels.apply(this.context, this.dependents); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + startInspecting: function() + { + }, + + stopInspecting: function(object, cancelled) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + search: function(text, reverse) + { + }, + + /** + * Retrieves the search options that this modules supports. + * This is used by the search UI to present the proper options. + */ + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive") + ]; + }, + + /** + * Navigates to the next document whose match parameter returns true. + */ + navigateToNextDocument: function(match, reverse) + { + // This is an approximation of the UI that is displayed by the location + // selector. This should be close enough, although it may be better + // to simply generate the sorted list within the module, rather than + // sorting within the UI. + var self = this; + function compare(a, b) { + var locA = self.getObjectDescription(a); + var locB = self.getObjectDescription(b); + if(locA.path > locB.path) + return 1; + if(locA.path < locB.path) + return -1; + if(locA.name > locB.name) + return 1; + if(locA.name < locB.name) + return -1; + return 0; + } + var allLocs = this.getLocationList().sort(compare); + for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++); + + function transformIndex(index) { + if (reverse) { + // For the reverse case we need to implement wrap around. + var intermediate = curPos - index - 1; + return (intermediate < 0 ? allLocs.length : 0) + intermediate; + } else { + return (curPos + index + 1) % allLocs.length; + } + }; + + for (var next = 0; next < allLocs.length - 1; next++) + { + var object = allLocs[transformIndex(next)]; + + if (match(object)) + { + this.navigate(object); + return object; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // Called when "Options" clicked. Return array of + // {label: 'name', nol10n: true, type: "checkbox", checked: , command:function to set } + getOptionsMenuItems: function() + { + return null; + }, + + /* + * Called by chrome.onContextMenu to build the context menu when this panel has focus. + * See also FirebugRep for a similar function also called by onContextMenu + * Extensions may monkey patch and chain off this call + * @param object: the 'realObject', a model value, eg a DOM property + * @param target: the HTML element clicked on. + * @return an array of menu items. + */ + getContextMenuItems: function(object, target) + { + return []; + }, + + getBreakOnMenuItems: function() + { + return []; + }, + + getEditor: function(target, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getDefaultSelection: function() + { + return null; + }, + + browseObject: function(object) + { + }, + + getPopupObject: function(target) + { + return Firebug.getRepObject(target); + }, + + getTooltipObject: function(target) + { + return Firebug.getRepObject(target); + }, + + showInfoTip: function(infoTip, x, y) + { + + }, + + getObjectPath: function(object) + { + return null; + }, + + // An array of objects that can be passed to getObjectLocation. + // The list of things a panel can show, eg sourceFiles. + // Only shown if panel.location defined and supportsObject true + getLocationList: function() + { + return null; + }, + + getDefaultLocation: function() + { + return null; + }, + + getObjectLocation: function(object) + { + return ""; + }, + + // Text for the location list menu eg script panel source file list + // return.path: group/category label, return.name: item label + getObjectDescription: function(object) + { + var url = this.getObjectLocation(object); + return FBL.splitURLBase(url); + }, + + /* + * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint + * @param: show boolean, true turns on. + */ + highlight: function(show) + { + var tab = this.getTab(); + if (!tab) + return; + + if (show) + tab.setAttribute("highlight", "true"); + else + tab.removeAttribute("highlight"); + }, + + getTab: function() + { + var chrome = Firebug.chrome; + + var tab = chrome.$("fbPanelBar2").getTab(this.name); + if (!tab) + tab = chrome.$("fbPanelBar1").getTab(this.name); + return tab; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for Break On Next + + /** + * Called by the framework when the user clicks on the Break On Next button. + * @param {Boolean} armed Set to true if the Break On Next feature is + * to be armed for action and set to false if the Break On Next should be disarmed. + * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|. + */ + breakOnNext: function(armed) + { + }, + + /** + * Called when a panel is selected/displayed. The method should return true + * if the Break On Next feature is currently armed for this panel. + */ + shouldBreakOnNext: function() + { + return false; + }, + + /** + * Returns labels for Break On Next tooltip (one for enabled and one for disabled state). + * @param {Boolean} enabled Set to true if the Break On Next feature is + * currently activated for this panel. + */ + getBreakOnNextTooltip: function(enabled) + { + return null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // xxxpedro contextMenu + onContextMenu: function(event) + { + if (!this.getContextMenuItems) + return; + + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + var menu = this.getContextMenuItems(this.selection, target); + if (!menu) + return; + + var contextMenu = new Menu( + { + id: "fbPanelContextMenu", + + items: menu + }); + + contextMenu.show(event.clientX, event.clientY); + + return true; + + /* + // TODO: xxxpedro move code to somewhere. code to get cross-browser + // window to screen coordinates + var box = Firebug.browser.getElementPosition(Firebug.chrome.node); + + var screenY = 0; + + // Firefox + if (typeof window.mozInnerScreenY != "undefined") + { + screenY = window.mozInnerScreenY; + } + // Chrome + else if (typeof window.innerHeight != "undefined") + { + screenY = window.outerHeight - window.innerHeight; + } + // IE + else if (typeof window.screenTop != "undefined") + { + screenY = window.screenTop; + } + + contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top); + /**/ + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * MeasureBox + * To get pixels size.width and size.height: + *
      • this.startMeasuring(view);
      • + *
      • var size = this.measureText(lineNoCharsSpacer);
      • + *
      • this.stopMeasuring();
      • + *
      + * + * @namespace + */ +Firebug.MeasureBox = +{ + startMeasuring: function(target) + { + if (!this.measureBox) + { + this.measureBox = target.ownerDocument.createElement("span"); + this.measureBox.className = "measureBox"; + } + + copyTextStyles(target, this.measureBox); + target.ownerDocument.body.appendChild(this.measureBox); + }, + + getMeasuringElement: function() + { + return this.measureBox; + }, + + measureText: function(value) + { + this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m"; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + measureInputText: function(value) + { + value = value ? escapeForTextNode(value) : "m"; + if (!Firebug.showTextNodesWithWhitespace) + value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m'); + this.measureBox.innerHTML = value; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + getBox: function(target) + { + var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, ""); + var box = getBoxFromStyles(style, this.measureBox); + return box; + }, + + stopMeasuring: function() + { + this.measureBox.parentNode.removeChild(this.measureBox); + } +}; + + +// ************************************************************************************************ +if (FBL.domplate) Firebug.Rep = domplate( +{ + className: "", + inspectable: true, + + supportsObject: function(object, type) + { + return false; + }, + + inspectObject: function(object, context) + { + Firebug.chrome.select(object); + }, + + browseObject: function(object, context) + { + }, + + persistObject: function(object, context) + { + }, + + getRealObject: function(object, context) + { + return object; + }, + + getTitle: function(object) + { + var label = safeToString(object); + + var re = /\[object (.*?)\]/; + var m = re.exec(label); + + ///return m ? m[1] : label; + + // if the label is in the "[object TYPE]" format return its type + if (m) + { + return m[1]; + } + // if it is IE we need to handle some special cases + else if ( + // safeToString() fails to recognize some objects in IE + isIE && + // safeToString() returns "[object]" for some objects like window.Image + (label == "[object]" || + // safeToString() returns undefined for some objects like window.clientInformation + typeof object == "object" && typeof label == "undefined") + ) + { + return "Object"; + } + else + { + return label; + } + }, + + getTooltip: function(object) + { + return null; + }, + + getContextMenuItems: function(object, target, context) + { + return []; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Convenience for domplates + + STR: function(name) + { + return $STR(name); + }, + + cropString: function(text) + { + return cropString(text); + }, + + cropMultipleLines: function(text, limit) + { + return cropMultipleLines(text, limit); + }, + + toLowerCase: function(text) + { + return text ? text.toLowerCase() : text; + }, + + plural: function(n) + { + return n == 1 ? "" : "s"; + } +}); + +// ************************************************************************************************ + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-gui */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Controller + +/**@namespace*/ +FBL.Controller = { + + controllers: null, + controllerContext: null, + + initialize: function(context) + { + this.controllers = []; + this.controllerContext = context || Firebug.chrome; + }, + + shutdown: function() + { + this.removeControllers(); + + //this.controllers = null; + //this.controllerContext = null; + }, + + addController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + // If the first argument is a string, make a selector query + // within the controller node context + if (typeof arg[0] == "string") + { + arg[0] = $$(arg[0], this.controllerContext); + } + + // bind the handler to the proper context + var handler = arg[2]; + arg[2] = bind(handler, this); + // save the original handler as an extra-argument, so we can + // look for it later, when removing a particular controller + arg[3] = handler; + + this.controllers.push(arg); + addEvent.apply(this, arg); + } + }, + + removeController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + for (var j=0, c; c=this.controllers[j]; j++) + { + if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3]) + removeEvent.apply(this, c); + } + } + }, + + removeControllers: function() + { + for (var i=0, c; c=this.controllers[i]; i++) + { + removeEvent.apply(this, c); + } + } +}; + + +// ************************************************************************************************ +// PanelBar + +/**@namespace*/ +FBL.PanelBar = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + panelMap: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + selectedPanel: null, + parentPanelName: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function(ownerPanel) + { + this.panelMap = {}; + this.ownerPanel = ownerPanel; + + if (ownerPanel) + { + ownerPanel.sidePanelBarNode = createElement("span"); + ownerPanel.sidePanelBarNode.style.display = "none"; + ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode); + } + + var panels = Firebug.panelTypes; + for (var i=0, p; p=panels[i]; i++) + { + if ( // normal Panel of the Chrome's PanelBar + !ownerPanel && !p.prototype.parentPanel || + // Child Panel of the current Panel's SidePanelBar + ownerPanel && p.prototype.parentPanel && + ownerPanel.name == p.prototype.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + }, + + destroy: function() + { + PanelBar.shutdown.call(this); + + for (var name in this.panelMap) + { + this.removePanel(name); + + var panel = this.panelMap[name]; + panel.destroy(); + + this.panelMap[name] = null; + delete this.panelMap[name]; + } + + this.panelMap = null; + this.ownerPanel = null; + }, + + initialize: function() + { + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "inline"; + + for(var name in this.panelMap) + { + (function(self, name){ + + // tab click handler + var onTabClick = function onTabClick() + { + self.selectPanel(name); + return false; + }; + + Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]); + + })(this, name); + } + }, + + shutdown: function() + { + var selectedPanel = this.selectedPanel; + + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.hide(); + selectedPanel.shutdown(); + } + + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "none"; + + this.selectedPanel = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + addPanel: function(panelName, parentPanel) + { + var PanelType = Firebug.panelTypeMap[panelName]; + var panel = this.panelMap[panelName] = new PanelType(); + + panel.create(); + }, + + removePanel: function(panelName) + { + var panel = this.panelMap[panelName]; + if (panel.hasOwnProperty(panelName)) + panel.destroy(); + }, + + selectPanel: function(panelName) + { + var selectedPanel = this.selectedPanel; + var panel = this.panelMap[panelName]; + + if (panel && selectedPanel != panel) + { + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.shutdown(); + selectedPanel.hide(); + } + + if (!panel.parentPanel) + FirebugChrome.selectedPanelName = panelName; + + this.selectedPanel = panel; + + setClass(panel.tabNode, "fbSelectedTab"); + panel.show(); + panel.initialize(); + } + }, + + getPanel: function(panelName) + { + var panel = this.panelMap[panelName]; + + return panel; + } + +}; + +//************************************************************************************************ +// Button + +/** + * options.element + * options.caption + * options.title + * + * options.owner + * options.className + * options.pressedClassName + * + * options.onPress + * options.onUnpress + * options.onClick + * + * @class + * @extends FBL.Controller + * + */ + +FBL.Button = function(options) +{ + options = options || {}; + + append(this, options); + + this.state = "unpressed"; + this.display = "unpressed"; + + if (this.element) + { + this.container = this.element.parentNode; + } + else + { + this.shouldDestroy = true; + + this.container = this.owner.getPanel().toolButtonsNode; + + this.element = createElement("a", { + className: this.baseClassName + " " + this.className + " fbHover", + innerHTML: this.caption + }); + + if (this.title) + this.element.title = this.title; + + this.container.appendChild(this.element); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +Button.prototype = extend(Controller, +/**@extend FBL.Button.prototype*/ +{ + type: "normal", + caption: "caption", + title: null, + + className: "", // custom class + baseClassName: "fbButton", // control class + pressedClassName: "fbBtnPressed", // control pressed class + + element: null, + container: null, + owner: null, + + state: null, + display: null, + + destroy: function() + { + this.shutdown(); + + // only remove if it is a dynamically generated button (not pre-rendered) + if (this.shouldDestroy) + this.container.removeChild(this.element); + + this.element = null; + this.container = null; + this.owner = null; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var element = this.element; + + this.addController([element, "mousedown", this.handlePress]); + + if (this.type == "normal") + this.addController( + [element, "mouseup", this.handleUnpress], + [element, "mouseout", this.handleUnpress], + [element, "click", this.handleClick] + ); + }, + + shutdown: function() + { + Controller.shutdown.apply(this); + }, + + restore: function() + { + this.changeState("unpressed"); + }, + + changeState: function(state) + { + this.state = state; + this.changeDisplay(state); + }, + + changeDisplay: function(display) + { + if (display != this.display) + { + if (display == "pressed") + { + setClass(this.element, this.pressedClassName); + } + else if (display == "unpressed") + { + removeClass(this.element, this.pressedClassName); + } + this.display = display; + } + }, + + handlePress: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + this.changeDisplay("pressed"); + this.beforeClick = true; + } + else if (this.type == "toggle") + { + if (this.state == "pressed") + { + this.changeState("unpressed"); + + if (this.onUnpress) + this.onUnpress.apply(this.owner, arguments); + } + else + { + this.changeState("pressed"); + + if (this.onPress) + this.onPress.apply(this.owner, arguments); + } + + if (this.onClick) + this.onClick.apply(this.owner, arguments); + } + + return false; + }, + + handleUnpress: function(event) + { + cancelEvent(event, true); + + if (this.beforeClick) + this.changeDisplay("unpressed"); + + return false; + }, + + handleClick: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + if (this.onClick) + this.onClick.apply(this.owner); + + this.changeState("unpressed"); + } + + this.beforeClick = false; + + return false; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * @class + * @extends FBL.Button + */ +FBL.IconButton = function() +{ + Button.apply(this, arguments); +}; + +IconButton.prototype = extend(Button.prototype, +/**@extend FBL.IconButton.prototype*/ +{ + baseClassName: "fbIconButton", + pressedClassName: "fbIconPressed" +}); + + +//************************************************************************************************ +// Menu + +var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value", + _command: "$item.command"}; + +if (isIE6) + menuItemProps.href = "javascript:void(0)"; + +// Allow GUI to be loaded even when Domplate module is not installed. +if (FBL.domplate) +var MenuPlate = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "fbMenu fbShadow"}, + DIV({"class": "fbMenuContent fbShadowContent"}, + FOR("item", "$object.items|memberIterator", + TAG("$item.tag", {item: "$item"}) + ) + ) + ), + + itemTag: + A(menuItemProps, + "$item.label" + ), + + checkBoxTag: + A(extend(menuItemProps, {checked : "$item.checked"}), + + "$item.label" + ), + + radioButtonTag: + A(extend(menuItemProps, {selected : "$item.selected"}), + + "$item.label" + ), + + groupTag: + A(extend(menuItemProps, {child: "$item.child"}), + "$item.label" + ), + + shortcutTag: + A(menuItemProps, + "$item.label", + SPAN({"class": "fbMenuShortcutKey"}, + "$item.key" + ) + ), + + separatorTag: + SPAN({"class": "fbMenuSeparator"}), + + memberIterator: function(items) + { + var result = []; + + for (var i=0, length=items.length; i width || el.scrollHeight > height)) + { + width = el.scrollWidth; + height = el.scrollHeight; + } + + return {width: width, height: height}; + }, + + getWindowScrollPosition: function() + { + var top=0, left=0, el; + + if(typeof this.window.pageYOffset == "number") + { + top = this.window.pageYOffset; + left = this.window.pageXOffset; + } + else if((el=this.document.body) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + + return {top:top, left:left}; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Element Methods + + getElementFromPoint: function(x, y) + { + if (shouldFixElementFromPoint) + { + var scroll = this.getWindowScrollPosition(); + return this.document.elementFromPoint(x + scroll.left, y + scroll.top); + } + else + return this.document.elementFromPoint(x, y); + }, + + getElementPosition: function(el) + { + var left = 0 + var top = 0; + + do + { + left += el.offsetLeft; + top += el.offsetTop; + } + while (el = el.offsetParent); + + return {left:left, top:top}; + }, + + getElementBox: function(el) + { + var result = {}; + + if (el.getBoundingClientRect) + { + var rect = el.getBoundingClientRect(); + + // fix IE problem with offset when not in fullscreen mode + var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; + + var scroll = this.getWindowScrollPosition(); + + result.top = Math.round(rect.top - offset + scroll.top); + result.left = Math.round(rect.left - offset + scroll.left); + result.height = Math.round(rect.bottom - rect.top); + result.width = Math.round(rect.right - rect.left); + } + else + { + var position = this.getElementPosition(el); + + result.top = position.top; + result.left = position.left; + result.height = el.offsetHeight; + result.width = el.offsetWidth; + } + + return result; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Measurement Methods + + getMeasurement: function(el, name) + { + var result = {value: 0, unit: "px"}; + + var cssValue = this.getStyle(el, name); + + if (!cssValue) return result; + if (cssValue.toLowerCase() == "auto") return result; + + var reMeasure = /(\d+\.?\d*)(.*)/; + var m = cssValue.match(reMeasure); + + if (m) + { + result.value = m[1]-0; + result.unit = m[2].toLowerCase(); + } + + return result; + }, + + getMeasurementInPixels: function(el, name) + { + if (!el) return null; + + var m = this.getMeasurement(el, name); + var value = m.value; + var unit = m.unit; + + if (unit == "px") + return value; + + else if (unit == "pt") + return this.pointsToPixels(name, value); + + if (unit == "em") + return this.emToPixels(el, value); + + else if (unit == "%") + return this.percentToPixels(el, value); + }, + + getMeasurementBox1: function(el, name) + { + var sufixes = ["Top", "Left", "Bottom", "Right"]; + var result = []; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getMeasurementBox: function(el, name) + { + var result = []; + var sufixes = name == "border" ? + ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : + ["Top", "Left", "Bottom", "Right"]; + + if (isIE) + { + var propName, cssValue; + var autoMargin = null; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + { + propName = name + sufix; + + cssValue = el.currentStyle[propName] || el.style[propName]; + + if (cssValue == "auto") + { + if (!autoMargin) + autoMargin = this.getCSSAutoMarginBox(el); + + result[i] = autoMargin[sufix.toLowerCase()]; + } + else + result[i] = this.getMeasurementInPixels(el, propName); + + } + + } + else + { + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = this.getMeasurementInPixels(el, name + sufix); + } + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getCSSAutoMarginBox: function(el) + { + if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + var offsetTop = 0; + if (false && isIEStantandMode) + { + var scrollSize = Firebug.browser.getWindowScrollSize(); + offsetTop = scrollSize.height; + } + + var box = this.document.createElement("div"); + //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;"; + box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;"; + + var clone = el.cloneNode(false); + var text = this.document.createTextNode(" "); + clone.appendChild(text); + + box.appendChild(clone); + + this.document.body.appendChild(box); + + var marginTop = clone.offsetTop - box.offsetTop - 1; + var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; + + var marginLeft = clone.offsetLeft - box.offsetLeft - 1; + var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; + + this.document.body.removeChild(box); + + return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight}; + }, + + getFontSizeInPixels: function(el) + { + var size = this.getMeasurement(el, "fontSize"); + + if (size.unit == "px") return size.value; + + // get font size, the dirty way + var computeDirtyFontSize = function(el, calibration) + { + var div = this.document.createElement("div"); + var divStyle = offscreenStyle; + + if (calibration) + divStyle += " font-size:"+calibration+"px;"; + + div.style.cssText = divStyle; + div.innerHTML = "A"; + el.appendChild(div); + + var value = div.offsetHeight; + el.removeChild(div); + return value; + } + + /* + var calibrationBase = 200; + var calibrationValue = computeDirtyFontSize(el, calibrationBase); + var rate = calibrationBase / calibrationValue; + /**/ + + // the "dirty technique" fails in some environments, so we're using a static value + // based in some tests. + var rate = 200 / 225; + + var value = computeDirtyFontSize(el); + + return value * rate; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Unit Funtions + + pointsToPixels: function(name, value, returnFloat) + { + var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; + + var result = value * pixelsPerInch[axis] / 72; + + return returnFloat ? result : Math.round(result); + }, + + emToPixels: function(el, value) + { + if (!el) return null; + + var fontSize = this.getFontSizeInPixels(el); + + return Math.round(value * fontSize); + }, + + exToPixels: function(el, value) + { + if (!el) return null; + + // get ex value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "ex;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + percentToPixels: function(el, value) + { + if (!el) return null; + + // get % value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "%;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getStyle: isIE ? function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : function(el, name) + { + return this.document.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + } + +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Window Options + +var WindowDefaultOptions = + { + type: "frame", + id: "FirebugUI", + height: 250 + }, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Instantiated objects + + commandLine, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Interface Elements Cache + + fbTop, + fbContent, + fbContentStyle, + fbBottom, + fbBtnInspect, + + fbToolbar, + + fbPanelBox1, + fbPanelBox1Style, + fbPanelBox2, + fbPanelBox2Style, + fbPanelBar2Box, + fbPanelBar2BoxStyle, + + fbHSplitter, + fbVSplitter, + fbVSplitterStyle, + + fbPanel1, + fbPanel1Style, + fbPanel2, + fbPanel2Style, + + fbConsole, + fbConsoleStyle, + fbHTML, + + fbCommandLine, + fbLargeCommandLine, + fbLargeCommandButtons, + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Cached size values + + topHeight, + topPartialHeight, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastSelectedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLineState = 0, + lastFocusedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastHSplitterMouseMove = 0, + onHSplitterMouseMoveBuffer = null, + onHSplitterMouseMoveTimer = null, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastVSplitterMouseMove = 0; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// FirebugChrome + +/**@namespace*/ +FBL.FirebugChrome = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + isOpen: false, + height: 250, + sidePanelWidth: 350, + + selectedPanelName: "Console", + selectedHTMLElementId: null, + + chromeMap: {}, + + htmlSelectionStack: [], + consoleMessageQueue: [], + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); + + createChromeWindow(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); + + if (Env.chrome.type == "frame" || Env.chrome.type == "div") + ChromeMini.create(Env.chrome); + + var chrome = Firebug.chrome = new Chrome(Env.chrome); + FirebugChrome.chromeMap[chrome.type] = chrome; + + addGlobalEvent("keydown", onGlobalKeyDown); + + if (Env.Options.enablePersistent && chrome.type == "popup") + { + // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode + var frame = FirebugChrome.chromeMap.frame; + if (frame) + frame.close(); + + //chrome.reattach(frame, chrome); + //TODO: xxxpedro persist synchronize? + chrome.initialize(); + } + }, + + clone: function(FBChrome) + { + for (var name in FBChrome) + { + var prop = FBChrome[name]; + if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) + { + this[name] = prop; + } + } + } +}; + + + +// ************************************************************************************************ +// Chrome Window Creation + +var createChromeWindow = function(options) +{ + options = extend(WindowDefaultOptions, options || {}); + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Locals + + var chrome = {}, + + context = options.context || Env.browser, + + type = chrome.type = Env.Options.enablePersistent ? + "popup" : + options.type, + + isChromeFrame = type == "frame", + + useLocalSkin = Env.useLocalSkin, + + url = useLocalSkin ? + Env.Location.skin : + "about:blank", + + // document.body not available in XML+XSL documents in Firefox + body = context.document.getElementsByTagName("body")[0], + + formatNode = function(node) + { + if (!Env.isDebugMode) + { + node.firebugIgnore = true; + } + + node.style.border = "0"; + node.style.visibility = "hidden"; + node.style.zIndex = "2147483647"; // MAX z-index = 2147483647 + node.style.position = noFixedPosition ? "absolute" : "fixed"; + node.style.width = "100%"; // "102%"; IE auto margin bug + node.style.left = "0"; + node.style.bottom = noFixedPosition ? "-1px" : "0"; + node.style.height = options.height + "px"; + + // avoid flickering during chrome rendering + if (isFirefox) + node.style.display = "none"; + }, + + createChromeDiv = function() + { + //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed."); + + var node = chrome.node = createGlobalElement("div"), + style = createGlobalElement("style"), + + css = FirebugChrome.Skin.CSS + /* + .replace(/;/g, " !important;") + .replace(/!important\s!important/g, "!important") + .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/, + + // reset some styles to minimize interference from the main page's style + rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" + + // load the chrome styles + css + + // adjust some remaining styles + ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}"; + /* + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + rules += ".fbBody table.fbChrome{position: static !important;}"; + }/**/ + + style.type = "text/css"; + + if (style.styleSheet) + style.styleSheet.cssText = rules; + else + style.appendChild(context.document.createTextNode(rules)); + + document.getElementsByTagName("head")[0].appendChild(style); + + node.className = "fbBody"; + node.style.overflow = "hidden"; + node.innerHTML = getChromeDivTemplate(); + + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + setTimeout(function(){ + node.firstChild.style.height = "1px"; + node.firstChild.style.position = "static"; + },0); + /**/ + } + + formatNode(node); + + body.appendChild(node); + + chrome.window = window; + chrome.document = document; + onChromeLoad(chrome); + }; + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + try + { + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "div" (windowless mode) + if (type == "div") + { + createChromeDiv(); + return; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // cretate the Chrome as an "iframe" + else if (isChromeFrame) + { + // Create the Chrome Frame + var node = chrome.node = createGlobalElement("iframe"); + node.setAttribute("src", url); + node.setAttribute("frameBorder", "0"); + + formatNode(node); + + body.appendChild(node); + + // must set the id after appending to the document, otherwise will cause an + // strange error in IE, making the iframe load the page in which the bookmarklet + // was created (like getfirebug.com), before loading the injected UI HTML, + // generating an "Access Denied" error. + node.id = options.id; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "popup" + else + { + var height = FirebugChrome.height || options.height, + + options = [ + "true,top=", + Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0), + ",left=0,height=", + height, + ",width=", + screen.availWidth-10, // Opera opens popup in a new tab if it's too big! + ",resizable" + ].join(""), + + node = chrome.node = context.window.open( + url, + "popup", + options + ); + + if (node) + { + try + { + node.focus(); + } + catch(E) + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + else + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inject the interface HTML if it is not using the local skin + + if (!useLocalSkin) + { + var tpl = getChromeTemplate(!isChromeFrame), + doc = isChromeFrame ? node.contentWindow.document : node.document; + + doc.write(tpl); + doc.close(); + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Wait the Window to be loaded + + var win, + + waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100, + + waitForWindow = function() + { + if ( // Frame loaded... OR + isChromeFrame && (win=node.contentWindow) && + node.contentWindow.document.getElementById("fbCommandLine") || + + // Popup loaded + !isChromeFrame && (win=node.window) && node.document && + node.document.getElementById("fbCommandLine") ) + { + chrome.window = win.window; + chrome.document = win.document; + + // Prevent getting the wrong chrome height in FF when opening a popup + setTimeout(function(){ + onChromeLoad(chrome); + },0); + } + else + setTimeout(waitForWindow, waitDelay); + }; + + waitForWindow(); + } + catch(e) + { + var msg = e.message || e; + + if (/access/i.test(msg)) + { + // Firebug Lite could not create a window for its Graphical User Interface due to + // a access restriction. This happens in some pages, when loading via bookmarklet. + // In such cases, the only way is to load the GUI in a "windowless mode". + + if (isChromeFrame) + body.removeChild(node); + else if(type == "popup") + node.close(); + + // Load the GUI in a "windowless mode" + createChromeDiv(); + } + else + { + alert("Firebug Error: Firebug GUI could not be created."); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var onChromeLoad = function onChromeLoad(chrome) +{ + Env.chrome = chrome; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded"); + + if (Env.Options.enablePersistent) + { + // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode + Env.FirebugChrome = FirebugChrome; + + chrome.window.Firebug = chrome.window.Firebug || {}; + chrome.window.Firebug.SharedEnv = Env; + + if (Env.isDevelopmentMode) + { + Env.browser.window.FBDev.loadChromeApplication(chrome); + } + else + { + var doc = chrome.document; + var script = doc.createElement("script"); + script.src = Env.Location.app + "#remote,persist"; + doc.getElementsByTagName("head")[0].appendChild(script); + } + } + else + { + if (chrome.type == "frame" || chrome.type == "div") + { + // initialize the chrome application + setTimeout(function(){ + FBL.Firebug.initialize(); + },0); + } + else if (chrome.type == "popup") + { + var oldChrome = FirebugChrome.chromeMap.frame; + + var newChrome = new Chrome(chrome); + + // TODO: xxxpedro sync detach reattach attach + dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); + + if (oldChrome) + oldChrome.close(); + + newChrome.reattach(oldChrome, newChrome); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var getChromeDivTemplate = function() +{ + return FirebugChrome.Skin.HTML; +}; + +var getChromeTemplate = function(isPopup) +{ + var tpl = FirebugChrome.Skin; + var r = [], i = -1; + + r[++i] = ''; + r[++i] = ''; + r[++i] = Firebug.version; + + /* + r[++i] = ''; + /**/ + + r[++i] = ''; + /**/ + + r[++i] = ''; + r[++i] = tpl.HTML; + r[++i] = ''; + + return r.join(""); +}; + + +// ************************************************************************************************ +// Chrome Class + +/**@class*/ +var Chrome = function Chrome(chrome) +{ + var type = chrome.type; + var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; + + append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase) + append(this, chrome); // inherit chrome window properties + append(this, new Context(chrome.window)); // inherit from Context class + + FirebugChrome.chromeMap[type] = this; + Firebug.chrome = this; + Env.chrome = chrome.window; + + this.commandLineVisible = false; + this.sidePanelVisible = false; + + this.create(); + + return this; +}; + +// ************************************************************************************************ +// ChromeBase + +/** + * @namespace + * @extends FBL.Controller + * @extends FBL.PanelBar + **/ +var ChromeBase = {}; +append(ChromeBase, Controller); +append(ChromeBase, PanelBar); +append(ChromeBase, +/**@extend ns-chrome-ChromeBase*/ +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited properties + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from createChrome function + + node: null, + type: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from Context.prototype + + document: null, + window: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // value properties + + sidePanelVisible: false, + commandLineVisible: false, + largeCommandLineVisible: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // object properties + + inspectButton: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + PanelBar.create.call(this); + + if (Firebug.Inspector) + this.inspectButton = new Button({ + type: "toggle", + element: $("fbChrome_btInspect"), + owner: Firebug.Inspector, + + onPress: Firebug.Inspector.startInspecting, + onUnpress: Firebug.Inspector.stopInspecting + }); + }, + + destroy: function() + { + if(Firebug.Inspector) + this.inspectButton.destroy(); + + PanelBar.destroy.call(this); + + this.shutdown(); + }, + + testMenu: function() + { + var firebugMenu = new Menu( + { + id: "fbFirebugMenu", + + items: + [ + { + label: "Open Firebug", + type: "shortcut", + key: isFirefox ? "Shift+F12" : "F12", + checked: true, + command: "toggleChrome" + }, + { + label: "Open Firebug in New Window", + type: "shortcut", + key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12", + command: "openPopup" + }, + { + label: "Inspect Element", + type: "shortcut", + key: "Ctrl+Shift+C", + command: "toggleInspect" + }, + { + label: "Command Line", + type: "shortcut", + key: "Ctrl+Shift+L", + command: "focusCommandLine" + }, + "-", + { + label: "Options", + type: "group", + child: "fbFirebugOptionsMenu" + }, + "-", + { + label: "Firebug Lite Website...", + command: "visitWebsite" + }, + { + label: "Discussion Group...", + command: "visitDiscussionGroup" + }, + { + label: "Issue Tracker...", + command: "visitIssueTracker" + } + ], + + onHide: function() + { + iconButton.restore(); + }, + + toggleChrome: function() + { + Firebug.chrome.toggle(); + }, + + openPopup: function() + { + Firebug.chrome.toggle(true, true); + }, + + toggleInspect: function() + { + Firebug.Inspector.toggleInspect(); + }, + + focusCommandLine: function() + { + Firebug.chrome.focusCommandLine(); + }, + + visitWebsite: function() + { + this.visit("http://getfirebug.com/lite.html"); + }, + + visitDiscussionGroup: function() + { + this.visit("http://groups.google.com/group/firebug"); + }, + + visitIssueTracker: function() + { + this.visit("http://code.google.com/p/fbug/issues/list"); + }, + + visit: function(url) + { + window.open(url); + } + + }); + + /**@private*/ + var firebugOptionsMenu = + { + id: "fbFirebugOptionsMenu", + + getItems: function() + { + var cookiesDisabled = !Firebug.saveCookies; + + return [ + { + label: "Save Options in Cookies", + type: "checkbox", + value: "saveCookies", + checked: Firebug.saveCookies, + command: "saveOptions" + }, + "-", + { + label: "Start Opened", + type: "checkbox", + value: "startOpened", + checked: Firebug.startOpened, + disabled: cookiesDisabled + }, + { + label: "Start in New Window", + type: "checkbox", + value: "startInNewWindow", + checked: Firebug.startInNewWindow, + disabled: cookiesDisabled + }, + { + label: "Show Icon When Hidden", + type: "checkbox", + value: "showIconWhenHidden", + checked: Firebug.showIconWhenHidden, + disabled: cookiesDisabled + }, + { + label: "Override Console Object", + type: "checkbox", + value: "overrideConsole", + checked: Firebug.overrideConsole, + disabled: cookiesDisabled + }, + { + label: "Ignore Firebug Elements", + type: "checkbox", + value: "ignoreFirebugElements", + checked: Firebug.ignoreFirebugElements, + disabled: cookiesDisabled + }, + { + label: "Disable When Firebug Active", + type: "checkbox", + value: "disableWhenFirebugActive", + checked: Firebug.disableWhenFirebugActive, + disabled: cookiesDisabled + }, + { + label: "Disable XHR Listener", + type: "checkbox", + value: "disableXHRListener", + checked: Firebug.disableXHRListener, + disabled: cookiesDisabled + }, + { + label: "Enable Trace Mode", + type: "checkbox", + value: "enableTrace", + checked: Firebug.enableTrace, + disabled: cookiesDisabled + }, + { + label: "Enable Persistent Mode (experimental)", + type: "checkbox", + value: "enablePersistent", + checked: Firebug.enablePersistent, + disabled: cookiesDisabled + }, + "-", + { + label: "Reset All Firebug Options", + command: "restorePrefs", + disabled: cookiesDisabled + } + ]; + }, + + onCheck: function(target, value, checked) + { + Firebug.setPref(value, checked); + }, + + saveOptions: function(target) + { + var saveEnabled = target.getAttribute("checked"); + + if (!saveEnabled) this.restorePrefs(); + + this.updateMenu(target); + + return false; + }, + + restorePrefs: function(target) + { + Firebug.restorePrefs(); + + if(Firebug.saveCookies) + Firebug.savePrefs(); + else + Firebug.erasePrefs(); + + if (target) + this.updateMenu(target); + + return false; + }, + + updateMenu: function(target) + { + var options = getElementsByClass(target.parentNode, "fbMenuOption"); + + var firstOption = options[0]; + var enabled = Firebug.saveCookies; + if (enabled) + Menu.check(firstOption); + else + Menu.uncheck(firstOption); + + if (enabled) + Menu.check(options[0]); + else + Menu.uncheck(options[0]); + + for (var i = 1, length = options.length; i < length; i++) + { + var option = options[i]; + + var value = option.getAttribute("value"); + var pref = Firebug[value]; + + if (pref) + Menu.check(option); + else + Menu.uncheck(option); + + if (enabled) + Menu.enable(option); + else + Menu.disable(option); + } + } + }; + + Menu.register(firebugOptionsMenu); + + var menu = firebugMenu; + + var testMenuClick = function(event) + { + //console.log("testMenuClick"); + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + if (menu.isVisible) + menu.hide(); + else + { + var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position + + chrome = Firebug.chrome, + + box = chrome.getElementBox(target), + + offset = chrome.type == "div" ? + chrome.getElementPosition(chrome.node) : + {top: 0, left: 0}; + + menu.show( + box.left + offsetLeft - offset.left, + box.top + box.height -5 - offset.top + ); + } + + return false; + }; + + var iconButton = new IconButton({ + type: "toggle", + element: $("fbFirebugButton"), + + onClick: testMenuClick + }); + + iconButton.initialize(); + + //addEvent($("fbToolbarIcon"), "click", testMenuClick); + }, + + initialize: function() + { + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Env.bookmarkletOutdated) + Firebug.Console.logFormatted([ + "A new bookmarklet version is available. " + + "Please visit http://getfirebug.com/firebuglite#Install and update it." + ], Firebug.context, "warn"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Firebug.Console) + Firebug.Console.flush(); + + if (Firebug.Trace) + FBTrace.flush(Firebug.Trace); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize inherited classes + Controller.initialize.call(this); + PanelBar.initialize.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the interface elements cache + + fbTop = $("fbTop"); + fbContent = $("fbContent"); + fbContentStyle = fbContent.style; + fbBottom = $("fbBottom"); + fbBtnInspect = $("fbBtnInspect"); + + fbToolbar = $("fbToolbar"); + + fbPanelBox1 = $("fbPanelBox1"); + fbPanelBox1Style = fbPanelBox1.style; + fbPanelBox2 = $("fbPanelBox2"); + fbPanelBox2Style = fbPanelBox2.style; + fbPanelBar2Box = $("fbPanelBar2Box"); + fbPanelBar2BoxStyle = fbPanelBar2Box.style; + + fbHSplitter = $("fbHSplitter"); + fbVSplitter = $("fbVSplitter"); + fbVSplitterStyle = fbVSplitter.style; + + fbPanel1 = $("fbPanel1"); + fbPanel1Style = fbPanel1.style; + fbPanel2 = $("fbPanel2"); + fbPanel2Style = fbPanel2.style; + + fbConsole = $("fbConsole"); + fbConsoleStyle = fbConsole.style; + fbHTML = $("fbHTML"); + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + topHeight = fbTop.offsetHeight; + topPartialHeight = fbToolbar.offsetHeight; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + disableTextSelection($("fbToolbar")); + disableTextSelection($("fbPanelBarBox")); + disableTextSelection($("fbPanelBar1")); + disableTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6 + if (isIE6 && Firebug.Selector) + { + // TODO: xxxpedro change to getElementsByClass + var as = $$(".fbHover"); + for (var i=0, a; a=as[i]; i++) + { + a.setAttribute("href", "javascript:void(0)"); + } + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize all panels + /* + var panelMap = Firebug.panelTypes; + for (var i=0, p; p=panelMap[i]; i++) + { + if (!p.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + /**/ + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.initialize(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + this.addController( + [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine] + ); + + // ************************************************************************************************ + + // Select the first registered panel + // TODO: BUG IE7 + var self = this; + setTimeout(function(){ + self.selectPanel(FirebugChrome.selectedPanelName); + + if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine) + Firebug.chrome.focusCommandLine(); + },0); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + //this.draw(); + + + + + + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + var onPanelMouseDown = function onPanelMouseDown(event) + { + //console.log("onPanelMouseDown", event.target || event.srcElement, event); + + var target = event.target || event.srcElement; + + if (FBL.isLeftClick(event)) + { + var editable = FBL.getAncestorByClass(target, "editable"); + + // if an editable element has been clicked then start editing + if (editable) + { + Firebug.Editor.startEditing(editable); + FBL.cancelEvent(event); + } + // if any other element has been clicked then stop editing + else + { + if (!hasClass(target, "textEditorInner")) + Firebug.Editor.stopEditing(); + } + } + else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target)) + { + // Prevent auto-scroll when middle-clicking a rep object + FBL.cancelEvent(event); + } + }; + + Firebug.getElementPanel = function(element) + { + var panelNode = getAncestorByClass(element, "fbPanel"); + var id = panelNode.id.substr(2); + + var panel = Firebug.chrome.panelMap[id]; + + if (!panel) + { + if (Firebug.chrome.selectedPanel.sidePanelBar) + panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; + } + + return panel; + }; + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // TODO: xxxpedro port to Firebug + + // Improved window key code event listener. Only one "keydown" event will be attached + // to the window, and the onKeyCodeListen() function will delegate which listeners + // should be called according to the event.keyCode fired. + var onKeyCodeListenersMap = []; + var onKeyCodeListen = function(event) + { + for (var keyCode in onKeyCodeListenersMap) + { + var listeners = onKeyCodeListenersMap[keyCode]; + + for (var i = 0, listener; listener = listeners[i]; i++) + { + var filter = listener.filter || FBL.noKeyModifiers; + + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener.listener(); + FBL.cancelEvent(event, true); + return false; + } + } + } + }; + + addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); + + /** + * @name keyCodeListen + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + var keyCode = KeyEvent["DOM_VK_"+key]; + + if (!onKeyCodeListenersMap[keyCode]) + onKeyCodeListenersMap[keyCode] = []; + + onKeyCodeListenersMap[keyCode].push({ + filter: filter, + listener: listener + }); + + return keyCode; + }; + + /** + * @name keyIgnore + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyIgnore = function(keyCode) + { + onKeyCodeListenersMap[keyCode] = null; + delete onKeyCodeListenersMap[keyCode]; + }; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /**/ + // move to shutdown + //removeEvent(Firebug.chrome.document, "keydown", listener[0]); + + + /* + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + if (!filter) + filter = FBL.noKeyModifiers; + + var keyCode = KeyEvent["DOM_VK_"+key]; + + var fn = function fn(event) + { + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener(); + FBL.cancelEvent(event, true); + return false; + } + } + + addEvent(Firebug.chrome.document, "keydown", fn); + + return [fn, capture]; + }; + + Firebug.chrome.keyIgnore = function(listener) + { + removeEvent(Firebug.chrome.document, "keydown", listener[0]); + }; + /**/ + + + this.addController( + [fbPanel1, "mousedown", onPanelMouseDown], + [fbPanel2, "mousedown", onPanelMouseDown] + ); +/**/ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + + // menus can be used without domplate + if (FBL.domplate) + this.testMenu(); + /**/ + + //test XHR + /* + setTimeout(function(){ + + FBL.Ajax.request({url: "../content/firebug/boot.js"}); + FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); + + },1000); + /**/ + }, + + shutdown: function() + { + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.shutdown(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // remove disableTextSelection event handlers + restoreTextSelection($("fbToolbar")); + restoreTextSelection($("fbPanelBarBox")); + restoreTextSelection($("fbPanelBar1")); + restoreTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // shutdown inherited classes + Controller.shutdown.call(this); + PanelBar.shutdown.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Remove the interface elements cache (this must happen after calling + // the shutdown method of all dependent components to avoid errors) + + fbTop = null; + fbContent = null; + fbContentStyle = null; + fbBottom = null; + fbBtnInspect = null; + + fbToolbar = null; + + fbPanelBox1 = null; + fbPanelBox1Style = null; + fbPanelBox2 = null; + fbPanelBox2Style = null; + fbPanelBar2Box = null; + fbPanelBar2BoxStyle = null; + + fbHSplitter = null; + fbVSplitter = null; + fbVSplitterStyle = null; + + fbPanel1 = null; + fbPanel1Style = null; + fbPanel2 = null; + + fbConsole = null; + fbConsoleStyle = null; + fbHTML = null; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + + topHeight = null; + topPartialHeight = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + toggle: function(forceOpen, popup) + { + if(popup) + { + this.detach(); + } + else + { + if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) + { + var frame = FirebugChrome.chromeMap.frame; + frame.reattach(); + + FirebugChrome.chromeMap.popup = null; + + frame.open(); + + return; + } + + // If the context is a popup, ignores the toggle process + if (Firebug.chrome.type == "popup") return; + + var shouldOpen = forceOpen || !FirebugChrome.isOpen; + + if(shouldOpen) + this.open(); + else + this.close(); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + detach: function() + { + if(!FirebugChrome.chromeMap.popup) + { + createChromeWindow({type: "popup"}); + } + }, + + reattach: function(oldChrome, newChrome) + { + Firebug.browser.window.Firebug = Firebug; + + // chrome synchronization + var newPanelMap = newChrome.panelMap; + var oldPanelMap = oldChrome.panelMap; + + var panel; + for(var name in newPanelMap) + { + // TODO: xxxpedro innerHTML + panel = newPanelMap[name]; + if (panel.options.innerHTMLSync) + panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; + } + + Firebug.chrome = newChrome; + + // TODO: xxxpedro sync detach reattach attach + //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); + + if (newChrome.type == "popup") + { + newChrome.initialize(); + //dispatch(Firebug.modules, "initialize", []); + } + else + { + // TODO: xxxpedro only needed in persistent + // should use FirebugChrome.clone, but popup FBChrome + // isn't acessible + FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name; + } + + dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + draw: function() + { + var size = this.getSize(); + + // Height related values + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, + + y = Math.max(size.height /* chrome height */, topHeight), + + heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), + + height = heightValue + "px", + + // Width related values + sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0, + + width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Height related rendering + fbPanelBox1Style.height = height; + fbPanel1Style.height = height; + + if (isIE || isOpera) + { + // Fix IE and Opera problems with auto resizing the verticall splitter + fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px"; + } + //xxxpedro FF2 only? + /* + else if (isFirefox) + { + // Fix Firefox problem with table rows with 100% height (fit height) + fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px"; + }/**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Width related rendering + fbPanelBox1Style.width = width; + fbPanel1Style.width = width; + + // SidePanel rendering + if (Firebug.chrome.sidePanelVisible) + { + sideWidthValue = Math.max(sideWidthValue - 6, 0); + + var sideWidth = sideWidthValue + "px"; + + fbPanelBox2Style.width = sideWidth; + + fbVSplitterStyle.right = sideWidth; + + if (Firebug.chrome.largeCommandLineVisible) + { + fbLargeCommandLine = $("fbLargeCommandLine"); + + fbLargeCommandLine.style.height = heightValue - 4 + "px"; + fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; + + fbLargeCommandButtons = $("fbLargeCommandButtons"); + fbLargeCommandButtons.style.width = sideWidth; + } + else + { + fbPanel2Style.height = height; + fbPanel2Style.width = sideWidth; + + fbPanelBar2BoxStyle.width = sideWidth; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getSize: function() + { + return this.type == "div" ? + { + height: this.node.offsetHeight, + width: this.node.offsetWidth + } + : + this.getWindowSize(); + }, + + resize: function() + { + var self = this; + + // avoid partial resize when maximizing window + setTimeout(function(){ + self.draw(); + + if (noFixedPosition && (self.type == "frame" || self.type == "div")) + self.fixIEPosition(); + }, 0); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + layout: function(panel) + { + if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); + + var options = panel.options; + + changeCommandLineVisibility(options.hasCommandLine); + changeSidePanelVisibility(panel.hasSidePanel); + + Firebug.chrome.draw(); + }, + + showLargeCommandLine: function(hideToggleIcon) + { + var chrome = Firebug.chrome; + + if (!chrome.largeCommandLineVisible) + { + chrome.largeCommandLineVisible = true; + + if (chrome.selectedPanel.options.hasCommandLine) + { + if (Firebug.CommandLine) + Firebug.CommandLine.blur(); + + changeCommandLineVisibility(false); + } + + changeSidePanelVisibility(true); + + fbLargeCommandLine.style.display = "block"; + fbLargeCommandButtons.style.display = "block"; + + fbPanel2Style.display = "none"; + fbPanelBar2BoxStyle.display = "none"; + + chrome.draw(); + + fbLargeCommandLine.focus(); + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(true); + } + }, + + hideLargeCommandLine: function() + { + if (Firebug.chrome.largeCommandLineVisible) + { + Firebug.chrome.largeCommandLineVisible = false; + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(false); + + fbLargeCommandLine.blur(); + + fbPanel2Style.display = "block"; + fbPanelBar2BoxStyle.display = "block"; + + fbLargeCommandLine.style.display = "none"; + fbLargeCommandButtons.style.display = "none"; + + changeSidePanelVisibility(false); + + if (Firebug.chrome.selectedPanel.options.hasCommandLine) + changeCommandLineVisibility(true); + + Firebug.chrome.draw(); + + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLine: function() + { + var selectedPanelName = this.selectedPanel.name, panelToSelect; + + if (focusCommandLineState == 0 || selectedPanelName != "Console") + { + focusCommandLineState = 0; + lastFocusedPanelName = selectedPanelName; + + panelToSelect = "Console"; + } + if (focusCommandLineState == 1) + { + panelToSelect = lastFocusedPanelName; + } + + this.selectPanel(panelToSelect); + + try + { + if (Firebug.CommandLine) + { + if (panelToSelect == "Console") + Firebug.CommandLine.focus(); + else + Firebug.CommandLine.blur(); + } + } + catch(e) + { + //TODO: xxxpedro trace error + } + + focusCommandLineState = ++focusCommandLineState % 2; + } + +}); + +// ************************************************************************************************ +// ChromeFrameBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromeFrameBase = extend(ChromeBase, +/**@extend ns-chrome-ChromeFrameBase*/ +{ + create: function() + { + ChromeBase.create.call(this); + + // restore display for the anti-flicker trick + if (isFirefox) + this.node.style.display = "block"; + + if (Env.Options.startInNewWindow) + { + this.close(); + this.toggle(true, true); + return; + } + + if (Env.Options.startOpened) + this.open(); + else + this.close(); + }, + + destroy: function() + { + removeGlobalEvent("keydown", onGlobalKeyDown); + + ChromeBase.destroy.call(this); + + this.document = null; + delete this.document; + + this.window = null; + delete this.window; + + this.node.parentNode.removeChild(this.node); + this.node = null; + delete this.node; + }, + + initialize: function() + { + //FBTrace.sysout("Frame", "initialize();") + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.browser.window, "resize", this.resize], + [$("fbWindow_btClose"), "click", this.close], + [$("fbWindow_btDetach"), "click", this.detach], + [$("fbWindow_btDeactivate"), "click", this.deactivate] + ); + + if (!Env.Options.enablePersistent) + this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + fbVSplitter.onmousedown = onVSplitterMouseDown; + fbHSplitter.onmousedown = onHSplitterMouseDown; + + this.isInitialized = true; + }, + + shutdown: function() + { + fbVSplitter.onmousedown = null; + fbHSplitter.onmousedown = null; + + ChromeBase.shutdown.apply(this); + + this.isInitialized = false; + }, + + reattach: function() + { + var frame = FirebugChrome.chromeMap.frame; + + ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); + }, + + open: function() + { + if (!FirebugChrome.isOpen) + { + FirebugChrome.isOpen = true; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,1"); + + var node = this.node; + + node.style.visibility = "hidden"; // Avoid flickering + + if (Firebug.showIconWhenHidden) + { + if (ChromeMini.isInitialized) + { + ChromeMini.shutdown(); + } + + } + else + node.style.display = "block"; + + var main = $("fbChrome"); + + // IE6 throws an error when setting this property! why? + //main.style.display = "table"; + main.style.display = ""; + + var self = this; + setTimeout(function(){ + node.style.visibility = "visible"; + + //dispatch(Firebug.modules, "initialize", []); + self.initialize(); + + if (noFixedPosition) + self.fixIEPosition(); + + self.draw(); + + }, 10); + } + }, + + close: function() + { + if (FirebugChrome.isOpen || !this.isInitialized) + { + if (this.isInitialized) + { + //dispatch(Firebug.modules, "shutdown", []); + this.shutdown(); + } + + FirebugChrome.isOpen = false; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,0"); + + var node = this.node; + + if (Firebug.showIconWhenHidden) + { + node.style.visibility = "hidden"; // Avoid flickering + + // TODO: xxxpedro - persist IE fixed? + var main = $("fbChrome", FirebugChrome.chromeMap.frame.document); + main.style.display = "none"; + + ChromeMini.initialize(); + + node.style.visibility = "visible"; + } + else + node.style.display = "none"; + } + }, + + deactivate: function() + { + // if it is running as a Chrome extension, dispatch a message to the extension signaling + // that Firebug should be deactivated for the current tab + if (Env.isChromeExtension) + { + localStorage.removeItem("Firebug"); + Firebug.GoogleChrome.dispatch("FB_deactivate"); + + // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole + // app, otherwise it won't be able to be reactivated without reloading the page. + // but we need to stop listening global keys, otherwise the key activation won't work. + Firebug.chrome.close(); + } + else + { + Firebug.shutdown(); + } + }, + + fixIEPosition: function() + { + // fix IE problem with offset when not in fullscreen mode + var doc = this.document; + var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0; + + var size = Firebug.browser.getWindowSize(); + var scroll = Firebug.browser.getWindowScrollPosition(); + var maxHeight = size.height; + var height = this.node.offsetHeight; + + var bodyStyle = doc.body.currentStyle; + + this.node.style.top = maxHeight - height + scroll.top + "px"; + + if ((this.type == "frame" || this.type == "div") && + (bodyStyle.marginLeft || bodyStyle.marginRight)) + { + this.node.style.width = size.width + "px"; + } + + if (fbVSplitterStyle) + fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px"; + + this.draw(); + } + +}); + + +// ************************************************************************************************ +// ChromeMini + +/** + * @namespace + * @extends FBL.Controller + */ +var ChromeMini = extend(Controller, +/**@extend ns-chrome-ChromeMini*/ +{ + create: function(chrome) + { + append(this, chrome); + this.type = "mini"; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "block"; + + var miniIcon = $("fbMiniIcon", doc); + var width = miniIcon.offsetWidth + 10; + miniIcon.title = "Open " + Firebug.version; + + var errors = $("fbMiniErrors", doc); + if (errors.offsetWidth) + width += errors.offsetWidth + 10; + + var node = this.node; + node.style.height = "27px"; + node.style.width = width + "px"; + node.style.left = ""; + node.style.right = 0; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "true"); + this.document.body.style.backgroundColor = "transparent"; + } + else + node.style.background = "transparent"; + + if (noFixedPosition) + this.fixIEPosition(); + + this.addController( + [$("fbMiniIcon", doc), "click", onMiniIconClick] + ); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + this.isInitialized = true; + }, + + shutdown: function() + { + var node = this.node; + node.style.height = FirebugChrome.height + "px"; + node.style.width = "100%"; + node.style.left = 0; + node.style.right = ""; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "false"); + this.document.body.style.backgroundColor = "#fff"; + } + else + node.style.background = "#fff"; + + if (noFixedPosition) + this.fixIEPosition(); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "none"; + + Controller.shutdown.apply(this); + + this.isInitialized = false; + }, + + draw: function() + { + + }, + + fixIEPosition: ChromeFrameBase.fixIEPosition + +}); + + +// ************************************************************************************************ +// ChromePopupBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromePopupBase = extend(ChromeBase, +/**@extend ns-chrome-ChromePopupBase*/ +{ + + initialize: function() + { + setClass(this.document.body, "FirebugPopup"); + + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.chrome.window, "resize", this.resize], + [Firebug.chrome.window, "unload", this.destroy] + ); + + if (Env.Options.enablePersistent) + { + this.persist = bind(this.persist, this); + addEvent(Firebug.browser.window, "unload", this.persist); + } + else + this.addController( + [Firebug.browser.window, "unload", this.close] + ); + + fbVSplitter.onmousedown = onVSplitterMouseDown; + }, + + destroy: function() + { + // TODO: xxxpedro sync detach reattach attach + var frame = FirebugChrome.chromeMap.frame; + + if(frame) + { + dispatch(frame.panelMap, "detach", [this, frame]); + + frame.reattach(this, frame); + } + + if (Env.Options.enablePersistent) + { + removeEvent(Firebug.browser.window, "unload", this.persist); + } + + ChromeBase.destroy.apply(this); + + FirebugChrome.chromeMap.popup = null; + + this.node.close(); + }, + + persist: function() + { + persistTimeStart = new Date().getTime(); + + removeEvent(Firebug.browser.window, "unload", this.persist); + + Firebug.Inspector.destroy(); + Firebug.browser.window.FirebugOldBrowser = true; + + var persistTimeStart = new Date().getTime(); + + var waitMainWindow = function() + { + var doc, head; + + try + { + if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && + doc.documentElement && (head = doc.documentElement.firstChild)*/) + { + + try + { + // exposes the FBL to the global namespace when in debug mode + if (Env.isDebugMode) + { + window.FBL = FBL; + } + + window.Firebug = Firebug; + window.opener.Firebug = Firebug; + + Env.browser = window.opener; + Firebug.browser = Firebug.context = new Context(Env.browser); + + registerConsole(); + + // the delay time should be calculated right after registering the + // console, once right after the console registration, call log messages + // will be properly handled + var persistDelay = new Date().getTime() - persistTimeStart; + + var chrome = Firebug.chrome; + addEvent(Firebug.browser.window, "unload", chrome.persist); + + FBL.cacheDocument(); + Firebug.Inspector.create(); + + var htmlPanel = chrome.getPanel("HTML"); + htmlPanel.createUI(); + + Firebug.Console.logFormatted( + ["Firebug could not capture console calls during " + + persistDelay + "ms"], + Firebug.context, + "info" + ); + } + catch(pE) + { + alert("persist error: " + (pE.message || pE)); + } + + } + else + { + window.setTimeout(waitMainWindow, 0); + } + + } catch (E) { + window.close(); + } + }; + + waitMainWindow(); + }, + + close: function() + { + this.destroy(); + } + +}); + + +//************************************************************************************************ +// UI helpers + +var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) +{ + var last = Firebug.chrome.commandLineVisible; + var visible = Firebug.chrome.commandLineVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; + + if (visible != last) + { + if (visible) + { + fbBottom.className = ""; + + if (Firebug.CommandLine) + Firebug.CommandLine.activate(); + } + else + { + if (Firebug.CommandLine) + Firebug.CommandLine.deactivate(); + + fbBottom.className = "hide"; + } + } +}; + +var changeSidePanelVisibility = function changeSidePanelVisibility(visibility) +{ + var last = Firebug.chrome.sidePanelVisible; + Firebug.chrome.sidePanelVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible; + + if (Firebug.chrome.sidePanelVisible != last) + { + fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + } +}; + + +// ************************************************************************************************ +// F12 Handler + +var onGlobalKeyDown = function onGlobalKeyDown(event) +{ + var keyCode = event.keyCode; + var shiftKey = event.shiftKey; + var ctrlKey = event.ctrlKey; + + if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox)) + { + Firebug.chrome.toggle(false, ctrlKey); + cancelEvent(event, true); + + // TODO: xxxpedro replace with a better solution. we're doing this + // to allow reactivating with the F12 key after being deactivated + if (Env.isChromeExtension) + { + Firebug.GoogleChrome.dispatch("FB_enableIcon"); + } + } + else if (keyCode == 67 /* C */ && ctrlKey && shiftKey) + { + Firebug.Inspector.toggleInspect(); + cancelEvent(event, true); + } + else if (keyCode == 76 /* L */ && ctrlKey && shiftKey) + { + Firebug.chrome.focusCommandLine(); + cancelEvent(event, true); + } +}; + +var onMiniIconClick = function onMiniIconClick(event) +{ + Firebug.chrome.toggle(false, event.ctrlKey); + cancelEvent(event, true); +}; + + +// ************************************************************************************************ +// Horizontal Splitter Handling + +var onHSplitterMouseDown = function onHSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onHSplitterMouseMove); + addGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = "fbOnMovingHSplitter"; + + return false; +}; + +var onHSplitterMouseMove = function onHSplitterMouseMove(event) +{ + cancelEvent(event, true); + + var clientY = event.clientY; + var win = isIE + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument && event.target.ownerDocument.defaultView; + + if (!win) + return; + + if (win != win.parent) + { + var frameElement = win.frameElement; + if (frameElement) + { + var framePos = Firebug.browser.getElementPosition(frameElement).top; + clientY += framePos; + + if (frameElement.style.position != "fixed") + clientY -= Firebug.browser.getWindowScrollPosition().top; + } + } + + if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI") + { + clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY; + } + /* + console.log( + typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome", + //win.frameElement.id, + event.target, + clientY + );/**/ + + onHSplitterMouseMoveBuffer = clientY; // buffer + + if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + lastHSplitterMouseMove = new Date().getTime(); + handleHSplitterMouseMove(); + } + else + if (!onHSplitterMouseMoveTimer) + onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate); + + // improving the resizing performance by canceling the mouse event. + // canceling events will prevent the page to receive such events, which would imply + // in more processing being expended. + cancelEvent(event, true); + return false; +}; + +var handleHSplitterMouseMove = function() +{ + if (onHSplitterMouseMoveTimer) + { + clearTimeout(onHSplitterMouseMoveTimer); + onHSplitterMouseMoveTimer = null; + } + + var clientY = onHSplitterMouseMoveBuffer; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + + // compute chrome fixed size (top bar and command line) + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0; + var fixedHeight = topHeight + commandLineHeight; + var chromeNode = Firebug.chrome.node; + + var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; + + //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; + var height = windowSize.height; + + // compute the min and max size of the chrome + var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight); + chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize); + + FirebugChrome.height = chromeHeight; + chromeNode.style.height = chromeHeight + "px"; + + if (noFixedPosition) + Firebug.chrome.fixIEPosition(); + + Firebug.chrome.draw(); +}; + +var onHSplitterMouseUp = function onHSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onHSplitterMouseMove); + removeGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = ""; + + Firebug.chrome.draw(); + + // avoid text selection in IE when returning to the document + // after the mouse leaves the document during the resizing + return false; +}; + + +// ************************************************************************************************ +// Vertical Splitter Handling + +var onVSplitterMouseDown = function onVSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onVSplitterMouseMove); + addGlobalEvent("mouseup", onVSplitterMouseUp); + + return false; +}; + +var onVSplitterMouseMove = function onVSplitterMouseMove(event) +{ + if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + var target = event.target || event.srcElement; + if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome + { + var clientX = event.clientX; + var win = document.all + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument.defaultView; + + if (win != win.parent) + clientX += win.frameElement ? win.frameElement.offsetLeft : 0; + + var size = Firebug.chrome.getSize(); + var x = Math.max(size.width - clientX + 3, 6); + + FirebugChrome.sidePanelWidth = x; + Firebug.chrome.draw(); + } + + lastVSplitterMouseMove = new Date().getTime(); + } + + cancelEvent(event, true); + return false; +}; + +var onVSplitterMouseUp = function onVSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onVSplitterMouseMove); + removeGlobalEvent("mouseup", onVSplitterMouseUp); + + Firebug.chrome.draw(); +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Browser = function(window) +{ + this.contentWindow = window; + this.contentDocument = window.document; + this.currentURI = + { + spec: window.location.href + }; +}; + +Firebug.Lite.Browser.prototype = +{ + toString: function() + { + return "Firebug.Lite.Browser"; + } +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Cache = +{ + ID: "firebug" + new Date().getTime() +}; + +// ************************************************************************************************ + +/** + * TODO: if a cached element is cloned, the expando property will be cloned too in IE + * which will result in a bug. Firebug Lite will think the new cloned node is the old + * one. + * + * TODO: Investigate a possibility of cache validation, to be customized by each + * kind of cache. For ElementCache it should validate if the element still is + * inserted at the DOM. + */ +var cacheUID = 0; +var createCache = function() +{ + var map = {}; + var CID = Firebug.Lite.Cache.ID; + + // better detection + var supportsDeleteExpando = !document.all; + + var cacheFunction = function(element) + { + return cacheAPI.set(element); + }; + + var cacheAPI = + { + get: function(key) + { + return map.hasOwnProperty(key) ? + map[key] : + null; + }, + + set: function(element) + { + var id = element[CID]; + + if (!id) + { + id = ++cacheUID; + element[CID] = id; + } + + if (!map.hasOwnProperty(id)) + { + map[id] = element; + } + + return id; + }, + + unset: function(element) + { + var id = element[CID]; + + if (supportsDeleteExpando) + { + delete element[CID]; + } + else if (element.removeAttribute) + { + element.removeAttribute(CID); + } + + delete map[id]; + + }, + + key: function(element) + { + return element[CID]; + }, + + has: function(element) + { + return map.hasOwnProperty(element[CID]); + }, + + clear: function() + { + for (var id in map) + { + var element = map[id]; + cacheAPI.unset(element); + } + } + }; + + FBL.append(cacheFunction, cacheAPI); + + return cacheFunction; +}; + +// ************************************************************************************************ + +// TODO: xxxpedro : check if we need really this on FBL scope +Firebug.Lite.Cache.StyleSheet = createCache(); +Firebug.Lite.Cache.Element = createCache(); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Proxy = +{ + // jsonp callbacks + _callbacks: {}, + + /** + * Load a resource, either locally (directly) or externally (via proxy) using + * synchronous XHR calls. Loading external resources requires the proxy plugin to + * be installed and configured (see /plugin/proxy/proxy.php). + */ + load: function(url) + { + var resourceDomain = getDomain(url); + var isLocalResource = + // empty domain means local URL + !resourceDomain || + // same domain means local too + resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context + + return isLocalResource ? fetchResource(url) : fetchProxyResource(url); + }, + + /** + * Load a resource using JSONP technique. + */ + loadJSONP: function(url, callback) + { + var script = createGlobalElement("script"), + doc = Firebug.context.document, + + uid = "" + new Date().getTime(), + callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, + + jsonpURL = url.indexOf("?") != -1 ? + url + "&" + callbackName : + url + "?" + callbackName; + + Firebug.Lite.Proxy._callbacks[uid] = function(data) + { + if (callback) + callback(data); + + script.parentNode.removeChild(script); + delete Firebug.Lite.Proxy._callbacks[uid]; + }; + + script.src = jsonpURL; + + if (doc.documentElement) + doc.documentElement.appendChild(script); + }, + + /** + * Load a resource using YQL (not reliable). + */ + YQL: function(url, callback) + { + var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + + encodeURIComponent(url) + "%22&format=xml"; + + this.loadJSONP(yql, function(data) + { + var source = data.results[0]; + + // clean up YQL bogus elements + var match = /\s+

      ([\s\S]+)<\/p>\s+<\/body>$/.exec(source); + if (match) + source = match[1]; + + console.log(source); + }); + } +}; + +// ************************************************************************************************ + +var fetchResource = function(url) +{ + var xhr = FBL.Ajax.getXHRObject(); + xhr.open("get", url, false); + xhr.send(); + + return xhr.responseText; +}; + +var fetchProxyResource = function(url) +{ + var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); + var response = fetchResource(proxyURL); + + try + { + var data = eval("(" + response + ")"); + } + catch(E) + { + return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; + } + + return data ? data.contents : ""; +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Script = function(window) +{ + this.fileName = null; + this.isValid = null; + this.baseLineNumber = null; + this.lineExtent = null; + this.tag = null; + + this.functionName = null; + this.functionSource = null; +}; + +Firebug.Lite.Script.prototype = +{ + isLineExecutable: function(){}, + pcToLine: function(){}, + lineToPc: function(){}, + + toString: function() + { + return "Firebug.Lite.Script"; + } +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Style = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-selector*/ function() { with (FBL) { +// ************************************************************************************************ + +/* + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +/** + * @name Firebug.Selector + * @namespace + */ + +/** + * @exports Sizzle as Firebug.Selector + */ +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +/**#@+ @ignore */ +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + if ( div.getElementsByClassName("e").length === 0 ) + return; + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE + +Firebug.Selector = Sizzle; + +/**#@-*/ + +// ************************************************************************************************ +}}); + +// Problems in IE +// FIXED - eval return +// FIXED - addEventListener problem in IE +// FIXED doc.createRange? +// +// class reserved word +// test all honza examples in IE6 and IE7 + + +/* See license.txt for terms of usage */ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function DomplateTag(tagName) +{ + this.tagName = tagName; +} + +function DomplateEmbed() +{ +} + +function DomplateLoop() +{ +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +( /** @scope ns-domplate */ function() { + +var womb = null; + +var domplate = FBL.domplate = function() +{ + var lastSubject; + for (var i = 0; i < arguments.length; ++i) + lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i]; + + for (var name in lastSubject) + { + var val = lastSubject[name]; + if (isTag(val)) + val.tag.subject = lastSubject; + } + + return lastSubject; +}; + +domplate.context = function(context, fn) +{ + var lastContext = domplate.lastContext; + domplate.topContext = context; + fn.apply(context); + domplate.topContext = lastContext; +}; + +FBL.TAG = function() +{ + var embed = new DomplateEmbed(); + return embed.merge(arguments); +}; + +FBL.FOR = function() +{ + var loop = new DomplateLoop(); + return loop.merge(arguments); +}; + +DomplateTag.prototype = +{ + merge: function(args, oldTag) + { + if (oldTag) + this.tagName = oldTag.tagName; + + this.context = oldTag ? oldTag.context : null; + this.subject = oldTag ? oldTag.subject : null; + this.attrs = oldTag ? copyObject(oldTag.attrs) : {}; + this.classes = oldTag ? copyObject(oldTag.classes) : {}; + this.props = oldTag ? copyObject(oldTag.props) : null; + this.listeners = oldTag ? copyArray(oldTag.listeners) : null; + this.children = oldTag ? copyArray(oldTag.children) : []; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args.length ? args[0] : null; + var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); + + this.children = []; + + if (domplate.topContext) + this.context = domplate.topContext; + + if (args.length) + parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); + + if (hasAttrs) + this.parseAttrs(attrs); + + return creator(this, DomplateTag); + }, + + parseAttrs: function(args) + { + for (var name in args) + { + var val = parseValue(args[name]); + readPartNames(val, this.vars); + + if (name.indexOf("on") == 0) + { + var eventName = name.substr(2); + if (!this.listeners) + this.listeners = []; + this.listeners.push(eventName, val); + } + else if (name.indexOf("_") == 0) + { + var propName = name.substr(1); + if (!this.props) + this.props = {}; + this.props[propName] = val; + } + else if (name.indexOf("$") == 0) + { + var className = name.substr(1); + if (!this.classes) + this.classes = {}; + this.classes[className] = val; + } + else + { + if (name == "class" && this.attrs.hasOwnProperty(name) ) + this.attrs[name] += " " + val; + else + this.attrs[name] = val; + } + } + }, + + compile: function() + { + if (this.renderMarkup) + return; + + this.compileMarkup(); + this.compileDOM(); + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs); + }, + + compileMarkup: function() + { + this.markupArgs = []; + var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; + + this.generateMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + + var fnBlock = ['r=(function (__code__, __context__, __in__, __out__']; + for (var i = 0; i < info.argIndex; ++i) + fnBlock.push(', s', i); + fnBlock.push(') {'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (__context__) {'); + fnBlock.push('with (__in__) {'); + + fnBlock.push.apply(fnBlock, blocks); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('}})'); + + function __link__(tag, code, outputs, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var tagOutputs = []; + var markupArgs = [code, tag.tag.context, args, tagOutputs]; + markupArgs.push.apply(markupArgs, tag.tag.markupArgs); + tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs); + + outputs.push(tag); + outputs.push(tagOutputs); + } + + function __escape__(value) + { + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); + } + + function __loop__(iter, outputs, fn) + { + var iterOuts = []; + outputs.push(iterOuts); + + if (iter instanceof Array) + iter = new ArrayIterator(iter); + + try + { + while (1) + { + var value = iter.next(); + var itemOuts = [0,0]; + iterOuts.push(itemOuts); + fn.apply(this, [value, itemOuts]); + } + } + catch (exc) + { + if (exc != StopIteration) + throw exc; + } + } + + var js = fnBlock.join(""); + var r = null; + eval(js); + this.renderMarkup = r; + }, + + getVarNames: function(args) + { + if (this.vars) + args.push.apply(args, this.vars); + + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.getVarNames(args); + else if (child instanceof Parts) + { + for (var i = 0; i < child.parts.length; ++i) + { + if (child.parts[i] instanceof Variable) + { + var name = child.parts[i].name; + var names = name.split("."); + args.push(names[0]); + } + } + } + } + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + topBlock.push(',"<', this.tagName, '"'); + + for (var name in this.attrs) + { + if (name != "class") + { + var val = this.attrs[name]; + topBlock.push(', " ', name, '=\\""'); + addParts(val, ',', topBlock, info, true); + topBlock.push(', "\\""'); + } + } + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + readPartNames(this.listeners[i+1], topOuts); + } + + if (this.props) + { + for (var name in this.props) + readPartNames(this.props[name], topOuts); + } + + if ( this.attrs.hasOwnProperty("class") || this.classes) + { + topBlock.push(', " class=\\""'); + if (this.attrs.hasOwnProperty("class")) + addParts(this.attrs["class"], ',', topBlock, info, true); + topBlock.push(', " "'); + for (var name in this.classes) + { + topBlock.push(', ('); + addParts(this.classes[name], '', topBlock, info); + topBlock.push(' ? "', name, '" + " " : "")'); + } + topBlock.push(', "\\""'); + } + topBlock.push(',">"'); + + this.generateChildMarkup(topBlock, topOuts, blocks, info); + topBlock.push(',""'); + }, + + generateChildMarkup: function(topBlock, topOuts, blocks, info) + { + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.generateMarkup(topBlock, topOuts, blocks, info); + else + addParts(child, ',', topBlock, info, true); + } + }, + + addCode: function(topBlock, topOuts, blocks) + { + if (topBlock.length) + blocks.push('__code__.push(""', topBlock.join(""), ');'); + if (topOuts.length) + blocks.push('__out__.push(', topOuts.join(","), ');'); + topBlock.splice(0, topBlock.length); + topOuts.splice(0, topOuts.length); + }, + + addLocals: function(blocks) + { + var varNames = []; + this.getVarNames(varNames); + + var map = {}; + for (var i = 0; i < varNames.length; ++i) + { + var name = varNames[i]; + if ( map.hasOwnProperty(name) ) + continue; + + map[name] = 1; + var names = name.split("."); + blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); + } + }, + + compileDOM: function() + { + var path = []; + var blocks = []; + this.domArgs = []; + path.embedIndex = 0; + path.loopIndex = 0; + path.staticIndex = 0; + path.renderIndex = 0; + var nodeCount = this.generateDOM(path, blocks, this.domArgs); + + var fnBlock = ['r=(function (root, context, o']; + + for (var i = 0; i < path.staticIndex; ++i) + fnBlock.push(', ', 's'+i); + + for (var i = 0; i < path.renderIndex; ++i) + fnBlock.push(', ', 'd'+i); + + fnBlock.push(') {'); + for (var i = 0; i < path.loopIndex; ++i) + fnBlock.push('var l', i, ' = 0;'); + for (var i = 0; i < path.embedIndex; ++i) + fnBlock.push('var e', i, ' = 0;'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (context) {'); + + fnBlock.push(blocks.join("")); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('return ', nodeCount, ';'); + fnBlock.push('})'); + + function __bind__(object, fn) + { + return function(event) { return fn.apply(object, [event]); }; + } + + function __link__(node, tag, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var domArgs = [node, tag.tag.context, 0]; + domArgs.push.apply(domArgs, tag.tag.domArgs); + domArgs.push.apply(domArgs, args); + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs); + return tag.tag.renderDOM.apply(tag.tag.subject, domArgs); + } + + var self = this; + function __loop__(iter, fn) + { + var nodeCount = 0; + for (var i = 0; i < iter.length; ++i) + { + iter[i][0] = i; + iter[i][1] = nodeCount; + nodeCount += fn.apply(this, iter[i]); + //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount); + } + return nodeCount; + } + + function __path__(parent, offset) + { + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); + var root = parent; + + for (var i = 2; i < arguments.length; ++i) + { + var index = arguments[i]; + if (i == 3) + index += offset; + + if (index == -1) + parent = parent.parentNode; + else + parent = parent.childNodes[index]; + } + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); + return parent; + } + + var js = fnBlock.join(""); + //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); + var r = null; + eval(js); + this.renderDOM = r; + }, + + generateDOM: function(path, blocks, args) + { + if (this.listeners || this.props) + this.generateNodePath(path, blocks); + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + { + var val = this.listeners[i+1]; + var arg = generateArg(val, path, args); + //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + } + } + + if (this.props) + { + for (var name in this.props) + { + var val = this.props[name]; + var arg = generateArg(val, path, args); + blocks.push('node.', name, ' = ', arg, ';'); + } + } + + this.generateChildDOM(path, blocks, args); + return 1; + }, + + generateNodePath: function(path, blocks) + { + blocks.push("var node = __path__(root, o"); + for (var i = 0; i < path.length; ++i) + blocks.push(",", path[i]); + blocks.push(");"); + }, + + generateChildDOM: function(path, blocks, args) + { + path.push(0); + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args); + else + path[path.length-1] += '+1'; + } + path.pop(); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateEmbed.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.value = oldTag ? oldTag.value : parseValue(args[0]); + this.attrs = oldTag ? oldTag.attrs : {}; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args[1]; + for (var name in attrs) + { + var val = parseValue(attrs[name]); + this.attrs[name] = val; + readPartNames(val, this.vars); + } + + return creator(this, DomplateEmbed); + }, + + getVarNames: function(names) + { + if (this.value instanceof Parts) + names.push(this.value.parts[0].name); + + if (this.vars) + names.push.apply(names, this.vars); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + blocks.push('__link__('); + addParts(this.value, '', blocks, info); + blocks.push(', __code__, __out__, {'); + + var lastName = null; + for (var name in this.attrs) + { + if (lastName) + blocks.push(','); + lastName = name; + + var val = this.attrs[name]; + blocks.push('"', name, '":'); + addParts(val, '', blocks, info); + } + + blocks.push('});'); + //this.generateChildMarkup(topBlock, topOuts, blocks, info); + }, + + generateDOM: function(path, blocks, args) + { + var embedName = 'e'+path.embedIndex++; + + this.generateNodePath(path, blocks); + + var valueName = 'd' + path.renderIndex++; + var argsName = 'd' + path.renderIndex++; + blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); + + return embedName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateLoop.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.varName = oldTag ? oldTag.varName : args[0]; + this.iter = oldTag ? oldTag.iter : parseValue(args[1]); + this.vars = []; + + this.children = oldTag ? copyArray(oldTag.children) : []; + + var offset = Math.min(args.length, 2); + parseChildren(args, offset, this.vars, this.children); + + return creator(this, DomplateLoop); + }, + + getVarNames: function(names) + { + if (this.iter instanceof Parts) + names.push(this.iter.parts[0].name); + + DomplateTag.prototype.getVarNames.apply(this, [names]); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + var iterName; + if (this.iter instanceof Parts) + { + var part = this.iter.parts[0]; + iterName = part.name; + + if (part.format) + { + for (var i = 0; i < part.format.length; ++i) + iterName = part.format[i] + "(" + iterName + ")"; + } + } + else + iterName = this.iter; + + blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {'); + this.generateChildMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + blocks.push('}]);'); + }, + + generateDOM: function(path, blocks, args) + { + var iterName = 'd'+path.renderIndex++; + var counterName = 'i'+path.loopIndex; + var loopName = 'l'+path.loopIndex++; + + if (!path.length) + path.push(-1, 0); + + var preIndex = path.renderIndex; + path.renderIndex = 0; + + var nodeCount = 0; + + var subBlocks = []; + var basePath = path[path.length-1]; + for (var i = 0; i < this.children.length; ++i) + { + path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount; + + var child = this.children[i]; + if (isTag(child)) + nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args); + else + nodeCount += '+1'; + } + + path[path.length-1] = basePath+'+'+loopName; + + blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName); + for (var i = 0; i < path.renderIndex; ++i) + blocks.push(',d'+i); + blocks.push(') {'); + blocks.push(subBlocks.join("")); + blocks.push('return ', nodeCount, ';'); + blocks.push('}]);'); + + path.renderIndex = preIndex; + + return loopName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function Variable(name, format) +{ + this.name = name; + this.format = format; +} + +function Parts(parts) +{ + this.parts = parts; +} + +// ************************************************************************************************ + +function parseParts(str) +{ + var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g; + var index = 0; + var parts = []; + + var m; + while (m = re.exec(str)) + { + var pre = str.substr(index, (re.lastIndex-m[0].length)-index); + if (pre) + parts.push(pre); + + var expr = m[1].split("|"); + parts.push(new Variable(expr[0], expr.slice(1))); + index = re.lastIndex; + } + + if (!index) + return str; + + var post = str.substr(index); + if (post) + parts.push(post); + + return new Parts(parts); +} + +function parseValue(val) +{ + return typeof(val) == 'string' ? parseParts(val) : val; +} + +function parseChildren(args, offset, vars, children) +{ + for (var i = offset; i < args.length; ++i) + { + var val = parseValue(args[i]); + children.push(val); + readPartNames(val, vars); + } +} + +function readPartNames(val, vars) +{ + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + vars.push(part.name); + } + } +} + +function generateArg(val, path, args) +{ + if (val instanceof Parts) + { + var vals = []; + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var varName = 'd'+path.renderIndex++; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + varName = part.format[j] + '(' + varName + ')'; + } + + vals.push(varName); + } + else + vals.push('"'+part.replace(/"/g, '\\"')+'"'); + } + + return vals.join('+'); + } + else + { + args.push(val); + return 's' + path.staticIndex++; + } +} + +function addParts(val, delim, block, info, escapeIt) +{ + var vals = []; + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var partName = part.name; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + partName = part.format[j] + "(" + partName + ")"; + } + + if (escapeIt) + vals.push("__escape__(" + partName + ")"); + else + vals.push(partName); + } + else + vals.push('"'+ part + '"'); + } + } + else if (isTag(val)) + { + info.args.push(val); + vals.push('s'+info.argIndex++); + } + else + vals.push('"'+ val + '"'); + + var parts = vals.join(delim); + if (parts) + block.push(delim, parts); +} + +function isTag(obj) +{ + return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag; +} + +function creator(tag, cons) +{ + var fn = new Function( + "var tag = arguments.callee.tag;" + + "var cons = arguments.callee.cons;" + + "var newTag = new cons();" + + "return newTag.merge(arguments, tag);"); + + fn.tag = tag; + fn.cons = cons; + extend(fn, Renderer); + + return fn; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function copyArray(oldArray) +{ + var ary = []; + if (oldArray) + for (var i = 0; i < oldArray.length; ++i) + ary.push(oldArray[i]); + return ary; +} + +function copyObject(l, r) +{ + var m = {}; + extend(m, l); + extend(m, r); + return m; +} + +function extend(l, r) +{ + for (var n in r) + l[n] = r[n]; +} + +function addEvent(object, name, handler) +{ + if (document.all) + object.attachEvent("on"+name, handler); + else + object.addEventListener(name, handler, false); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function ArrayIterator(array) +{ + var index = -1; + + this.next = function() + { + if (++index >= array.length) + throw StopIteration; + + return array[index]; + }; +} + +function StopIteration() {} + +FBL.$break = function() +{ + throw StopIteration; +}; + +// ************************************************************************************************ + +var Renderer = +{ + renderHTML: function(args, outputs, self) + { + var code = []; + var markupArgs = [code, this.tag.context, args, outputs]; + markupArgs.push.apply(markupArgs, this.tag.markupArgs); + this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs); + return code.join(""); + }, + + insertRows: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + var div = doc.createElement("div"); + div.innerHTML = ""+html+"
      "; + + var tbody = div.firstChild.firstChild; + var parent = before.tagName == "TR" ? before.parentNode : before; + var after = before.tagName == "TR" ? before.nextSibling : null; + + var firstRow = tbody.firstChild, lastRow; + while (tbody.firstChild) + { + lastRow = tbody.firstChild; + if (after) + parent.insertBefore(lastRow, after); + else + parent.appendChild(lastRow); + } + + var offset = 0; + if (before.tagName == "TR") + { + var node = firstRow.parentNode.firstChild; + for (; node && node != firstRow; node = node.nextSibling) + ++offset; + } + + var domArgs = [firstRow, this.tag.context, offset]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + return [firstRow, lastRow]; + }, + + insertBefore: function(args, before, self) + { + return this.insertNode(args, before.ownerDocument, before, false, self); + }, + + insertAfter: function(args, after, self) + { + return this.insertNode(args, after.ownerDocument, after, true, self); + }, + + insertNode: function(args, doc, element, isAfter, self) + { + if (!args) + args = {}; + + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode html: "+html+"\n"); + + var doc = element.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + if (isAfter) + { + while (womb.firstChild) + if (element.nextSibling) + element.parentNode.insertBefore(womb.firstChild, element.nextSibling); + else + element.parentNode.appendChild(womb.firstChild); + } + else + { + while (womb.lastChild) + element.parentNode.insertBefore(womb.lastChild, element); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + /**/ + + /* + insertAfter: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + while (womb.firstChild) + if (before.nextSibling) + before.parentNode.insertBefore(womb.firstChild, before.nextSibling); + else + before.parentNode.appendChild(womb.firstChild); + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), + domArgs); + + return root; + }, + /**/ + + replace: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var root; + if (parent.nodeType == 1) + { + parent.innerHTML = html; + root = parent.firstChild; + } + else + { + if (!parent || parent.nodeType != 9) + parent = document; + + if (!womb || womb.ownerDocument != parent) + womb = parent.createElement("div"); + womb.innerHTML = html; + + root = womb.firstChild; + //womb.removeChild(root); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + + append: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n"); + + if (!womb || womb.ownerDocument != parent.ownerDocument) + womb = parent.ownerDocument.createElement("div"); + womb.innerHTML = html; + + // TODO: xxxpedro domplate port to Firebug + var root = womb.firstChild; + while (womb.firstChild) + parent.appendChild(womb.firstChild); + + // clearing element reference to avoid reference error in IE8 when switching contexts + womb = null; + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + } +}; + +// ************************************************************************************************ + +function defineTags() +{ + for (var i = 0; i < arguments.length; ++i) + { + var tagName = arguments[i]; + var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);"); + fn.DomplateTag = DomplateTag; + + var fnName = tagName.toUpperCase(); + FBL[fnName] = fn; + } +} + +defineTags( + "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr", + "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select", + "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe" +); + +})(); + + +/* See license.txt for terms of usage */ + +var FirebugReps = FBL.ns(function() { with (FBL) { + + +// ************************************************************************************************ +// Common Tags + +var OBJECTBOX = this.OBJECTBOX = + SPAN({"class": "objectBox objectBox-$className"}); + +var OBJECTBLOCK = this.OBJECTBLOCK = + DIV({"class": "objectBox objectBox-$className"}); + +var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation + A({ + "class": "objectLink objectLink-$className a11yFocus", + href: "javascript:void(0)", + _repObject: "$object" + }) + : // Other browsers + A({ + "class": "objectLink objectLink-$className a11yFocus", + _repObject: "$object" + }); + + +// ************************************************************************************************ + +this.Undefined = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("undefined"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "undefined", + + supportsObject: function(object, type) + { + return type == "undefined"; + } +}); + +// ************************************************************************************************ + +this.Null = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("null"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "null", + + supportsObject: function(object, type) + { + return object == null; + } +}); + +// ************************************************************************************************ + +this.Nada = domplate(Firebug.Rep, +{ + tag: SPAN(""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "nada" +}); + +// ************************************************************************************************ + +this.Number = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "number", + + supportsObject: function(object, type) + { + return type == "boolean" || type == "number"; + } +}); + +// ************************************************************************************************ + +this.String = domplate(Firebug.Rep, +{ + tag: OBJECTBOX(""$object""), + + shortTag: OBJECTBOX(""$object|cropString""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "string", + + supportsObject: function(object, type) + { + return type == "string"; + } +}); + +// ************************************************************************************************ + +this.Text = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + shortTag: OBJECTBOX("$object|cropString"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "text" +}); + +// ************************************************************************************************ + +this.Caption = domplate(Firebug.Rep, +{ + tag: SPAN({"class": "caption"}, "$object") +}); + +// ************************************************************************************************ + +this.Warning = domplate(Firebug.Rep, +{ + tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR") +}); + +// ************************************************************************************************ + +this.Func = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("$object|summarizeFunction"), + + summarizeFunction: function(fn) + { + var fnRegex = /function ([^(]+\([^)]*\)) \{/; + var fnText = safeToString(fn); + + var m = fnRegex.exec(fnText); + return m ? m[1] : "function()"; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copySource: function(fn) + { + copyToClipboard(safeToString(fn)); + }, + + monitor: function(fn, script, monitored) + { + if (monitored) + Firebug.Debugger.unmonitorScript(fn, script, "monitor"); + else + Firebug.Debugger.monitorScript(fn, script, "monitor"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "function", + + supportsObject: function(object, type) + { + return isFunction(object); + }, + + inspectObject: function(fn, context) + { + var sourceLink = findSourceForFunction(fn, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + if (FBTrace.DBG_FUNCTION_NAME) + FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink); + }, + + getTooltip: function(fn, context) + { + var script = findScriptForFunctionInContext(context, fn); + if (script) + return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]); + else + if (fn.toString) + return fn.toString(); + }, + + getTitle: function(fn, context) + { + var name = fn.name ? fn.name : "function"; + return name + "()"; + }, + + getContextMenuItems: function(fn, target, context, script) + { + if (!script) + script = findScriptForFunctionInContext(context, fn); + if (!script) + return; + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = script ? getFunctionName(script, context) : fn.name; + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, fn) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); + +// ************************************************************************************************ +/* +this.jsdScript = domplate(Firebug.Rep, +{ + copySource: function(script) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.copySource(fn); + }, + + monitor: function(fn, script, monitored) + { + fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.monitor(fn, script, monitored); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "jsdScript", + inspectable: false, + + supportsObject: function(object, type) + { + return object instanceof jsdIScript; + }, + + inspectObject: function(script, context) + { + var sourceLink = getSourceLinkForScript(script, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + }, + + getRealObject: function(script, context) + { + return script; + }, + + getTooltip: function(script) + { + return $STRF("jsdIScript", [script.tag]); + }, + + getTitle: function(script, context) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.getTitle(fn, context); + }, + + getContextMenuItems: function(script, target, context) + { + var fn = script.functionObject.getWrappedValue(); + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = getFunctionName(script, context); + + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, script) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); +/**/ +//************************************************************************************************ + +this.Obj = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + SPAN({"class": "objectTitle"}, "$object|getTitle "), + + SPAN({"class": "objectProps"}, + SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"), + FOR("prop", "$object|propIterator", + SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"), + SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"), + TAG("$prop.tag", {object: "$prop.object"}), + SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim") + ), + SPAN({"class": "objectRightBrace"}, "}") + ) + ), + + propNumberTag: + SPAN({"class": "objectProp-number"}, "$object"), + + propStringTag: + SPAN({"class": "objectProp-string"}, ""$object""), + + propObjectTag: + SPAN({"class": "objectProp-object"}, "$object"), + + propIterator: function (object) + { + ///Firebug.ObjectShortIteratorMax; + var maxLength = 55; // default max length for long representation + + if (!object) + return []; + + var props = []; + var length = 0; + + var numProperties = 0; + var numPropertiesShown = 0; + var maxLengthReached = false; + + var lib = this; + + var propRepsMap = + { + "boolean": this.propNumberTag, + "number": this.propNumberTag, + "string": this.propStringTag, + "object": this.propObjectTag + }; + + try + { + var title = Firebug.Rep.getTitle(object); + length += title.length; + + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var type = typeof(value); + if (type == "boolean" || + type == "number" || + (type == "string" && value) || + (type == "object" && value && value.toString)) + { + var tag = propRepsMap[type]; + + var value = (type == "object") ? + Firebug.getRep(value).getTitle(value) : + value + ""; + + length += name.length + value.length + 4; + + if (length <= maxLength) + { + props.push({ + tag: tag, + name: name, + object: value, + equal: "=", + delim: ", " + }); + + numPropertiesShown++; + } + else + maxLengthReached = true; + + } + + numProperties++; + + if (maxLengthReached && numProperties > numPropertiesShown) + break; + } + + if (numProperties > numPropertiesShown) + { + props.push({ + object: "...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }); + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + fb_1_6_propIterator: function (object, max) + { + max = max || 3; + if (!object) + return []; + + var props = []; + var len = 0, count = 0; + + try + { + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof(value); + if (t == "boolean" || t == "number" || (t == "string" && value) + || (t == "object" && value && value.toString)) + { + var rep = Firebug.getRep(value); + var tag = rep.shortTag || rep.tag; + if (t == "object") + { + value = rep.getTitle(value); + tag = rep.titleTag; + } + count++; + if (count <= max) + props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "}); + else + break; + } + } + if (count > max) + { + props[Math.max(1,max-1)] = { + object: "more...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }; + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + /* + propIterator: function (object) + { + if (!object) + return []; + + var props = []; + var len = 0; + + try + { + for (var name in object) + { + var val; + try + { + val = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof val; + if (t == "boolean" || t == "number" || (t == "string" && val) + || (t == "object" && !isFunction(val) && val && val.toString)) + { + var title = (t == "object") + ? Firebug.getRep(val).getTitle(val) + : val+""; + + len += name.length + title.length + 1; + if (len < 50) + props.push({name: name, value: title}); + else + break; + } + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + + return props; + }, + /**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object, type) + { + return true; + } +}); + + +// ************************************************************************************************ + +this.Arr = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|arrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + SPAN({"class": "arrayRightBracket", role : "presentation"}, "]") + ), + + shortTag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|shortArrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + // TODO: xxxpedro - confirm this on Firebug + //FOR("prop", "$object|shortPropIterator", + // " $prop.name=", + // SPAN({"class": "objectPropValue"}, "$prop.value|cropString") + //), + SPAN({"class": "arrayRightBracket"}, "]") + ), + + arrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + return items; + }, + + shortArrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length && i < 3; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + if (array.length > 3) + items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""}); + + return items; + }, + + shortPropIterator: this.Obj.propIterator, + + getItemIndex: function(child) + { + var arrayIndex = 0; + for (child = child.previousSibling; child; child = child.previousSibling) + { + if (child.repObject) + ++arrayIndex; + } + return arrayIndex; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "array", + + supportsObject: function(object) + { + return this.isArray(object); + }, + + // http://code.google.com/p/fbug/issues/detail?id=874 + // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007 + isArray: function(obj) { + try { + if (!obj) + return false; + else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8) + return true; + else if (isFinite(obj.length) && isFunction(obj.splice)) + return true; + else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments + return true; + else if (instanceOf(obj, "HTMLCollection")) + return true; + else if (instanceOf(obj, "NodeList")) + return true; + else + return false; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */ + FBTrace.sysout("isArray Fails on obj", obj); + } + } + + return false; + }, + // END Yahoo BSD SOURCE See license below. + + getTitle: function(object, context) + { + return "[" + object.length + "]"; + } +}); + +// ************************************************************************************************ + +this.Property = domplate(Firebug.Rep, +{ + supportsObject: function(object) + { + return object instanceof Property; + }, + + getRealObject: function(prop, context) + { + return prop.object[prop.name]; + }, + + getTitle: function(prop, context) + { + return prop.name; + } +}); + +// ************************************************************************************************ + +this.NetFile = domplate(this.Obj, +{ + supportsObject: function(object) + { + return object instanceof Firebug.NetFile; + }, + + browseObject: function(file, context) + { + openNewTab(file.href); + return true; + }, + + getRealObject: function(file, context) + { + return null; + } +}); + +// ************************************************************************************************ + +this.Except = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, "$object.message"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "exception", + + supportsObject: function(object) + { + return object instanceof ErrorCopy; + } +}); + + +// ************************************************************************************************ + +this.Element = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), + FOR("attr", "$object|attrIterator", + " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ + ), + ">" + ), + + shortTag: + OBJECTLINK( + SPAN({"class": "$object|getVisible"}, + SPAN({"class": "selectorTag"}, "$object|getSelectorTag"), + SPAN({"class": "selectorId"}, "$object|getSelectorId"), + SPAN({"class": "selectorClass"}, "$object|getSelectorClass"), + SPAN({"class": "selectorValue"}, "$object|getValue") + ) + ), + + getVisible: function(elt) + { + return isVisible(elt) ? "" : "selectorHidden"; + }, + + getSelectorTag: function(elt) + { + return elt.nodeName.toLowerCase(); + }, + + getSelectorId: function(elt) + { + return elt.id ? "#" + elt.id : ""; + }, + + getSelectorClass: function(elt) + { + return elt.className ? "." + elt.className.split(" ")[0] : ""; + }, + + getValue: function(elt) + { + // TODO: xxxpedro + return ""; + var value; + if (elt instanceof HTMLImageElement) + value = getFileName(elt.src); + else if (elt instanceof HTMLAnchorElement) + value = getFileName(elt.href); + else if (elt instanceof HTMLInputElement) + value = elt.value; + else if (elt instanceof HTMLFormElement) + value = getFileName(elt.action); + else if (elt instanceof HTMLScriptElement) + value = getFileName(elt.src); + + return value ? " " + cropString(value, 20) : ""; + }, + + attrIterator: function(elt) + { + var attrs = []; + var idAttr, classAttr; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName && attr.nodeName.indexOf("firebug-") != -1) + continue; + else if (attr.nodeName == "id") + idAttr = attr; + else if (attr.nodeName == "class") + classAttr = attr; + else + attrs.push(attr); + } + } + if (classAttr) + attrs.splice(0, 0, classAttr); + if (idAttr) + attrs.splice(0, 0, idAttr); + + return attrs; + }, + + shortAttrIterator: function(elt) + { + var attrs = []; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName == "id" || attr.nodeName == "class") + attrs.push(attr); + } + } + + return attrs; + }, + + getHidden: function(elt) + { + return isVisible(elt) ? "" : "nodeHidden"; + }, + + getXPath: function(elt) + { + return getElementTreeXPath(elt); + }, + + // TODO: xxxpedro remove this? + getNodeText: function(element) + { + var text = element.textContent; + if (Firebug.showFullTextNodes) + return text; + else + return cropString(text, 50); + }, + /**/ + + getNodeTextGroups: function(element) + { + var text = element.textContent; + if (!Firebug.showFullTextNodes) + { + text=cropString(text,50); + } + + var escapeGroups=[]; + + if (Firebug.showTextNodesWithWhitespace) + escapeGroups.push({ + 'group': 'whitespace', + 'class': 'nodeWhiteSpace', + 'extra': { + '\t': '_Tab', + '\n': '_Para', + ' ' : '_Space' + } + }); + if (Firebug.showTextNodesWithEntities) + escapeGroups.push({ + 'group':'text', + 'class':'nodeTextEntity', + 'extra':{} + }); + + if (escapeGroups.length) + return escapeGroupsForEntities(text, escapeGroups); + else + return [{str:text,'class':'',extra:''}]; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyHTML: function(elt) + { + var html = getElementXML(elt); + copyToClipboard(html); + }, + + copyInnerHTML: function(elt) + { + copyToClipboard(elt.innerHTML); + }, + + copyXPath: function(elt) + { + var xpath = getElementXPath(elt); + copyToClipboard(xpath); + }, + + persistor: function(context, xpath) + { + var elts = xpath + ? getElementsByXPath(context.window.document, xpath) + : null; + + return elts && elts.length ? elts[0] : null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "element", + + supportsObject: function(object) + { + //return object instanceof Element || object.nodeType == 1 && typeof object.nodeName == "string"; + return instanceOf(object, "Element"); + }, + + browseObject: function(elt, context) + { + var tag = elt.nodeName.toLowerCase(); + if (tag == "script") + openNewTab(elt.src); + else if (tag == "link") + openNewTab(elt.href); + else if (tag == "a") + openNewTab(elt.href); + else if (tag == "img") + openNewTab(elt.src); + + return true; + }, + + persistObject: function(elt, context) + { + var xpath = getElementXPath(elt); + + return bind(this.persistor, top, xpath); + }, + + getTitle: function(element, context) + { + return getElementCSSSelector(element); + }, + + getTooltip: function(elt) + { + return this.getXPath(elt); + }, + + getContextMenuItems: function(elt, target, context) + { + var monitored = areEventsMonitored(elt, null, context); + + return [ + {label: "CopyHTML", command: bindFixed(this.copyHTML, this, elt) }, + {label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) }, + {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) }, + "-", + {label: "ShowEventsInConsole", type: "checkbox", checked: monitored, + command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) }, + "-", + {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) } + ]; + } +}); + +// ************************************************************************************************ + +this.TextNode = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "TextNode"), + " textContent="", SPAN({"class": "nodeValue"}, "$object.textContent|cropString"), """, + ">" + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "textNode", + + supportsObject: function(object) + { + return object instanceof Text; + } +}); + +// ************************************************************************************************ + +this.Document = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(doc) + { + return doc.location ? getFileName(doc.location.href) : ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Document || object instanceof XMLDocument; + return instanceOf(object, "Document"); + }, + + browseObject: function(doc, context) + { + openNewTab(doc.location.href); + return true; + }, + + persistObject: function(doc, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window.document; + }, + + getTitle: function(win, context) + { + return "document"; + }, + + getTooltip: function(doc) + { + return doc.location.href; + } +}); + +// ************************************************************************************************ + +this.StyleSheet = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(styleSheet) + { + return getFileName(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(styleSheet) + { + copyToClipboard(styleSheet.href); + }, + + openInTab: function(styleSheet) + { + openNewTab(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof CSSStyleSheet; + return instanceOf(object, "CSSStyleSheet"); + }, + + browseObject: function(styleSheet, context) + { + openNewTab(styleSheet.href); + return true; + }, + + persistObject: function(styleSheet, context) + { + return bind(this.persistor, top, styleSheet.href); + }, + + getTooltip: function(styleSheet) + { + return styleSheet.href; + }, + + getContextMenuItems: function(styleSheet, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) } + ]; + }, + + persistor: function(context, href) + { + return getStyleSheetByHref(href, context); + } +}); + +// ************************************************************************************************ + +this.Window = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(win) + { + try + { + return (win && win.location && !win.closed) ? getFileName(win.location.href) : ""; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.Window window closed?"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + return instanceOf(object, "Window"); + }, + + browseObject: function(win, context) + { + openNewTab(win.location.href); + return true; + }, + + persistObject: function(win, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window; + }, + + getTitle: function(win, context) + { + return "window"; + }, + + getTooltip: function(win) + { + if (win && !win.closed) + return win.location.href; + } +}); + +// ************************************************************************************************ + +this.Event = domplate(Firebug.Rep, +{ + tag: TAG("$copyEventTag", {object: "$object|copyEvent"}), + + copyEventTag: + OBJECTLINK("$object|summarizeEvent"), + + summarizeEvent: function(event) + { + var info = [event.type, ' ']; + + var eventFamily = getEventFamily(event.type); + if (eventFamily == "mouse") + info.push("clientX=", event.clientX, ", clientY=", event.clientY); + else if (eventFamily == "key") + info.push("charCode=", event.charCode, ", keyCode=", event.keyCode); + + return info.join(""); + }, + + copyEvent: function(event) + { + return new EventCopy(event); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Event || object instanceof EventCopy; + return instanceOf(object, "Event") || instanceOf(object, "EventCopy"); + }, + + getTitle: function(event, context) + { + return "Event " + event.type; + } +}); + +// ************************************************************************************************ + +this.SourceLink = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + hideSourceLink: function(sourceLink) + { + return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true; + }, + + getSourceLinkTitle: function(sourceLink) + { + if (!sourceLink) + return ""; + + try + { + var fileName = getFileName(sourceLink.href); + fileName = decodeURIComponent(fileName); + fileName = cropString(fileName, 17); + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'"+fileName+"\': "+exc, exc); + } + + return typeof sourceLink.line == "number" ? + fileName + " (line " + sourceLink.line + ")" : + fileName; + + // TODO: xxxpedro + //return $STRF("Line", [fileName, sourceLink.line]); + }, + + copyLink: function(sourceLink) + { + copyToClipboard(sourceLink.href); + }, + + openInTab: function(sourceLink) + { + openNewTab(sourceLink.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceLink", + + supportsObject: function(object) + { + return object instanceof SourceLink; + }, + + getTooltip: function(sourceLink) + { + return decodeURI(sourceLink.href); + }, + + inspectObject: function(sourceLink, context) + { + if (sourceLink.type == "js") + { + var scriptFile = getSourceFileByHref(sourceLink.href, context); + if (scriptFile) + return Firebug.chrome.select(sourceLink); + } + else if (sourceLink.type == "css") + { + // If an object is defined, treat it as the highest priority for + // inspect actions + if (sourceLink.object) { + Firebug.chrome.select(sourceLink.object); + return; + } + + var stylesheet = getStyleSheetByHref(sourceLink.href, context); + if (stylesheet) + { + var ownerNode = stylesheet.ownerNode; + if (ownerNode) + { + Firebug.chrome.select(sourceLink, "html"); + return; + } + + var panel = context.getPanel("stylesheet"); + if (panel && panel.getRuleByLine(stylesheet, sourceLink.line)) + return Firebug.chrome.select(sourceLink); + } + } + + // Fallback is to just open the view-source window on the file + viewSource(sourceLink.href, sourceLink.line); + }, + + browseObject: function(sourceLink, context) + { + openNewTab(sourceLink.href); + return true; + }, + + getContextMenuItems: function(sourceLink, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceFile = domplate(this.SourceLink, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + persistor: function(context, href) + { + return getSourceFileByHref(href, context); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceFile", + + supportsObject: function(object) + { + return object instanceof SourceFile; + }, + + persistObject: function(sourceFile) + { + return bind(this.persistor, top, sourceFile.href); + }, + + browseObject: function(sourceLink, context) + { + }, + + getTooltip: function(sourceFile) + { + return sourceFile.href; + } +}); + +// ************************************************************************************************ + +this.StackFrame = domplate(Firebug.Rep, // XXXjjb Since the repObject is fn the stack does not have correct line numbers +{ + tag: + OBJECTBLOCK( + A({"class": "objectLink objectLink-function focusRow a11yFocus", _repObject: "$object.fn"}, "$object|getCallName"), + " ( ", + FOR("arg", "$object|argIterator", + TAG("$arg.tag", {object: "$arg.value"}), + SPAN({"class": "arrayComma"}, "$arg.delim") + ), + " )", + SPAN({"class": "objectLink-sourceLink objectLink"}, "$object|getSourceLinkTitle") + ), + + getCallName: function(frame) + { + //TODO: xxxpedro reps StackFrame + return frame.name || "anonymous"; + + //return getFunctionName(frame.script, frame.context); + }, + + getSourceLinkTitle: function(frame) + { + //TODO: xxxpedro reps StackFrame + var fileName = cropString(getFileName(frame.href), 20); + return fileName + (frame.lineNo ? " (line " + frame.lineNo + ")" : ""); + + var fileName = cropString(getFileName(frame.href), 17); + return $STRF("Line", [fileName, frame.lineNo]); + }, + + argIterator: function(frame) + { + if (!frame.args) + return []; + + var items = []; + + for (var i = 0; i < frame.args.length; ++i) + { + var arg = frame.args[i]; + + if (!arg) + break; + + var rep = Firebug.getRep(arg.value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var delim = (i == frame.args.length-1 ? "" : ", "); + + items.push({name: arg.name, value: arg.value, tag: tag, delim: delim}); + } + + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackFrame", + + supportsObject: function(object) + { + return object instanceof StackFrame; + }, + + inspectObject: function(stackFrame, context) + { + var sourceLink = new SourceLink(stackFrame.href, stackFrame.lineNo, "js"); + Firebug.chrome.select(sourceLink); + }, + + getTooltip: function(stackFrame, context) + { + return $STRF("Line", [stackFrame.href, stackFrame.lineNo]); + } + +}); + +// ************************************************************************************************ + +this.StackTrace = domplate(Firebug.Rep, +{ + tag: + FOR("frame", "$object.frames focusRow", + TAG(this.StackFrame.tag, {object: "$frame"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackTrace", + + supportsObject: function(object) + { + return object instanceof StackTrace; + } +}); + +// ************************************************************************************************ + +this.jsdStackFrame = domplate(Firebug.Rep, +{ + inspectable: false, + + supportsObject: function(object) + { + return (object instanceof jsdIStackFrame) && (object.isValid); + }, + + getTitle: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + return getFunctionName(frame.script, context); + }, + + getTooltip: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + var sourceInfo = FBL.getSourceFileAndLineByScript(context, frame.script, frame); + if (sourceInfo) + return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]); + else + return $STRF("Line", [frame.script.fileName, frame.line]); + }, + + getContextMenuItems: function(frame, target, context) + { + var fn = frame.script.functionObject.getWrappedValue(); + return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script); + } +}); + +// ************************************************************************************************ + +this.ErrorMessage = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({ + $hasTwisty: "$object|hasStackTrace", + $hasBreakSwitch: "$object|hasBreakSwitch", + $breakForError: "$object|hasErrorBreak", + _repObject: "$object", + _stackTrace: "$object|getLastErrorStackTrace", + onclick: "$onToggleError"}, + + DIV({"class": "errorTitle a11yFocus", role : 'checkbox', 'aria-checked' : 'false'}, + "$object.message|getMessage" + ), + DIV({"class": "errorTrace"}), + DIV({"class": "errorSourceBox errorSource-$object|getSourceType"}, + IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':'false', title: "Break on this error"}), + A({"class": "errorSource a11yFocus"}, "$object|getLine") + ), + TAG(this.SourceLink.tag, {object: "$object|getSourceLink"}) + ), + + getLastErrorStackTrace: function(error) + { + return error.trace; + }, + + hasStackTrace: function(error) + { + var url = error.href.toString(); + var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1); + return !fromCommandLine && error.trace; + }, + + hasBreakSwitch: function(error) + { + return error.href && error.lineNo > 0; + }, + + hasErrorBreak: function(error) + { + return fbs.hasErrorBreakpoint(error.href, error.lineNo); + }, + + getMessage: function(message) + { + var re = /\[Exception... "(.*?)" nsresult:/; + var m = re.exec(message); + return m ? m[1] : message; + }, + + getLine: function(error) + { + if (error.category == "js") + { + if (error.source) + return cropString(error.source, 80); + else if (error.href && error.href.indexOf("XPCSafeJSObjectWrapper") == -1) + return cropString(error.getSourceLine(), 80); + } + }, + + getSourceLink: function(error) + { + var ext = error.category == "css" ? "css" : "js"; + return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null; + }, + + getSourceType: function(error) + { + // Errors occurring inside of HTML event handlers look like "foo.html (line 1)" + // so let's try to skip those + if (error.source) + return "syntax"; + else if (error.lineNo == 1 && getFileExtension(error.href) != "js") + return "none"; + else if (error.category == "css") + return "none"; + else if (!error.href || !error.lineNo) + return "none"; + else + return "exec"; + }, + + onToggleError: function(event) + { + var target = event.currentTarget; + if (hasClass(event.target, "errorBreak")) + { + this.breakOnThisError(target.repObject); + } + else if (hasClass(event.target, "errorSource")) + { + var panel = Firebug.getElementPanel(event.target); + this.inspectObject(target.repObject, panel.context); + } + else if (hasClass(event.target, "errorTitle")) + { + var traceBox = target.childNodes[1]; + toggleClass(target, "opened"); + event.target.setAttribute('aria-checked', hasClass(target, "opened")); + if (hasClass(target, "opened")) + { + if (target.stackTrace) + var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox); + if (Firebug.A11yModel.enabled) + { + var panel = Firebug.getElementPanel(event.target); + dispatch([Firebug.A11yModel], "onLogRowContentCreated", [panel , traceBox]); + } + } + else + clearNode(traceBox); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyError: function(error) + { + var message = [ + this.getMessage(error.message), + error.href, + "Line " + error.lineNo + ]; + copyToClipboard(message.join("\n")); + }, + + breakOnThisError: function(error) + { + if (this.hasErrorBreak(error)) + Firebug.Debugger.clearErrorBreakpoint(error.href, error.lineNo); + else + Firebug.Debugger.setErrorBreakpoint(error.href, error.lineNo); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "errorMessage", + inspectable: false, + + supportsObject: function(object) + { + return object instanceof ErrorMessage; + }, + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + FirebugReps.SourceLink.inspectObject(sourceLink, context); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + var items = [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) } + ]; + + if (error.category == "css") + { + items.push( + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + + optionMenu("BreakOnAllErrors", "breakOnErrors") + ); + } + + return items; + } +}); + +// ************************************************************************************************ + +this.Assert = domplate(Firebug.Rep, +{ + tag: + DIV( + DIV({"class": "errorTitle"}), + DIV({"class": "assertDescription"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "assert", + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + Firebug.chrome.select(sourceLink); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + return [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) }, + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors, + command: bindFixed(this.breakOnAllErrors, this, error) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceText = domplate(Firebug.Rep, +{ + tag: + DIV( + FOR("line", "$object|lineIterator", + DIV({"class": "sourceRow", role : "presentation"}, + SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"), + SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text") + ) + ) + ), + + lineIterator: function(sourceText) + { + var maxLineNoChars = (sourceText.lines.length + "").length; + var list = []; + + for (var i = 0; i < sourceText.lines.length; ++i) + { + // Make sure all line numbers are the same width (with a fixed-width font) + var lineNo = (i+1) + ""; + while (lineNo.length < maxLineNoChars) + lineNo = " " + lineNo; + + list.push({lineNo: lineNo, text: sourceText.lines[i]}); + } + + return list; + }, + + getHTML: function(sourceText) + { + return getSourceLineRange(sourceText, 1, sourceText.lines.length); + } +}); + +//************************************************************************************************ +this.nsIDOMHistory = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showHistory"}, + OBJECTLINK("$object|summarizeHistory") + ), + + className: "nsIDOMHistory", + + summarizeHistory: function(history) + { + try + { + var items = history.length; + return items + " history entries"; + } + catch(exc) + { + return "object does not support history (nsIDOMHistory)"; + } + }, + + showHistory: function(history) + { + try + { + var items = history.length; // if this throws, then unsupported + Firebug.chrome.select(history); + } + catch (exc) + { + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object, type) + { + return (object instanceof Ci.nsIDOMHistory); + } +}); + +// ************************************************************************************************ +this.ApplicationCache = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showApplicationCache"}, + OBJECTLINK("$object|summarizeCache") + ), + + summarizeCache: function(applicationCache) + { + try + { + return applicationCache.length + " items in offline cache"; + } + catch(exc) + { + return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264"; + } + }, + + showApplicationCache: function(event) + { + openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "applicationCache", + + supportsObject: function(object, type) + { + if (Ci.nsIDOMOfflineResourceList) + return (object instanceof Ci.nsIDOMOfflineResourceList); + } + +}); + +this.Storage = domplate(Firebug.Rep, +{ + tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")), + + summarize: function(storage) + { + return storage.length +" items in Storage"; + }, + show: function(storage) + { + openNewTab("http://dev.w3.org/html5/webstorage/#storage-0"); + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "Storage", + + supportsObject: function(object, type) + { + return (object instanceof Storage); + } + +}); + +// ************************************************************************************************ +Firebug.registerRep( + //this.nsIDOMHistory, // make this early to avoid exceptions + this.Undefined, + this.Null, + this.Number, + this.String, + this.Window, + //this.ApplicationCache, // must come before Arr (array) else exceptions. + //this.ErrorMessage, + this.Element, + //this.TextNode, + this.Document, + this.StyleSheet, + this.Event, + //this.SourceLink, + //this.SourceFile, + //this.StackTrace, + //this.StackFrame, + //this.jsdStackFrame, + //this.jsdScript, + //this.NetFile, + this.Property, + this.Except, + this.Arr +); + +Firebug.setDefaultReps(this.Func, this.Obj); + +}}); + +// ************************************************************************************************ +/* + * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source" + * in only this file reps.js. John J. Barton June 2007. + * +Software License Agreement (BSD License) + +Copyright (c) 2006, Yahoo! Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Yahoo! Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Yahoo! Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * / + */ + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var saveTimeout = 400; +var pageAmount = 10; + +// ************************************************************************************************ +// Globals + +var currentTarget = null; +var currentGroup = null; +var currentPanel = null; +var currentEditor = null; + +var defaultEditor = null; + +var originalClassName = null; + +var originalValue = null; +var defaultValue = null; +var previousValue = null; + +var invalidEditor = false; +var ignoreNextInput = false; + +// ************************************************************************************************ + +Firebug.Editor = extend(Firebug.Module, +{ + supportsStopEvent: true, + + dispatchName: "editor", + tabCharacter: " ", + + startEditing: function(target, value, editor) + { + this.stopEditing(); + + if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter")) + return; + + var panel = Firebug.getElementPanel(target); + if (!panel.editable) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.startEditing " + value, target); + + defaultValue = target.getAttribute("defaultValue"); + if (value == undefined) + { + var textContent = isIE ? "innerText" : "textContent"; + value = target[textContent]; + if (value == defaultValue) + value = ""; + } + + originalValue = previousValue = value; + + invalidEditor = false; + currentTarget = target; + currentPanel = panel; + currentGroup = getAncestorByClass(target, "editGroup"); + + currentPanel.editing = true; + + var panelEditor = currentPanel.getEditor(target, value); + currentEditor = editor ? editor : panelEditor; + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + var inlineParent = getInlineParent(target); + var targetSize = getOffsetSize(inlineParent); + + setClass(panel.panelNode, "editing"); + setClass(target, "editing"); + if (currentGroup) + setClass(currentGroup, "editing"); + + currentEditor.show(target, currentPanel, value, targetSize); + //dispatch(this.fbListeners, "onBeginEditing", [currentPanel, currentEditor, target, value]); + currentEditor.beginEditing(target, value); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Editor start panel "+currentPanel.name); + this.attachListeners(currentEditor, panel.context); + }, + + stopEditing: function(cancel) + { + if (!currentTarget) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.stopEditing cancel:" + cancel+" saveTimeout: "+this.saveTimeout); + + clearTimeout(this.saveTimeout); + delete this.saveTimeout; + + this.detachListeners(currentEditor, currentPanel.context); + + removeClass(currentPanel.panelNode, "editing"); + removeClass(currentTarget, "editing"); + if (currentGroup) + removeClass(currentGroup, "editing"); + + var value = currentEditor.getValue(); + if (value == defaultValue) + value = ""; + + var removeGroup = currentEditor.endEditing(currentTarget, value, cancel); + + try + { + if (cancel) + { + //dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, removeGroup && !originalValue]); + if (value != originalValue) + this.saveEditAndNotifyListeners(currentTarget, originalValue, previousValue); + + if (removeGroup && !originalValue && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else if (!value) + { + this.saveEditAndNotifyListeners(currentTarget, null, previousValue); + + if (removeGroup && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else + this.save(value); + } + catch (exc) + { + //throw exc.message; + //ERROR(exc); + } + + currentEditor.hide(); + currentPanel.editing = false; + + //dispatch(this.fbListeners, "onStopEdit", [currentPanel, currentEditor, currentTarget]); + //if (FBTrace.DBG_EDITOR) + // FBTrace.sysout("Editor stop panel "+currentPanel.name); + + currentTarget = null; + currentGroup = null; + currentPanel = null; + currentEditor = null; + originalValue = null; + invalidEditor = false; + + return value; + }, + + cancelEditing: function() + { + return this.stopEditing(true); + }, + + update: function(saveNow) + { + if (this.saveTimeout) + clearTimeout(this.saveTimeout); + + invalidEditor = true; + + currentEditor.layout(); + + if (saveNow) + this.save(); + else + { + var context = currentPanel.context; + this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.update saveTimeout: "+this.saveTimeout); + } + }, + + save: function(value) + { + if (!invalidEditor) + return; + + if (value == undefined) + value = currentEditor.getValue(); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.save saveTimeout: "+this.saveTimeout+" currentPanel: "+(currentPanel?currentPanel.name:"null")); + try + { + this.saveEditAndNotifyListeners(currentTarget, value, previousValue); + + previousValue = value; + invalidEditor = false; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("editor.save FAILS "+exc, exc); + } + }, + + saveEditAndNotifyListeners: function(currentTarget, value, previousValue) + { + currentEditor.saveEdit(currentTarget, value, previousValue); + //dispatch(this.fbListeners, "onSaveEdit", [currentPanel, currentEditor, currentTarget, value, previousValue]); + }, + + setEditTarget: function(element) + { + if (!element) + { + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, true]); + this.stopEditing(); + } + else if (hasClass(element, "insertBefore")) + this.insertRow(element, "before"); + else if (hasClass(element, "insertAfter")) + this.insertRow(element, "after"); + else + this.startEditing(element); + }, + + tabNextEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var nextEditable = currentTarget; + do + { + nextEditable = !value && currentGroup + ? getNextOutsider(nextEditable, currentGroup) + : getNextByClass(nextEditable, "editable"); + } + while (nextEditable && !nextEditable.offsetHeight); + + this.setEditTarget(nextEditable); + }, + + tabPreviousEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var prevEditable = currentTarget; + do + { + prevEditable = !value && currentGroup + ? getPreviousOutsider(prevEditable, currentGroup) + : getPreviousByClass(prevEditable, "editable"); + } + while (prevEditable && !prevEditable.offsetHeight); + + this.setEditTarget(prevEditable); + }, + + insertRow: function(relative, insertWhere) + { + var group = + relative || getAncestorByClass(currentTarget, "editGroup") || currentTarget; + var value = this.stopEditing(); + + currentPanel = Firebug.getElementPanel(group); + + currentEditor = currentPanel.getEditor(group, value); + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + currentGroup = currentEditor.insertNewRow(group, insertWhere); + if (!currentGroup) + return; + + var editable = hasClass(currentGroup, "editable") + ? currentGroup + : getNextByClass(currentGroup, "editable"); + + if (editable) + this.setEditTarget(editable); + }, + + insertRowForObject: function(relative) + { + var container = getAncestorByClass(relative, "insertInto"); + if (container) + { + relative = getChildByClass(container, "insertBefore"); + if (relative) + this.insertRow(relative, "before"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + attachListeners: function(editor, context) + { + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + addEvent(win, "resize", this.onResize); + addEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + + this.listeners = [ + chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this)) + ]; + + if (editor.arrowCompletion) + { + this.listeners.push( + chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)), + chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)), + chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)), + chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount)) + ); + } + + if (currentEditor.tabNavigation) + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")), + chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this)) + ); + } + else if (currentEditor.multiLine) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, insertTab) + ); + } + else + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this)) + ); + + if (currentEditor.tabCompletion) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)), + chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1)) + ); + } + } + }, + + detachListeners: function(editor, context) + { + if (!this.listeners) + return; + + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + removeEvent(win, "resize", this.onResize); + removeEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + if (chrome) + { + for (var i = 0; i < this.listeners.length; ++i) + chrome.keyIgnore(this.listeners[i]); + } + + delete this.listeners; + }, + + onResize: function(event) + { + currentEditor.layout(true); + }, + + onBlur: function(event) + { + if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box)) + this.stopEditing(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + Firebug.Module.initialize.apply(this, arguments); + + this.onResize = bindFixed(this.onResize, this); + this.onBlur = bind(this.onBlur, this); + }, + + disable: function() + { + this.stopEditing(); + }, + + showContext: function(browser, context) + { + this.stopEditing(); + }, + + showPanel: function(browser, panel) + { + this.stopEditing(); + } +}); + +// ************************************************************************************************ +// BaseEditor + +Firebug.BaseEditor = extend(Firebug.MeasureBox, +{ + getValue: function() + { + }, + + setValue: function(value) + { + }, + + show: function(target, panel, value, textSize, targetSize) + { + }, + + hide: function() + { + }, + + layout: function(forceAll) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for context menus within inline editors. + + getContextMenuItems: function(target) + { + var items = []; + items.push({label: "Cut", commandID: "cmd_cut"}); + items.push({label: "Copy", commandID: "cmd_copy"}); + items.push({label: "Paste", commandID: "cmd_paste"}); + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Editor Module listeners will get "onBeginEditing" just before this call + + beginEditing: function(target, value) + { + }, + + // Editor Module listeners will get "onSaveEdit" just after this call + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + } +}); + +// ************************************************************************************************ +// InlineEditor + +// basic inline editor attributes +var inlineEditorAttributes = { + "class": "textEditorInner", + + type: "text", + spellcheck: "false", + + onkeypress: "$onKeyPress", + + onoverflow: "$onOverflow", + oncontextmenu: "$onContextMenu" +}; + +// IE does not support the oninput event, so we're using the onkeydown to signalize +// the relevant keyboard events, and the onpropertychange to actually handle the +// input event, which should happen after the onkeydown event is fired and after the +// value of the input is updated, but before the onkeyup and before the input (with the +// new value) is rendered +if (isIE) +{ + inlineEditorAttributes.onpropertychange = "$onInput"; + inlineEditorAttributes.onkeydown = "$onKeyDown"; +} +// for other browsers we use the oninput event +else +{ + inlineEditorAttributes.oninput = "$onInput"; +} + +Firebug.InlineEditor = function(doc) +{ + this.initializeInline(doc); +}; + +Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor, +{ + enterOnBlur: true, + outerMargin: 8, + shadowExpand: 7, + + tag: + DIV({"class": "inlineEditor"}, + DIV({"class": "textEditorTop1"}, + DIV({"class": "textEditorTop2"}) + ), + DIV({"class": "textEditorInner1"}, + DIV({"class": "textEditorInner2"}, + INPUT( + inlineEditorAttributes + ) + ) + ), + DIV({"class": "textEditorBottom1"}, + DIV({"class": "textEditorBottom2"}) + ) + ), + + inputTag : + INPUT({"class": "textEditorInner", type: "text", + /*oninput: "$onInput",*/ onkeypress: "$onKeyPress", onoverflow: "$onOverflow"} + ), + + expanderTag: + IMG({"class": "inlineExpander", src: "blank.gif"}), + + initialize: function() + { + this.fixedWidth = false; + this.completeAsYouType = true; + this.tabNavigation = true; + this.multiLine = false; + this.tabCompletion = false; + this.arrowCompletion = true; + this.noWrap = true; + this.numeric = false; + }, + + destroy: function() + { + this.destroyInput(); + }, + + initializeInline: function(doc) + { + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Firebug.InlineEditor initializeInline()"); + + //this.box = this.tag.replace({}, doc, this); + this.box = this.tag.append({}, doc.body, this); + + //this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required + this.input = this.box.getElementsByTagName("input")[0]; + + if (isIElt8) + { + this.input.style.top = "-8px"; + } + + this.expander = this.expanderTag.replace({}, doc, this); + this.initialize(); + }, + + destroyInput: function() + { + // XXXjoe Need to remove input/keypress handlers to avoid leaks + }, + + getValue: function() + { + return this.input.value; + }, + + setValue: function(value) + { + // It's only a one-line editor, so new lines shouldn't be allowed + return this.input.value = stripNewLines(value); + }, + + show: function(target, panel, value, targetSize) + { + //dispatch([Firebug.A11yModel], "onInlineEditorShow", [panel, this]); + this.target = target; + this.panel = panel; + + this.targetSize = targetSize; + + // TODO: xxxpedro editor + //this.targetOffset = getClientOffset(target); + + // Some browsers (IE, Google Chrome and Safari) will have problem trying to get the + // offset values of invisible elements, or empty elements. So, in order to get the + // correct values, we temporary inject a character in the innerHTML of the empty element, + // then we get the offset values, and next, we restore the original innerHTML value. + var innerHTML = target.innerHTML; + var isEmptyElement = !innerHTML; + if (isEmptyElement) + target.innerHTML = "."; + + // Get the position of the target element (that is about to be edited) + this.targetOffset = + { + x: target.offsetLeft, + y: target.offsetTop + }; + + // Restore the original innerHTML value of the empty element + if (isEmptyElement) + target.innerHTML = innerHTML; + + this.originalClassName = this.box.className; + + var classNames = target.className.split(" "); + for (var i = 0; i < classNames.length; ++i) + setClass(this.box, "editor-" + classNames[i]); + + // Make the editor match the target's font style + copyTextStyles(target, this.box); + + this.setValue(value); + + if (this.fixedWidth) + this.updateLayout(true); + else + { + this.startMeasuring(target); + this.textSize = this.measureInputText(value); + + // Correct the height of the box to make the funky CSS drop-shadow line up + var parent = this.input.parentNode; + if (hasClass(parent, "textEditorInner2")) + { + var yDiff = this.textSize.height - this.shadowExpand; + + // IE6 height offset + if (isIE6) + yDiff -= 2; + + parent.style.height = yDiff + "px"; + parent.parentNode.style.height = yDiff + "px"; + } + + this.updateLayout(true); + } + + this.getAutoCompleter().reset(); + + if (isIElt8) + panel.panelNode.appendChild(this.box); + else + target.offsetParent.appendChild(this.box); + + //console.log(target); + //this.input.select(); // it's called bellow, with setTimeout + + if (isIE) + { + // reset input style + this.input.style.fontFamily = "Monospace"; + this.input.style.fontSize = "11px"; + } + + // Insert the "expander" to cover the target element with white space + if (!this.fixedWidth) + { + copyBoxStyles(target, this.expander); + + target.parentNode.replaceChild(this.expander, target); + collapse(target, true); + this.expander.parentNode.insertBefore(target, this.expander); + } + + //TODO: xxxpedro + //scrollIntoCenterView(this.box, null, true); + + // Display the editor after change its size and position to avoid flickering + this.box.style.display = "block"; + + // we need to call input.focus() and input.select() with a timeout, + // otherwise it won't work on all browsers due to timing issues + var self = this; + setTimeout(function(){ + self.input.focus(); + self.input.select(); + },0); + }, + + hide: function() + { + this.box.className = this.originalClassName; + + if (!this.fixedWidth) + { + this.stopMeasuring(); + + collapse(this.target, false); + + if (this.expander.parentNode) + this.expander.parentNode.removeChild(this.expander); + } + + if (this.box.parentNode) + { + ///setSelectionRange(this.input, 0, 0); + this.input.blur(); + + this.box.parentNode.removeChild(this.box); + } + + delete this.target; + delete this.panel; + }, + + layout: function(forceAll) + { + if (!this.fixedWidth) + this.textSize = this.measureInputText(this.input.value); + + if (forceAll) + this.targetOffset = getClientOffset(this.expander); + + this.updateLayout(false, forceAll); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + beginEditing: function(target, value) + { + }, + + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + }, + + advanceToNext: function(target, charCode) + { + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleter: function() + { + if (!this.autoCompleter) + { + this.autoCompleter = new Firebug.AutoCompleter(null, + bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this), + true, false); + } + + return this.autoCompleter; + }, + + completeValue: function(amt) + { + //console.log("completeValue"); + + var selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0); + + if (selectRangeCallback) + { + Firebug.Editor.update(true); + + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + else + this.incrementValue(amt); + }, + + incrementValue: function(amt) + { + var value = this.input.value; + + // TODO: xxxpedro editor + if (isIE) + var start = getInputSelectionStart(this.input), end = start; + else + var start = this.input.selectionStart, end = this.input.selectionEnd; + + //debugger; + var range = this.getAutoCompleteRange(value, start); + if (!range || range.type != "int") + range = {start: 0, end: value.length-1}; + + var expr = value.substr(range.start, range.end-range.start+1); + preExpr = value.substr(0, range.start); + postExpr = value.substr(range.end+1); + + // See if the value is an integer, and if so increment it + var intValue = parseInt(expr); + if (!!intValue || intValue == 0) + { + var m = /\d+/.exec(expr); + var digitPost = expr.substr(m.index+m[0].length); + + var completion = intValue-amt; + this.input.value = preExpr + completion + digitPost + postExpr; + + setSelectionRange(this.input, start, end); + + Firebug.Editor.update(true); + + return true; + } + else + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onKeyPress: function(event) + { + //console.log("onKeyPress", event); + if (event.keyCode == 27 && !this.completeAsYouType) + { + var reverted = this.getAutoCompleter().revert(this.input); + if (reverted) + cancelEvent(event); + } + else if (event.charCode && this.advanceToNext(this.target, event.charCode)) + { + Firebug.Editor.tabNextEditor(); + cancelEvent(event); + } + else + { + if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57) + && event.charCode != 45 && event.charCode != 46) + FBL.cancelEvent(event); + else + { + // If the user backspaces, don't autocomplete after the upcoming input event + this.ignoreNextInput = event.keyCode == 8; + } + } + }, + + onOverflow: function() + { + this.updateLayout(false, false, 3); + }, + + onKeyDown: function(event) + { + //console.log("onKeyDown", event.keyCode); + if (event.keyCode > 46 || event.keyCode == 32 || event.keyCode == 8) + { + this.keyDownPressed = true; + } + }, + + onInput: function(event) + { + //debugger; + + // skip not relevant onpropertychange calls on IE + if (isIE) + { + if (event.propertyName != "value" || !isVisible(this.input) || !this.keyDownPressed) + return; + + this.keyDownPressed = false; + } + + //console.log("onInput", event); + //console.trace(); + + var selectRangeCallback; + + if (this.ignoreNextInput) + { + this.ignoreNextInput = false; + this.getAutoCompleter().reset(); + } + else if (this.completeAsYouType) + selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, false); + else + this.getAutoCompleter().reset(); + + Firebug.Editor.update(); + + if (selectRangeCallback) + { + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + }, + + onContextMenu: function(event) + { + cancelEvent(event); + + var popup = $("fbInlineEditorPopup"); + FBL.eraseNode(popup); + + var target = event.target || event.srcElement; + var menu = this.getContextMenuItems(target); + if (menu) + { + for (var i = 0; i < menu.length; ++i) + FBL.createMenuItem(popup, menu[i]); + } + + if (!popup.firstChild) + return false; + + popup.openPopupAtScreen(event.screenX, event.screenY, true); + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateLayout: function(initial, forceAll, extraWidth) + { + if (this.fixedWidth) + { + this.box.style.left = (this.targetOffset.x) + "px"; + this.box.style.top = (this.targetOffset.y) + "px"; + + var w = this.target.offsetWidth; + var h = this.target.offsetHeight; + this.input.style.width = w + "px"; + this.input.style.height = (h-3) + "px"; + } + else + { + if (initial || forceAll) + { + this.box.style.left = this.targetOffset.x + "px"; + this.box.style.top = this.targetOffset.y + "px"; + } + + var approxTextWidth = this.textSize.width; + var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x) + - this.outerMargin; + + var wrapped = initial + ? this.noWrap && this.targetSize.height > this.textSize.height+3 + : this.noWrap && approxTextWidth > maxWidth; + + if (wrapped) + { + var style = isIE ? + this.target.currentStyle : + this.target.ownerDocument.defaultView.getComputedStyle(this.target, ""); + + targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight); + + // Make the width fit the remaining x-space from the offset to the far right + approxTextWidth = maxWidth - targetMargin; + + this.input.style.width = "100%"; + this.box.style.width = approxTextWidth + "px"; + } + else + { + // Make the input one character wider than the text value so that + // typing does not ever cause the textbox to scroll + var charWidth = this.measureInputText('m').width; + + // Sometimes we need to make the editor a little wider, specifically when + // an overflow happens, otherwise it will scroll off some text on the left + if (extraWidth) + charWidth *= extraWidth; + + var inputWidth = approxTextWidth + charWidth; + + if (initial) + { + if (isIE) + { + // TODO: xxxpedro + var xDiff = 13; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + else + this.box.style.width = "auto"; + } + else + { + // TODO: xxxpedro + var xDiff = isIE ? 13: this.box.scrollWidth - this.input.offsetWidth; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + + this.input.style.width = inputWidth + "px"; + } + + this.expander.style.width = approxTextWidth + "px"; + this.expander.style.height = Math.max(this.textSize.height-3,0) + "px"; + } + + if (forceAll) + scrollIntoCenterView(this.box, null, true); + } +}); + +// ************************************************************************************************ +// Autocompletion + +Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive) +{ + var candidates = null; + var originalValue = null; + var originalOffset = -1; + var lastExpr = null; + var lastOffset = -1; + var exprOffset = 0; + var lastIndex = 0; + var preParsed = null; + var preExpr = null; + var postExpr = null; + + this.revert = function(textBox) + { + if (originalOffset != -1) + { + textBox.value = originalValue; + + setSelectionRange(textBox, originalOffset, originalOffset); + + this.reset(); + return true; + } + else + { + this.reset(); + return false; + } + }; + + this.reset = function() + { + candidates = null; + originalValue = null; + originalOffset = -1; + lastExpr = null; + lastOffset = 0; + exprOffset = 0; + }; + + this.complete = function(context, textBox, cycle, reverse) + { + //console.log("complete", context, textBox, cycle, reverse); + // TODO: xxxpedro important port to firebug (variable leak) + //var value = lastValue = textBox.value; + var value = textBox.value; + + //var offset = textBox.selectionStart; + var offset = getInputSelectionStart(textBox); + + // The result of selectionStart() in Safari/Chrome is 1 unit less than the result + // in Firefox. Therefore, we need to manually adjust the value here. + if (isSafari && !cycle && offset >= 0) offset++; + + if (!selectMode && originalOffset != -1) + offset = originalOffset; + + if (!candidates || !cycle || offset != lastOffset) + { + originalOffset = offset; + originalValue = value; + + // Find the part of the string that will be parsed + var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0; + preParsed = value.substr(0, parseStart); + var parsed = value.substr(parseStart); + + // Find the part of the string that is being completed + var range = getRange ? getRange(parsed, offset-parseStart, context) : null; + if (!range) + range = {start: 0, end: parsed.length-1 }; + + var expr = parsed.substr(range.start, range.end-range.start+1); + preExpr = parsed.substr(0, range.start); + postExpr = parsed.substr(range.end+1); + exprOffset = parseStart + range.start; + + if (!cycle) + { + if (!expr) + return; + else if (lastExpr && lastExpr.indexOf(expr) != 0) + { + candidates = null; + } + else if (lastExpr && lastExpr.length >= expr.length) + { + candidates = null; + lastExpr = expr; + return; + } + } + + lastExpr = expr; + lastOffset = offset; + + var searchExpr; + + // Check if the cursor is at the very right edge of the expression, or + // somewhere in the middle of it + if (expr && offset != parseStart+range.end+1) + { + if (cycle) + { + // We are in the middle of the expression, but we can + // complete by cycling to the next item in the values + // list after the expression + offset = range.start; + searchExpr = expr; + expr = ""; + } + else + { + // We can't complete unless we are at the ridge edge + return; + } + } + + var values = evaluator(preExpr, expr, postExpr, context); + if (!values) + return; + + if (expr) + { + // Filter the list of values to those which begin with expr. We + // will then go on to complete the first value in the resulting list + candidates = []; + + if (caseSensitive) + { + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.indexOf(expr) == 0) + candidates.push(name); + } + } + else + { + var lowerExpr = caseSensitive ? expr : expr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0) + candidates.push(name); + } + } + + lastIndex = reverse ? candidates.length-1 : 0; + } + else if (searchExpr) + { + var searchIndex = -1; + + // Find the first instance of searchExpr in the values list. We + // will then complete the string that is found + if (caseSensitive) + { + searchIndex = values.indexOf(expr); + } + else + { + var lowerExpr = searchExpr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name && name.toLowerCase().indexOf(lowerExpr) == 0) + { + searchIndex = i; + break; + } + } + } + + // Nothing found, so there's nothing to complete to + if (searchIndex == -1) + return this.reset(); + + expr = searchExpr; + candidates = cloneArray(values); + lastIndex = searchIndex; + } + else + { + expr = ""; + candidates = []; + for (var i = 0; i < values.length; ++i) + { + if (values[i].substr) + candidates.push(values[i]); + } + lastIndex = -1; + } + } + + if (cycle) + { + expr = lastExpr; + lastIndex += reverse ? -1 : 1; + } + + if (!candidates.length) + return; + + if (lastIndex >= candidates.length) + lastIndex = 0; + else if (lastIndex < 0) + lastIndex = candidates.length-1; + + var completion = candidates[lastIndex]; + var preCompletion = expr.substr(0, offset-exprOffset); + var postCompletion = completion.substr(offset-exprOffset); + + textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr; + var offsetEnd = preParsed.length + preExpr.length + completion.length; + + // TODO: xxxpedro remove the following commented code, if the lib.setSelectionRange() + // is working well. + /* + if (textBox.setSelectionRange) + { + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + setTimeout(function(){ + if (selectMode) + textBox.setSelectionRange(offset, offsetEnd); + else + textBox.setSelectionRange(offsetEnd, offsetEnd); + },0); + } + /**/ + + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + /* + setTimeout(function(){ + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + },0); + + return true; + /**/ + + // The editor text should be selected only after calling the editor.update() + // in Safari/Chrome, otherwise the text won't be selected. So, we're returning + // a function to be called later (in the proper time for all browsers). + // + // TODO: xxxpedro see if we can move the editor.update() calls to here, and avoid + // returning a closure. the complete() function seems to be called only twice in + // editor.js. See if this function is called anywhere else (like css.js for example). + return function(){ + //console.log("autocomplete ", textBox, offset, offsetEnd); + + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + }; + /**/ + }; +}; + +// ************************************************************************************************ +// Local Helpers + +var getDefaultEditor = function getDefaultEditor(panel) +{ + if (!defaultEditor) + { + var doc = panel.document; + defaultEditor = new Firebug.InlineEditor(doc); + } + + return defaultEditor; +} + +/** + * An outsider is the first element matching the stepper element that + * is not an child of group. Elements tagged with insertBefore or insertAfter + * classes are also excluded from these results unless they are the sibling + * of group, relative to group's parent editGroup. This allows for the proper insertion + * rows when groups are nested. + */ +var getOutsider = function getOutsider(element, group, stepper) +{ + var parentGroup = getAncestorByClass(group.parentNode, "editGroup"); + var next; + do + { + next = stepper(next || element); + } + while (isAncestor(next, group) || isGroupInsert(next, parentGroup)); + + return next; +} + +var isGroupInsert = function isGroupInsert(next, group) +{ + return (!group || isAncestor(next, group)) + && (hasClass(next, "insertBefore") || hasClass(next, "insertAfter")); +} + +var getNextOutsider = function getNextOutsider(element, group) +{ + return getOutsider(element, group, bind(getNextByClass, FBL, "editable")); +} + +var getPreviousOutsider = function getPreviousOutsider(element, group) +{ + return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable")); +} + +var getInlineParent = function getInlineParent(element) +{ + var lastInline = element; + for (; element; element = element.parentNode) + { + //var s = element.ownerDocument.defaultView.getComputedStyle(element, ""); + var s = isIE ? + element.currentStyle : + element.ownerDocument.defaultView.getComputedStyle(element, ""); + + if (s.display != "inline") + return lastInline; + else + lastInline = element; + } + return null; +} + +var insertTab = function insertTab() +{ + insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.Editor); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Inspector Module + +var ElementCache = Firebug.Lite.Cache.Element; + +var inspectorTS, inspectorTimer, isInspecting; + +Firebug.Inspector = +{ + create: function() + { + offlineFragment = Env.browser.document.createDocumentFragment(); + + createBoxModelInspector(); + createOutlineInspector(); + }, + + destroy: function() + { + destroyBoxModelInspector(); + destroyOutlineInspector(); + + offlineFragment = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inspect functions + + toggleInspect: function() + { + if (isInspecting) + { + this.stopInspecting(); + } + else + { + Firebug.chrome.inspectButton.changeState("pressed"); + this.startInspecting(); + } + }, + + startInspecting: function() + { + isInspecting = true; + + Firebug.chrome.selectPanel("HTML"); + + createInspectorFrame(); + + var size = Firebug.browser.getWindowScrollSize(); + + fbInspectFrame.style.width = size.width + "px"; + fbInspectFrame.style.height = size.height + "px"; + + //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody); + + addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + }, + + stopInspecting: function() + { + isInspecting = false; + + if (outlineVisible) this.hideOutline(); + removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + + destroyInspectorFrame(); + + Firebug.chrome.inspectButton.restore(); + + if (Firebug.chrome.type == "popup") + Firebug.chrome.node.focus(); + }, + + onInspectingClick: function(e) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + //Firebug.Console.log(targ); + Firebug.Inspector.stopInspecting(); + }, + + onInspecting: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache(targ)) + { + var target = ""+ElementCache.key(targ); + var lazySelect = function() + { + inspectorTS = new Date().getTime(); + + Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)) + }; + + if (inspectorTimer) + { + clearTimeout(inspectorTimer); + inspectorTimer = null; + } + + if (new Date().getTime() - inspectorTS > 200) + setTimeout(lazySelect, 0) + else + inspectorTimer = setTimeout(lazySelect, 300); + } + + lastInspecting = new Date().getTime(); + } + }, + + // TODO: xxxpedro remove this? + onInspectingBody: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + var targ = e.target; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache.has(targ)) + FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)); + + lastInspecting = new Date().getTime(); + } + }, + + /** + * + * llttttttrr + * llttttttrr + * ll rr + * ll rr + * llbbbbbbrr + * llbbbbbbrr + */ + drawOutline: function(el) + { + var border = 2; + var scrollbarSize = 17; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + var box = Firebug.browser.getElementBox(el); + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width - + (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible + scrollbarSize : 0); + + var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height - + (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible + scrollbarSize : 0); + + var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1; + + var o = outlineElements; + var style; + + style = o.fbOutlineT.style; + style.top = top-border + "px"; + style.left = left + "px"; + style.height = border + "px"; // TODO: on initialize() + style.width = width + "px"; + + style = o.fbOutlineL.style; + style.top = top-border + "px"; + style.left = left-border + "px"; + style.height = height+ numVerticalBorders*border + "px"; + style.width = border + "px"; // TODO: on initialize() + + style = o.fbOutlineB.style; + if (freeVerticalSpace > 0) + { + style.top = top+height + "px"; + style.left = left + "px"; + style.width = width + "px"; + //style.height = border + "px"; // TODO: on initialize() or worst case? + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.width = border + "px"; + //style.height = border + "px"; + } + + style = o.fbOutlineR.style; + if (freeHorizontalSpace > 0) + { + style.top = top-border + "px"; + style.left = left+width + "px"; + style.height = height + numVerticalBorders*border + "px"; + style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px"; + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.height = border + "px"; + style.width = border + "px"; + } + + if (!outlineVisible) this.showOutline(); + }, + + hideOutline: function() + { + if (!outlineVisible) return; + + for (var name in outline) + offlineFragment.appendChild(outlineElements[name]); + + outlineVisible = false; + }, + + showOutline: function() + { + if (outlineVisible) return; + + if (boxModelVisible) this.hideBoxModel(); + + for (var name in outline) + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]); + + outlineVisible = true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Box Model + + drawBoxModel: function(el) + { + // avoid error when the element is not attached a document + if (!el || !el.parentNode) + return; + + var box = Firebug.browser.getElementBox(el); + + var windowSize = Firebug.browser.getWindowSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + // element may be occluded by the chrome, when in frame mode + var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0; + + // if element box is not inside the viewport, don't draw the box model + if (box.top > scrollPosition.top + windowSize.height - offsetHeight || + box.left > scrollPosition.left + windowSize.width || + scrollPosition.top > box.top + box.height || + scrollPosition.left > box.left + box.width ) + return; + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var margin = Firebug.browser.getMeasurementBox(el, "margin"); + var padding = Firebug.browser.getMeasurementBox(el, "padding"); + var border = Firebug.browser.getMeasurementBox(el, "border"); + + boxModelStyle.top = top - margin.top + "px"; + boxModelStyle.left = left - margin.left + "px"; + boxModelStyle.height = height + margin.top + margin.bottom + "px"; + boxModelStyle.width = width + margin.left + margin.right + "px"; + + boxBorderStyle.top = margin.top + "px"; + boxBorderStyle.left = margin.left + "px"; + boxBorderStyle.height = height + "px"; + boxBorderStyle.width = width + "px"; + + boxPaddingStyle.top = margin.top + border.top + "px"; + boxPaddingStyle.left = margin.left + border.left + "px"; + boxPaddingStyle.height = height - border.top - border.bottom + "px"; + boxPaddingStyle.width = width - border.left - border.right + "px"; + + boxContentStyle.top = margin.top + border.top + padding.top + "px"; + boxContentStyle.left = margin.left + border.left + padding.left + "px"; + boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px"; + boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px"; + + if (!boxModelVisible) this.showBoxModel(); + }, + + hideBoxModel: function() + { + if (!boxModelVisible) return; + + offlineFragment.appendChild(boxModel); + boxModelVisible = false; + }, + + showBoxModel: function() + { + if (boxModelVisible) return; + + if (outlineVisible) this.hideOutline(); + + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel); + boxModelVisible = true; + } + +}; + +// ************************************************************************************************ +// Inspector Internals + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Shared variables + + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internal variables + +var offlineFragment = null; + +var boxModelVisible = false; + +var boxModel, boxModelStyle, + boxMargin, boxMarginStyle, + boxBorder, boxBorderStyle, + boxPadding, boxPaddingStyle, + boxContent, boxContentStyle; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; +var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;"; + +var inspectStyle = resetStyle + "z-index: 2147483500;"; +var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" + + Env.Location.skinDir + "pixel_transparent.gif);"; + +//if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);"; + +var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;"; +var inspectModelStyle = inspectStyle + inspectModelOpacity; +var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;"; +var inspectBorderStyle = inspectStyle + "background: #666;"; +var inspectPaddingStyle = inspectStyle + "background: SlateBlue;"; +var inspectContentStyle = inspectStyle + "background: SkyBlue;"; + + +var outlineStyle = { + fbHorizontalLine: "background: #3875D7;height: 2px;", + fbVerticalLine: "background: #3875D7;width: 2px;" +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var lastInspecting = 0; +var fbInspectFrame = null; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var outlineVisible = false; +var outlineElements = {}; +var outline = { + "fbOutlineT": "fbHorizontalLine", + "fbOutlineL": "fbVerticalLine", + "fbOutlineB": "fbHorizontalLine", + "fbOutlineR": "fbVerticalLine" +}; + + +var getInspectingTarget = function() +{ + +}; + +// ************************************************************************************************ +// Section + +var createInspectorFrame = function createInspectorFrame() +{ + fbInspectFrame = createGlobalElement("div"); + fbInspectFrame.id = "fbInspectFrame"; + fbInspectFrame.firebugIgnore = true; + fbInspectFrame.style.cssText = inspectFrameStyle; + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame); +}; + +var destroyInspectorFrame = function destroyInspectorFrame() +{ + if (fbInspectFrame) + { + Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame); + fbInspectFrame = null; + } +}; + +var createOutlineInspector = function createOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name] = createGlobalElement("div"); + el.id = name; + el.firebugIgnore = true; + el.style.cssText = inspectStyle + outlineStyle[outline[name]]; + offlineFragment.appendChild(el); + } +}; + +var destroyOutlineInspector = function destroyOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name]; + el.parentNode.removeChild(el); + } +}; + +var createBoxModelInspector = function createBoxModelInspector() +{ + boxModel = createGlobalElement("div"); + boxModel.id = "fbBoxModel"; + boxModel.firebugIgnore = true; + boxModelStyle = boxModel.style; + boxModelStyle.cssText = inspectModelStyle; + + boxMargin = createGlobalElement("div"); + boxMargin.id = "fbBoxMargin"; + boxMarginStyle = boxMargin.style; + boxMarginStyle.cssText = inspectMarginStyle; + boxModel.appendChild(boxMargin); + + boxBorder = createGlobalElement("div"); + boxBorder.id = "fbBoxBorder"; + boxBorderStyle = boxBorder.style; + boxBorderStyle.cssText = inspectBorderStyle; + boxModel.appendChild(boxBorder); + + boxPadding = createGlobalElement("div"); + boxPadding.id = "fbBoxPadding"; + boxPaddingStyle = boxPadding.style; + boxPaddingStyle.cssText = inspectPaddingStyle; + boxModel.appendChild(boxPadding); + + boxContent = createGlobalElement("div"); + boxContent.id = "fbBoxContent"; + boxContentStyle = boxContent.style; + boxContentStyle.cssText = inspectContentStyle; + boxModel.appendChild(boxContent); + + offlineFragment.appendChild(boxModel); +}; + +var destroyBoxModelInspector = function destroyBoxModelInspector() +{ + boxModel.parentNode.removeChild(boxModel); +}; + +// ************************************************************************************************ +// Section + + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +// next-generation Console Panel (will override consoje.js) +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Constants + +/* +const Cc = Components.classes; +const Ci = Components.interfaces; +const nsIPrefBranch2 = Ci.nsIPrefBranch2; +const PrefService = Cc["@mozilla.org/preferences-service;1"]; +const prefs = PrefService.getService(nsIPrefBranch2); +/**/ +/* + +// new offline message handler +o = {x:1,y:2}; + +r = Firebug.getRep(o); + +r.tag.tag.compile(); + +outputs = []; +html = r.tag.renderHTML({object:o}, outputs); + + +// finish rendering the template (the DOM part) +target = $("build"); +target.innerHTML = html; +root = target.firstChild; + +domArgs = [root, r.tag.context, 0]; +domArgs.push.apply(domArgs, r.tag.domArgs); +domArgs.push.apply(domArgs, outputs); +r.tag.tag.renderDOM.apply(self ? self : r.tag.subject, domArgs); + + + */ +var consoleQueue = []; +var lastHighlightedObject; +var FirebugContext = Env.browser; + +// ************************************************************************************************ + +var maxQueueRequests = 500; + +// ************************************************************************************************ + +Firebug.ConsoleBase = +{ + log: function(object, context, className, rep, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"log",[context, object, className, sourceLink]); + return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle); + }, + + logFormatted: function(objects, context, className, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]); + return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle); + }, + + openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush) + { + return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle); + }, + + closeGroup: function(context, noThrottle) + { + return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true); + }, + + logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow) + { + // TODO: xxxpedro console console2 + noThrottle = true; // xxxpedro forced because there is no TabContext yet + + if (!context) + context = FirebugContext; + + if (FBTrace.DBG_ERRORS && !context) + FBTrace.sysout("Console.logRow has no context, skipping objects", objects); + + if (!context) + return; + + if (noThrottle || !context) + { + var panel = this.getPanel(context); + if (panel) + { + var row = panel.append(appender, objects, className, rep, sourceLink, noRow); + var container = panel.panelNode; + + // TODO: xxxpedro what is this? console console2 + /* + var template = Firebug.NetMonitor.NetLimit; + + while (container.childNodes.length > maxQueueRequests + 1) + { + clearDomplate(container.firstChild.nextSibling); + container.removeChild(container.firstChild.nextSibling); + panel.limit.limitInfo.totalCount++; + template.updateCounter(panel.limit); + } + dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]); + /**/ + return row; + } + else + { + consoleQueue.push([appender, objects, context, className, rep, sourceLink, noThrottle, noRow]); + } + } + else + { + if (!context.throttle) + { + //FBTrace.sysout("console.logRow has not context.throttle! "); + return; + } + var args = [appender, objects, context, className, rep, sourceLink, true, noRow]; + context.throttle(this.logRow, this, args); + } + }, + + appendFormatted: function(args, row, context) + { + if (!context) + context = FirebugContext; + + var panel = this.getPanel(context); + panel.appendFormatted(args, row); + }, + + clear: function(context) + { + if (!context) + //context = FirebugContext; + context = Firebug.context; + + /* + if (context) + Firebug.Errors.clear(context); + /**/ + + var panel = this.getPanel(context, true); + if (panel) + { + panel.clear(); + } + }, + + // Override to direct output to your panel + getPanel: function(context, noCreate) + { + //return context.getPanel("console", noCreate); + // TODO: xxxpedro console console2 + return Firebug.chrome ? Firebug.chrome.getPanel("Console") : null; + } + +}; + +// ************************************************************************************************ + +//TODO: xxxpedro +//var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase); +var ActivableConsole = extend(Firebug.ConsoleBase, +{ + isAlwaysEnabled: function() + { + return true; + } +}); + +Firebug.Console = Firebug.Console = extend(ActivableConsole, +//Firebug.Console = extend(ActivableConsole, +{ + dispatchName: "console", + + error: function() + { + Firebug.Console.logFormatted(arguments, Firebug.browser, "error"); + }, + + flush: function() + { + dispatch(this.fbListeners,"flush",[]); + + for (var i=0, length=consoleQueue.length; i objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + if (typeof(object) != "undefined") + this.appendObject(object, row, part.rep); + else + this.appendObject(part.type, row, FirebugReps.Text); + } + else + FirebugReps.Text.tag.append({object: part}, row); + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + logText(" ", row); + var object = objects[i]; + if (typeof(object) == "string") + FirebugReps.Text.tag.append({object: object}, row); + else + this.appendObject(object, row); + } + }, + + appendOpenGroup: function(objects, row, rep) + { + if (!this.groups) + this.groups = []; + + setClass(row, "logGroup"); + setClass(row, "opened"); + + var innerRow = this.createRow("logRow"); + setClass(innerRow, "logGroupLabel"); + if (rep) + rep.tag.replace({"objects": objects}, innerRow); + else + this.appendFormatted(objects, innerRow, rep); + row.appendChild(innerRow); + //dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]); + var groupBody = this.createRow("logGroupBody"); + row.appendChild(groupBody); + groupBody.setAttribute('role', 'group'); + this.groups.push(groupBody); + + addEvent(innerRow, "mousedown", function(event) + { + if (isLeftClick(event)) + { + //console.log(event.currentTarget == event.target); + + var target = event.target || event.srcElement; + + target = getAncestorByClass(target, "logGroupLabel"); + + var groupRow = target.parentNode; + + if (hasClass(groupRow, "opened")) + { + removeClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'false'); + } + else + { + setClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'true'); + } + } + }); + }, + + appendCloseGroup: function(object, row, rep) + { + if (this.groups) + this.groups.pop(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // TODO: xxxpedro console2 + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + onMouseDown: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + var repObject = object ? object.repObject : null; + + if (!repObject) + { + return; + } + + if (hasClass(object, "objectLink-object")) + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(repObject, true); + } + else if (hasClass(object, "objectLink-element")) + { + Firebug.chrome.selectPanel("HTML"); + Firebug.chrome.getPanel("HTML").select(repObject, true); + } + + /* + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + /**/ + + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "Console", + title: "Console", + //searchable: true, + //breakable: true, + //editable: false, + + options: + { + hasCommandLine: true, + hasToolButtons: true, + isPreRendered: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.context = Firebug.browser.window; + this.document = Firebug.chrome.document; + this.onMouseMove = bind(this.onMouseMove, this); + this.onMouseDown = bind(this.onMouseDown, this); + + this.clearButton = new Button({ + element: $("fbConsole_btClear"), + owner: Firebug.Console, + onClick: Firebug.Console.clear + }); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); // loads persisted content + //Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content + + if (!this.persistedContent && Firebug.Console.isAlwaysEnabled()) + { + this.insertLogLimit(this.context); + + // Initialize log limit and listen for changes. + this.updateMaxLimit(); + + if (this.context.consoleReloadWarning) // we have not yet injected the console + this.insertReloadWarning(); + } + + //Firebug.Console.injector.install(Firebug.browser.window); + + addEvent(this.panelNode, "mouseover", this.onMouseMove); + addEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.clearButton.initialize(); + + //consolex.trace(); + //TODO: xxxpedro remove this + /* + Firebug.Console.openGroup(["asd"], null, "group", null, false); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + /**/ + + //TODO: xxxpedro preferences prefs + //prefs.addObserver(Firebug.prefDomain, this, false); + }, + + initializeNode : function() + { + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this]); + if (FBTrace.DBG_CONSOLE) + { + this.onScroller = bind(this.onScroll, this); + addEvent(this.panelNode, "scroll", this.onScroller); + } + + this.onResizer = bind(this.onResize, this); + this.resizeEventTarget = Firebug.chrome.$('fbContentBox'); + addEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + destroyNode : function() + { + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this]); + if (this.onScroller) + removeEvent(this.panelNode, "scroll", this.onScroller); + + //removeEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + shutdown: function() + { + //TODO: xxxpedro console console2 + this.clearButton.shutdown(); + + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + + //TODO: xxxpedro preferences prefs + //prefs.removeObserver(Firebug.prefDomain, this, false); + }, + + ishow: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel show; " + this.context.getName(), state); + + var enabled = Firebug.Console.isAlwaysEnabled(); + if (enabled) + { + Firebug.Console.disabledPanelPage.hide(this); + this.showCommandLine(true); + this.showToolbarButtons("fbConsoleButtons", true); + Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent); + + if (state && state.wasScrolledToBottom) + { + this.wasScrolledToBottom = state.wasScrolledToBottom; + delete state.wasScrolledToBottom; + } + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + } + else + { + this.hide(state); + Firebug.Console.disabledPanelPage.show(this); + } + }, + + ihide: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel hide; " + this.context.getName(), state); + + this.showToolbarButtons("fbConsoleButtons", false); + this.showCommandLine(false); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + destroy: function(state) + { + if (this.panelNode.offsetHeight) + this.wasScrolledToBottom = isScrolledToBottom(this.panelNode); + + if (state) + state.wasScrolledToBottom = this.wasScrolledToBottom; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + shouldBreakOnNext: function() + { + // xxxHonza: shouldn't the breakOnErrors be context related? + // xxxJJB, yes, but we can't support it because we can't yet tell + // which window the error is on. + return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors"); + }, + + getBreakOnNextTooltip: function(enabled) + { + return (enabled ? $STR("console.Disable Break On All Errors") : + $STR("console.Break On All Errors")); + }, + + enablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.enablePanel.apply(this, arguments); + + this.showCommandLine(true); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + }, + + disablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.disablePanel.apply(this, arguments); + + this.showCommandLine(false); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowJavaScriptErrors", "showJSErrors"), + optionMenu("ShowJavaScriptWarnings", "showJSWarnings"), + optionMenu("ShowCSSErrors", "showCSSErrors"), + optionMenu("ShowXMLErrors", "showXMLErrors"), + optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"), + optionMenu("ShowChromeErrors", "showChromeErrors"), + optionMenu("ShowChromeMessages", "showChromeMessages"), + optionMenu("ShowExternalErrors", "showExternalErrors"), + optionMenu("ShowNetworkErrors", "showNetworkErrors"), + this.getShowStackTraceMenuItem(), + this.getStrictOptionMenuItem(), + "-", + optionMenu("LargeCommandLine", "largeCommandLine") + ]; + }, + + getShowStackTraceMenuItem: function() + { + var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace"); + if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled()) + menuItem.disabled = true; + return menuItem; + }, + + getStrictOptionMenuItem: function() + { + var strictDomain = "javascript.options"; + var strictName = "strict"; + var strictValue = prefs.getBoolPref(strictDomain+"."+strictName); + return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue, + command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) }; + }, + + getBreakOnMenuItems: function() + { + //xxxHonza: no BON options for now. + /*return [ + optionMenu("console.option.Persist Break On Error", "persistBreakOnError") + ];*/ + return []; + }, + + search: function(text) + { + if (!text) + return; + + // Make previously visible nodes invisible again + if (this.matchSet) + { + for (var i in this.matchSet) + removeClass(this.matchSet[i], "matched"); + } + + this.matchSet = []; + + function findRow(node) { return getAncestorByClass(node, "logRow"); } + var search = new TextSearch(this.panelNode, findRow); + + var logRow = search.find(text); + if (!logRow) + { + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]); + return false; + } + for (; logRow; logRow = search.findNext()) + { + setClass(logRow, "matched"); + this.matchSet.push(logRow); + } + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]); + return true; + }, + + breakOnNext: function(breaking) + { + Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // private + + createRow: function(rowName, className) + { + var elt = this.document.createElement("div"); + elt.className = rowName + (className ? " " + rowName + "-" + className : ""); + return elt; + }, + + getTopContainer: function() + { + if (this.groups && this.groups.length) + return this.groups[this.groups.length-1]; + else + return this.panelNode; + }, + + filterLogRow: function(logRow, scrolledToBottom) + { + if (this.searchText) + { + setClass(logRow, "matching"); + setClass(logRow, "matched"); + + // Search after a delay because we must wait for a frame to be created for + // the new logRow so that the finder will be able to locate it + setTimeout(bindFixed(function() + { + if (this.searchFilter(this.searchText, logRow)) + this.matchSet.push(logRow); + else + removeClass(logRow, "matched"); + + removeClass(logRow, "matching"); + + if (scrolledToBottom) + scrollToBottom(this.panelNode); + }, this), 100); + } + }, + + searchFilter: function(text, logRow) + { + var count = this.panelNode.childNodes.length; + var searchRange = this.document.createRange(); + searchRange.setStart(this.panelNode, 0); + searchRange.setEnd(this.panelNode, count); + + var startPt = this.document.createRange(); + startPt.setStartBefore(logRow); + + var endPt = this.document.createRange(); + endPt.setStartAfter(logRow); + + return finder.Find(text, searchRange, startPt, endPt) != null; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + // xxxHonza check this out. + var prefDomain = "Firebug.extension."; + var prefName = data.substr(prefDomain.length); + if (prefName == "console.logLimit") + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = 1000; + //TODO: xxxpedro preferences log limit? + //var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + }, + + showCommandLine: function(shouldShow) + { + //TODO: xxxpedro show command line important + return; + + if (shouldShow) + { + collapse(Firebug.chrome.$("fbCommandBox"), false); + Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome); + } + else + { + // Make sure that entire content of the Console panel is hidden when + // the panel is disabled. + Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine); + collapse(Firebug.chrome.$("fbCommandBox"), true); + } + }, + + onScroll: function(event) + { + // Update the scroll position flag if the position changes. + this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", wasScrolledToBottom: " + + this.context.getName(), event); + }, + + onResize: function(event) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight + + ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " + + this.panelNode.scrollHeight + ", " + this.context.getName(), event); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + } +}); + +// ************************************************************************************************ + +function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +} + +// ************************************************************************************************ + +var appendObject = Firebug.ConsolePanel.prototype.appendObject; +var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted; +var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup; +var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup; + +// ************************************************************************************************ + +//Firebug.registerActivableModule(Firebug.Console); +Firebug.registerModule(Firebug.Console); +Firebug.registerPanel(Firebug.ConsolePanel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +var frameCounters = {}; +var traceRecursion = 0; + +Firebug.Console.injector = +{ + install: function(context) + { + var win = context.window; + + var consoleHandler = new FirebugConsoleHandler(context, win); + + var properties = + [ + "log", + "debug", + "info", + "warn", + "error", + "assert", + "dir", + "dirxml", + "group", + "groupCollapsed", + "groupEnd", + "time", + "timeEnd", + "count", + "trace", + "profile", + "profileEnd", + "clear", + "open", + "close" + ]; + + var Handler = function(name) + { + var c = consoleHandler; + var f = consoleHandler[name]; + return function(){return f.apply(c,arguments)}; + }; + + var installer = function(c) + { + for (var i=0, l=properties.length; i 1) + { + traceRecursion--; + return; + } + + var frames = []; + + for (var fn = arguments.callee.caller.caller; fn; fn = fn.caller) + { + if (wasVisited(fn)) break; + + var args = []; + + for (var i = 0, l = fn.arguments.length; i < l; ++i) + { + args.push({value: fn.arguments[i]}); + } + + frames.push({fn: fn, name: getFuncName(fn), args: args}); + } + + + // **************************************************************************************** + + try + { + (0)(); + } + catch(e) + { + var result = e; + + var stack = + result.stack || // Firefox / Google Chrome + result.stacktrace || // Opera + ""; + + stack = stack.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks + var items = stack.split(/[\n\r]/); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Google Chrome + if (FBL.isSafari) + { + //var reChromeStackItem = /^\s+at\s+([^\(]+)\s\((.*)\)$/; + //var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + + var reChromeStackItemName = /\s*\($/; + var reChromeStackItemValue = /^(.+)\:(\d+\:\d+)\)?$/; + + var framePos = 0; + for (var i=4, length=items.length; i 1) + { + objects = [errorObject]; + for (var i = 1; i < args.length; i++) + objects.push(args[i]); + } + + var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle + row.scrollIntoView(); + } + + function getComponentsStackDump() + { + // Starting with our stack, walk back to the user-level code + var frame = Components.stack; + var userURL = win.location.href.toString(); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame); + + // Drop frames until we get into user code. + while (frame && FBL.isSystemURL(frame.filename) ) + frame = frame.caller; + + // Drop two more frames, the injected console function and firebugAppendConsole() + if (frame) + frame = frame.caller; + if (frame) + frame = frame.caller; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame); + + return frame; + } + + function getStackLink() + { + // TODO: xxxpedro console2 + return; + //return FBL.getFrameSourceLink(getComponentsStackDump()); + } + + function getJSDUserStack() + { + var trace = FBL.getCurrentStackTrace(context); + + var frames = trace ? trace.frames : null; + if (frames && (frames.length > 0) ) + { + var oldest = frames.length - 1; // 6 - 1 = 5 + for (var i = 0; i < frames.length; i++) + { + if (frames[oldest - i].href.indexOf("chrome:") == 0) break; + var fn = frames[oldest - i].fn + ""; + if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line + } + FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace); + trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code + + return trace; + } + else + return "Firebug failed to get stack trace with any frames"; + } +} + +// ************************************************************************************************ +// Register console namespace + +FBL.registerConsole = function() +{ + //TODO: xxxpedro console options override + //if (Env.Options.overrideConsole) + var win = Env.browser.window; + Firebug.Console.injector.install(win); +}; + +registerConsole(); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +// ************************************************************************************************ +// Globals + +var commandPrefix = ">>>"; +var reOpenBracket = /[\[\(\{]/; +var reCloseBracket = /[\]\)\}]/; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var commandHistory = []; +var commandPointer = -1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var isAutoCompleting = null; +var autoCompletePrefix = null; +var autoCompleteExpr = null; +var autoCompleteBuffer = null; +var autoCompletePosition = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var fbCommandLine = null; +var fbLargeCommandLine = null; +var fbLargeCommandButtons = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _completion = +{ + window: + [ + "console" + ], + + document: + [ + "getElementById", + "getElementsByTagName" + ] +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _stack = function(command) +{ + commandHistory.push(command); + commandPointer = commandHistory.length; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +// ************************************************************************************************ +// CommandLine + +Firebug.CommandLine = extend(Firebug.Module, +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + element: null, + isMultiLine: false, + isActive: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + initialize: function(doc) + { + this.clear = bind(this.clear, this); + this.enter = bind(this.enter, this); + + this.onError = bind(this.onError, this); + this.onKeyDown = bind(this.onKeyDown, this); + this.onMultiLineKeyDown = bind(this.onMultiLineKeyDown, this); + + addEvent(Firebug.browser.window, "error", this.onError); + addEvent(Firebug.chrome.window, "error", this.onError); + }, + + shutdown: function(doc) + { + this.deactivate(); + + removeEvent(Firebug.browser.window, "error", this.onError); + removeEvent(Firebug.chrome.window, "error", this.onError); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + activate: function(multiLine, hideToggleIcon, onRun) + { + defineCommandLineAPI(); + + if (this.isActive) + { + if (this.isMultiLine == multiLine) return; + + this.deactivate(); + } + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + if (multiLine) + { + onRun = onRun || this.enter; + + this.isMultiLine = true; + + this.element = fbLargeCommandLine; + + addEvent(this.element, "keydown", this.onMultiLineKeyDown); + + addEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton = new Button({ + element: $("fbCommand_btRun"), + owner: Firebug.CommandLine, + onClick: onRun + }); + + this.runButton.initialize(); + + this.clearButton = new Button({ + element: $("fbCommand_btClear"), + owner: Firebug.CommandLine, + onClick: this.clear + }); + + this.clearButton.initialize(); + } + else + { + this.isMultiLine = false; + this.element = fbCommandLine; + + if (!fbCommandLine) + return; + + addEvent(this.element, "keydown", this.onKeyDown); + } + + //Firebug.Console.log("activate", this.element); + + if (isOpera) + fixOperaTabKey(this.element); + + if(this.lastValue) + this.element.value = this.lastValue; + + this.isActive = true; + }, + + deactivate: function() + { + if (!this.isActive) return; + + //Firebug.Console.log("deactivate", this.element); + + this.isActive = false; + + this.lastValue = this.element.value; + + if (this.isMultiLine) + { + removeEvent(this.element, "keydown", this.onMultiLineKeyDown); + + removeEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton.destroy(); + this.clearButton.destroy(); + } + else + { + removeEvent(this.element, "keydown", this.onKeyDown); + } + + this.element = null + delete this.element; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focus: function() + { + this.element.focus(); + }, + + blur: function() + { + this.element.blur(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + clear: function() + { + this.element.value = ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + evaluate: function(expr) + { + // TODO: need to register the API in console.firebug.commandLineAPI + var api = "Firebug.CommandLine.API" + + var result = Firebug.context.evaluate(expr, "window", api, Firebug.Console.error); + + return result; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + enter: function() + { + var command = this.element.value; + + if (!command) return; + + _stack(command); + + Firebug.Console.log(commandPrefix + " " + stripNewLines(command), Firebug.browser, "command", FirebugReps.Text); + + var result = this.evaluate(command); + + Firebug.Console.log(result); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + prevCommand: function() + { + if (commandPointer > 0 && commandHistory.length > 0) + this.element.value = commandHistory[--commandPointer]; + }, + + nextCommand: function() + { + var element = this.element; + + var limit = commandHistory.length -1; + var i = commandPointer; + + if (i < limit) + element.value = commandHistory[++commandPointer]; + + else if (i == limit) + { + ++commandPointer; + element.value = ""; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + autocomplete: function(reverse) + { + var element = this.element; + + var command = element.value; + var offset = getExpressionOffset(command); + + var valBegin = offset ? command.substr(0, offset) : ""; + var val = command.substr(offset); + + var buffer, obj, objName, commandBegin, result, prefix; + + // if it is the beginning of the completion + if(!isAutoCompleting) + { + + // group1 - command begin + // group2 - base object + // group3 - property prefix + var reObj = /(.*[^_$\w\d\.])?((?:[_$\w][_$\w\d]*\.)*)([_$\w][_$\w\d]*)?$/; + var r = reObj.exec(val); + + // parse command + if (r[1] || r[2] || r[3]) + { + commandBegin = r[1] || ""; + objName = r[2] || ""; + prefix = r[3] || ""; + } + else if (val == "") + { + commandBegin = objName = prefix = ""; + } else + return; + + isAutoCompleting = true; + + // find base object + if(objName == "") + obj = window; + + else + { + objName = objName.replace(/\.$/, ""); + + var n = objName.split("."); + var target = window, o; + + for (var i=0, ni; ni = n[i]; i++) + { + if (o = target[ni]) + target = o; + + else + { + target = null; + break; + } + } + obj = target; + } + + // map base object + if(obj) + { + autoCompletePrefix = prefix; + autoCompleteExpr = valBegin + commandBegin + (objName ? objName + "." : ""); + autoCompletePosition = -1; + + buffer = autoCompleteBuffer = isIE ? + _completion[objName || "window"] || [] : []; + + for(var p in obj) + buffer.push(p); + } + + // if it is the continuation of the last completion + } else + buffer = autoCompleteBuffer; + + if (buffer) + { + prefix = autoCompletePrefix; + + var diff = reverse ? -1 : 1; + + for(var i=autoCompletePosition+diff, l=buffer.length, bi; i>=0 && i', msg, '', + '' + ]; + + // TODO: xxxpedro ajust to Console2 + //Firebug.Console.writeRow(html, "error"); + }, + + onKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + /*tab, shift, control, alt*/ + if (code != 9 && code != 16 && code != 17 && code != 18) + { + isAutoCompleting = false; + } + + if (code == 13 /* enter */) + { + this.enter(); + this.clear(); + } + else if (code == 27 /* ESC */) + { + setTimeout(this.clear, 0); + } + else if (code == 38 /* up */) + { + this.prevCommand(); + } + else if (code == 40 /* down */) + { + this.nextCommand(); + } + else if (code == 9 /* tab */) + { + this.autocomplete(e.shiftKey); + } + else + return; + + cancelEvent(e, true); + return false; + }, + + onMultiLineKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + if (code == 13 /* enter */ && e.ctrlKey) + { + this.enter(); + } + } +}); + +Firebug.registerModule(Firebug.CommandLine); + + +// ************************************************************************************************ +// + +function getExpressionOffset(command) +{ + // XXXjoe This is kind of a poor-man's JavaScript parser - trying + // to find the start of the expression that the cursor is inside. + // Not 100% fool proof, but hey... + + var bracketCount = 0; + + var start = command.length-1; + for (; start >= 0; --start) + { + var c = command[start]; + if ((c == "," || c == ";" || c == " ") && !bracketCount) + break; + if (reOpenBracket.test(c)) + { + if (bracketCount) + --bracketCount; + else + break; + } + else if (reCloseBracket.test(c)) + ++bracketCount; + } + + return start + 1; +} + +// ************************************************************************************************ +// CommandLine API + +var CommandLineAPI = +{ + $: function(id) + { + return Firebug.browser.document.getElementById(id) + }, + + $$: function(selector, context) + { + context = context || Firebug.browser.document; + return Firebug.Selector ? + Firebug.Selector(selector, context) : + Firebug.Console.error("Firebug.Selector module not loaded."); + }, + + $0: null, + + $1: null, + + dir: function(o) + { + Firebug.Console.log(o, Firebug.context, "dir", Firebug.DOMPanel.DirTable); + }, + + dirxml: function(o) + { + ///if (o instanceof Window) + if (instanceOf(o, "Window")) + o = o.document.documentElement; + ///else if (o instanceof Document) + else if (instanceOf(o, "Document")) + o = o.documentElement; + + // TODO: xxxpedro html3 + ///Firebug.Console.log(o, Firebug.context, "dirxml", Firebug.HTMLPanel.SoloElement); + var div = Firebug.Console.log(o, Firebug.context, "dirxml"); + var html = []; + Firebug.Reps.appendNode(o, html); + div.innerHTML = html.join(""); + + } +}; + +// ************************************************************************************************ + +var defineCommandLineAPI = function defineCommandLineAPI() +{ + Firebug.CommandLine.API = {}; + for (var m in CommandLineAPI) + if (!Env.browser.window[m]) + Firebug.CommandLine.API[m] = CommandLineAPI[m]; + + var stack = FirebugChrome.htmlSelectionStack; + if (stack) + { + Firebug.CommandLine.API.$0 = stack[0]; + Firebug.CommandLine.API.$1 = stack[1]; + } +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +if (Env.Options.disableXHRListener) + return; + +// ************************************************************************************************ +// XHRSpy + +var XHRSpy = function() +{ + this.requestHeaders = []; + this.responseHeaders = []; +}; + +XHRSpy.prototype = +{ + method: null, + url: null, + async: null, + + xhrRequest: null, + + href: null, + + loaded: false, + + logRow: null, + + responseText: null, + + requestHeaders: null, + responseHeaders: null, + + sourceLink: null, // {href:"file.html", line: 22} + + getURL: function() + { + return this.href; + } +}; + +// ************************************************************************************************ +// XMLHttpRequestWrapper + +var XMLHttpRequestWrapper = function(activeXObject) +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal variables + + var xhrRequest = typeof activeXObject != "undefined" ? + activeXObject : + new _XMLHttpRequest(), + + spy = new XHRSpy(), + + self = this, + + reqType, + reqUrl, + reqStartTS; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal methods + + var updateSelfPropertiesIgnore = { + abort: 1, + channel: 1, + getAllResponseHeaders: 1, + getInterface: 1, + getResponseHeader: 1, + mozBackgroundRequest: 1, + multipart: 1, + onreadystatechange: 1, + open: 1, + send: 1, + setRequestHeader: 1 + }; + + var updateSelfProperties = function() + { + if (supportsXHRIterator) + { + for (var propName in xhrRequest) + { + if (propName in updateSelfPropertiesIgnore) + continue; + + try + { + var propValue = xhrRequest[propName]; + + if (propValue && !isFunction(propValue)) + self[propName] = propValue; + } + catch(E) + { + //console.log(propName, E.message); + } + } + } + else + { + // will fail to read these xhrRequest properties if the request is not completed + if (xhrRequest.readyState == 4) + { + self.status = xhrRequest.status; + self.statusText = xhrRequest.statusText; + self.responseText = xhrRequest.responseText; + self.responseXML = xhrRequest.responseXML; + } + } + }; + + var updateXHRPropertiesIgnore = { + channel: 1, + onreadystatechange: 1, + readyState: 1, + responseBody: 1, + responseText: 1, + responseXML: 1, + status: 1, + statusText: 1, + upload: 1 + }; + + var updateXHRProperties = function() + { + for (var propName in self) + { + if (propName in updateXHRPropertiesIgnore) + continue; + + try + { + var propValue = self[propName]; + + if (propValue && !xhrRequest[propName]) + { + xhrRequest[propName] = propValue; + } + } + catch(E) + { + //console.log(propName, E.message); + } + } + }; + + var logXHR = function() + { + var row = Firebug.Console.log(spy, null, "spy", Firebug.Spy.XHR); + + if (row) + { + setClass(row, "loading"); + spy.logRow = row; + } + }; + + var finishXHR = function() + { + var duration = new Date().getTime() - reqStartTS; + var success = xhrRequest.status == 200; + + var responseHeadersText = xhrRequest.getAllResponseHeaders(); + var responses = responseHeadersText ? responseHeadersText.split(/[\n\r]/) : []; + var reHeader = /^(\S+):\s*(.*)/; + + for (var i=0, l=responses.length; i 0; + + /**/ + + return this; +}; + +// ************************************************************************************************ +// ActiveXObject Wrapper (IE6 only) + +var _ActiveXObject; +var isIE6 = /msie 6/i.test(navigator.appVersion); + +if (isIE6) +{ + _ActiveXObject = window.ActiveXObject; + + var xhrObjects = " MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP "; + + window.ActiveXObject = function(name) + { + var error = null; + + try + { + var activeXObject = new _ActiveXObject(name); + } + catch(e) + { + error = e; + } + finally + { + if (!error) + { + if (xhrObjects.indexOf(" " + name + " ") != -1) + return new XMLHttpRequestWrapper(activeXObject); + else + return activeXObject; + } + else + throw error.message; + } + }; +} + +// ************************************************************************************************ + +// Register the XMLHttpRequestWrapper for non-IE6 browsers +if (!isIE6) +{ + var _XMLHttpRequest = XMLHttpRequest; + window.XMLHttpRequest = function() + { + return new XMLHttpRequestWrapper(); + }; +} + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var reIgnore = /about:|javascript:|resource:|chrome:|jar:/; +var layoutInterval = 300; +var indentWidth = 18; + +var cacheSession = null; +var contexts = new Array(); +var panelName = "net"; +var maxQueueRequests = 500; +//var panelBar1 = $("fbPanelBar1"); // chrome not available at startup +var activeRequests = []; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var mimeExtensionMap = +{ + "txt": "text/plain", + "html": "text/html", + "htm": "text/html", + "xhtml": "text/html", + "xml": "text/xml", + "css": "text/css", + "js": "application/x-javascript", + "jss": "application/x-javascript", + "jpg": "image/jpg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "png": "image/png", + "bmp": "image/bmp", + "swf": "application/x-shockwave-flash", + "flv": "video/x-flv" +}; + +var fileCategories = +{ + "undefined": 1, + "html": 1, + "css": 1, + "js": 1, + "xhr": 1, + "image": 1, + "flash": 1, + "txt": 1, + "bin": 1 +}; + +var textFileCategories = +{ + "txt": 1, + "html": 1, + "xhr": 1, + "css": 1, + "js": 1 +}; + +var binaryFileCategories = +{ + "bin": 1, + "flash": 1 +}; + +var mimeCategoryMap = +{ + "text/plain": "txt", + "application/octet-stream": "bin", + "text/html": "html", + "text/xml": "html", + "text/css": "css", + "application/x-javascript": "js", + "text/javascript": "js", + "application/javascript" : "js", + "image/jpeg": "image", + "image/jpg": "image", + "image/gif": "image", + "image/png": "image", + "image/bmp": "image", + "application/x-shockwave-flash": "flash", + "video/x-flv": "flash" +}; + +var binaryCategoryMap = +{ + "image": 1, + "flash" : 1 +}; + +// ************************************************************************************************ + +/** + * @module Represents a module object for the Net panel. This object is derived + * from Firebug.ActivableModule in order to support activation (enable/disable). + * This allows to avoid (performance) expensive features if the functionality is not necessary + * for the user. + */ +Firebug.NetMonitor = extend(Firebug.ActivableModule, +{ + dispatchName: "netMonitor", + + clear: function(context) + { + // The user pressed a Clear button so, remove content of the panel... + var panel = context.getPanel(panelName, true); + if (panel) + panel.clear(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + return; + + this.panelName = panelName; + + Firebug.ActivableModule.initialize.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + // HTTP observer must be registered now (and not in monitorContext, since if a + // page is opened in a new tab the top document request would be missed otherwise. + NetHttpObserver.registerObserver(); + NetHttpActivityObserver.registerObserver(); + + Firebug.Debugger.addListener(this.DebuggerListener); + }, + + shutdown: function() + { + return; + + prefs.removeObserver(Firebug.prefDomain, this, false); + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + + NetHttpObserver.unregisterObserver(); + NetHttpActivityObserver.unregisterObserver(); + + Firebug.Debugger.removeListener(this.DebuggerListener); + } +}); + + +/** + * @domplate Represents a template that is used to reneder detailed info about a request. + * This template is rendered when a request is expanded. + */ +Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep, new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoBody", _repObject: "$file"}, + TAG("$infoTabs", {file: "$file"}), + TAG("$infoBodies", {file: "$file"}) + ), + + infoTabs: + DIV({"class": "netInfoTabs focusRow subFocusRow", "role": "tablist"}, + A({"class": "netInfoParamsTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Params", + $collapsed: "$file|hideParams"}, + $STR("URLParameters") + ), + A({"class": "netInfoHeadersTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Headers"}, + $STR("Headers") + ), + A({"class": "netInfoPostTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Post", + $collapsed: "$file|hidePost"}, + $STR("Post") + ), + A({"class": "netInfoPutTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Put", + $collapsed: "$file|hidePut"}, + $STR("Put") + ), + A({"class": "netInfoResponseTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Response", + $collapsed: "$file|hideResponse"}, + $STR("Response") + ), + A({"class": "netInfoCacheTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Cache", + $collapsed: "$file|hideCache"}, + $STR("Cache") + ), + A({"class": "netInfoHtmlTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Html", + $collapsed: "$file|hideHtml"}, + $STR("HTML") + ) + ), + + infoBodies: + DIV({"class": "netInfoBodies outerFocusRow"}, + TABLE({"class": "netInfoParamsText netInfoText netInfoParamsTable", "role": "tabpanel", + cellpadding: 0, cellspacing: 0}, TBODY()), + DIV({"class": "netInfoHeadersText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPostText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPutText netInfoText", "role": "tabpanel"}), + PRE({"class": "netInfoResponseText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoCacheText netInfoText", "role": "tabpanel"}, + TABLE({"class": "netInfoCacheTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("Cache")}) + ) + ), + DIV({"class": "netInfoHtmlText netInfoText", "role": "tabpanel"}, + IFRAME({"class": "netInfoHtmlPreview", "role": "document"}) + ) + ), + + headerDataTag: + FOR("param", "$headers", + TR({"role": "listitem"}, + TD({"class": "netInfoParamName", "role": "presentation"}, + TAG("$param|getNameTag", {param: "$param"}) + ), + TD({"class": "netInfoParamValue", "role": "list", "aria-label": "$param.name"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class": "focusRow subFocusRow", "role": "listitem"}, "$line") + ) + ) + ) + ), + + customTab: + A({"class": "netInfo$tabId\\Tab netInfoTab", onclick: "$onClickTab", view: "$tabId", "role": "tab"}, + "$tabTitle" + ), + + customBody: + DIV({"class": "netInfo$tabId\\Text netInfoText", "role": "tabpanel"}), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + nameTag: + SPAN("$param|getParamName"), + + nameWithTooltipTag: + SPAN({title: "$param.name"}, "$param|getParamName"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getNameTag: function(param) + { + return (this.getParamName(param) == param.name) ? this.nameTag : this.nameWithTooltipTag; + }, + + getParamName: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + name = name.substr(0, limit) + "..."; + return name; + }, + + getParamTitle: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + return name; + return ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + hideParams: function(file) + { + return !file.urlParams || !file.urlParams.length; + }, + + hidePost: function(file) + { + return file.method.toUpperCase() != "POST"; + }, + + hidePut: function(file) + { + return file.method.toUpperCase() != "PUT"; + }, + + hideResponse: function(file) + { + return false; + //return file.category in binaryFileCategories; + }, + + hideCache: function(file) + { + return true; + //xxxHonza: I don't see any reason why not to display the cache also info for images. + return !file.cacheEntry; // || file.category=="image"; + }, + + hideHtml: function(file) + { + return (file.mimeType != "text/html") && (file.mimeType != "application/xhtml+xml"); + }, + + onClickTab: function(event) + { + this.selectTab(event.currentTarget || event.srcElement); + }, + + getParamValueIterator: function(param) + { + // TODO: xxxpedro console2 + return param.value; + + // This value is inserted into CODE element and so, make sure the HTML isn't escaped (1210). + // This is why the second parameter is true. + // The CODE (with style white-space:pre) element preserves whitespaces so they are + // displayed the same, as they come from the server (1194). + // In case of a long header values of post parameters the value must be wrapped (2105). + return wrapText(param.value, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + appendTab: function(netInfoBox, tabId, tabTitle) + { + // Create new tab and body. + var args = {tabId: tabId, tabTitle: tabTitle}; + ///this.customTab.append(args, netInfoBox.getElementsByClassName("netInfoTabs").item(0)); + ///this.customBody.append(args, netInfoBox.getElementsByClassName("netInfoBodies").item(0)); + this.customTab.append(args, $$(".netInfoTabs", netInfoBox)[0]); + this.customBody.append(args, $$(".netInfoBodies", netInfoBox)[0]); + }, + + selectTabByName: function(netInfoBox, tabName) + { + var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab"); + if (tab) + this.selectTab(tab); + }, + + selectTab: function(tab) + { + var view = tab.getAttribute("view"); + + var netInfoBox = getAncestorByClass(tab, "netInfoBody"); + + var selectedTab = netInfoBox.selectedTab; + + if (selectedTab) + { + //netInfoBox.selectedText.removeAttribute("selected"); + removeClass(netInfoBox.selectedText, "netInfoTextSelected"); + + removeClass(selectedTab, "netInfoTabSelected"); + //selectedTab.removeAttribute("selected"); + selectedTab.setAttribute("aria-selected", "false"); + } + + var textBodyName = "netInfo" + view + "Text"; + + selectedTab = netInfoBox.selectedTab = tab; + + netInfoBox.selectedText = $$("."+textBodyName, netInfoBox)[0]; + //netInfoBox.selectedText = netInfoBox.getElementsByClassName(textBodyName).item(0); + + //netInfoBox.selectedText.setAttribute("selected", "true"); + setClass(netInfoBox.selectedText, "netInfoTextSelected"); + + setClass(selectedTab, "netInfoTabSelected"); + selectedTab.setAttribute("selected", "true"); + selectedTab.setAttribute("aria-selected", "true"); + + var file = Firebug.getRepObject(netInfoBox); + + //var context = Firebug.getElementPanel(netInfoBox).context; + var context = Firebug.chrome; + + this.updateInfo(netInfoBox, file, context); + }, + + updateInfo: function(netInfoBox, file, context) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.updateInfo; file", file); + + if (!netInfoBox) + { + if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS) + FBTrace.sysout("net.updateInfo; ERROR netInfo == null " + file.href, file); + return; + } + + var tab = netInfoBox.selectedTab; + + if (hasClass(tab, "netInfoParamsTab")) + { + if (file.urlParams && !netInfoBox.urlParamsPresented) + { + netInfoBox.urlParamsPresented = true; + this.insertHeaderRows(netInfoBox, file.urlParams, "Params"); + } + } + + else if (hasClass(tab, "netInfoHeadersTab")) + { + var headersText = $$(".netInfoHeadersText", netInfoBox)[0]; + //var headersText = netInfoBox.getElementsByClassName("netInfoHeadersText").item(0); + + if (file.responseHeaders && !netInfoBox.responseHeadersPresented) + { + netInfoBox.responseHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.responseHeaders, "ResponseHeaders"); + } + + if (file.requestHeaders && !netInfoBox.requestHeadersPresented) + { + netInfoBox.requestHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.requestHeaders, "RequestHeaders"); + } + } + + else if (hasClass(tab, "netInfoPostTab")) + { + if (!netInfoBox.postPresented) + { + netInfoBox.postPresented = true; + //var postText = netInfoBox.getElementsByClassName("netInfoPostText").item(0); + var postText = $$(".netInfoPostText", netInfoBox)[0]; + NetInfoPostData.render(context, postText, file); + } + } + + else if (hasClass(tab, "netInfoPutTab")) + { + if (!netInfoBox.putPresented) + { + netInfoBox.putPresented = true; + //var putText = netInfoBox.getElementsByClassName("netInfoPutText").item(0); + var putText = $$(".netInfoPutText", netInfoBox)[0]; + NetInfoPostData.render(context, putText, file); + } + } + + else if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented) + { + ///var responseTextBox = netInfoBox.getElementsByClassName("netInfoResponseText").item(0); + var responseTextBox = $$(".netInfoResponseText", netInfoBox)[0]; + if (file.category == "image") + { + netInfoBox.responsePresented = true; + + var responseImage = netInfoBox.ownerDocument.createElement("img"); + responseImage.src = file.href; + + clearNode(responseTextBox); + responseTextBox.appendChild(responseImage, responseTextBox); + } + else ///if (!(binaryCategoryMap.hasOwnProperty(file.category))) + { + this.setResponseText(file, netInfoBox, responseTextBox, context); + } + } + + else if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented) + { + var responseTextBox = netInfoBox.getElementsByClassName("netInfoCacheText").item(0); + if (file.cacheEntry) { + netInfoBox.cachePresented = true; + this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache"); + } + } + + else if (hasClass(tab, "netInfoHtmlTab") && file.loaded && !netInfoBox.htmlPresented) + { + netInfoBox.htmlPresented = true; + + var text = Utils.getResponseText(file, context); + + ///var iframe = netInfoBox.getElementsByClassName("netInfoHtmlPreview").item(0); + var iframe = $$(".netInfoHtmlPreview", netInfoBox)[0]; + + ///iframe.contentWindow.document.body.innerHTML = text; + + // TODO: xxxpedro net - remove scripts + var reScript = //gi; + + text = text.replace(reScript, ""); + + iframe.contentWindow.document.write(text); + iframe.contentWindow.document.close(); + } + + // Notify listeners about update so, content of custom tabs can be updated. + dispatch(NetInfoBody.fbListeners, "updateTabBody", [netInfoBox, file, context]); + }, + + setResponseText: function(file, netInfoBox, responseTextBox, context) + { + //********************************************** + //********************************************** + //********************************************** + netInfoBox.responsePresented = true; + // line breaks somehow are different in IE + // make this only once in the initialization? we don't have net panels and modules yet. + if (isIE) + responseTextBox.style.whiteSpace = "nowrap"; + + responseTextBox[ + typeof responseTextBox.textContent != "undefined" ? + "textContent" : + "innerText" + ] = file.responseText; + + return; + //********************************************** + //********************************************** + //********************************************** + + // Get response text and make sure it doesn't exceed the max limit. + var text = Utils.getResponseText(file, context); + var limit = Firebug.netDisplayedResponseLimit + 15; + var limitReached = text ? (text.length > limit) : false; + if (limitReached) + text = text.substr(0, limit) + "..."; + + // Insert the response into the UI. + if (text) + insertWrappedText(text, responseTextBox); + else + insertWrappedText("", responseTextBox); + + // Append a message informing the user that the response isn't fully displayed. + if (limitReached) + { + var object = { + text: $STR("net.responseSizeLimitMessage"), + onClickLink: function() { + var panel = context.getPanel("net", true); + panel.openResponseInTab(file); + } + }; + Firebug.NetMonitor.ResponseSizeLimit.append(object, responseTextBox); + } + + netInfoBox.responsePresented = true; + + if (FBTrace.DBG_NET) + FBTrace.sysout("net.setResponseText; response text updated"); + }, + + insertHeaderRows: function(netInfoBox, headers, tableName, rowName) + { + if (!headers.length) + return; + + var headersTable = $$(".netInfo"+tableName+"Table", netInfoBox)[0]; + //var headersTable = netInfoBox.getElementsByClassName("netInfo"+tableName+"Table").item(0); + var tbody = getChildByClass(headersTable, "netInfo" + rowName + "Body"); + if (!tbody) + tbody = headersTable.firstChild; + var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title"); + + this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody); + removeClass(titleRow, "collapsed"); + } +}); + +var NetInfoBody = Firebug.NetMonitor.NetInfoBody; + +// ************************************************************************************************ + +/** + * @domplate Used within the Net panel to display raw source of request and response headers + * as well as pretty-formatted summary of these headers. + */ +Firebug.NetMonitor.NetInfoHeaders = domplate(Firebug.Rep, //new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoHeadersTable", "role": "tabpanel"}, + DIV({"class": "netInfoHeadersGroup netInfoResponseHeadersTitle"}, + SPAN($STR("ResponseHeaders")), + SPAN({"class": "netHeadersViewSource response collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "ResponseHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoResponseHeadersBody", "role": "list", + "aria-label": $STR("ResponseHeaders")}) + ), + DIV({"class": "netInfoHeadersGroup netInfoRequestHeadersTitle"}, + SPAN($STR("RequestHeaders")), + SPAN({"class": "netHeadersViewSource request collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "RequestHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoRequestHeadersBody", "role": "list", + "aria-label": $STR("RequestHeaders")}) + ) + ), + + sourceTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + PRE({"class": "source"}) + ) + ), + + onViewSource: function(event) + { + var target = event.target; + var requestHeaders = (target.rowName == "RequestHeaders"); + + var netInfoBox = getAncestorByClass(target, "netInfoBody"); + var file = netInfoBox.repObject; + + if (target.sourceDisplayed) + { + var headers = requestHeaders ? file.requestHeaders : file.responseHeaders; + this.insertHeaderRows(netInfoBox, headers, target.rowName); + target.innerHTML = $STR("net.headers.view source"); + } + else + { + var source = requestHeaders ? file.requestHeadersText : file.responseHeadersText; + this.insertSource(netInfoBox, source, target.rowName); + target.innerHTML = $STR("net.headers.pretty print"); + } + + target.sourceDisplayed = !target.sourceDisplayed; + + cancelEvent(event); + }, + + insertSource: function(netInfoBox, source, rowName) + { + // This breaks copy to clipboard. + //if (source) + // source = source.replace(/\r\n/gm, "\\r\\n\r\n"); + + ///var tbody = netInfoBox.getElementsByClassName("netInfo" + rowName + "Body").item(0); + var tbody = $$(".netInfo" + rowName + "Body", netInfoBox)[0]; + var node = this.sourceTag.replace({}, tbody); + ///var sourceNode = node.getElementsByClassName("source").item(0); + var sourceNode = $$(".source", node)[0]; + sourceNode.innerHTML = source; + }, + + insertHeaderRows: function(netInfoBox, headers, rowName) + { + var headersTable = $$(".netInfoHeadersTable", netInfoBox)[0]; + var tbody = $$(".netInfo" + rowName + "Body", headersTable)[0]; + + //var headersTable = netInfoBox.getElementsByClassName("netInfoHeadersTable").item(0); + //var tbody = headersTable.getElementsByClassName("netInfo" + rowName + "Body").item(0); + + clearNode(tbody); + + if (!headers.length) + return; + + NetInfoBody.headerDataTag.insertRows({headers: headers}, tbody); + + var titleRow = getChildByClass(headersTable, "netInfo" + rowName + "Title"); + removeClass(titleRow, "collapsed"); + }, + + init: function(parent) + { + var rootNode = this.tag.append({}, parent); + + var netInfoBox = getAncestorByClass(parent, "netInfoBody"); + var file = netInfoBox.repObject; + + var viewSource; + + viewSource = $$(".request", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource request").item(0); + if (file.requestHeadersText) + removeClass(viewSource, "collapsed"); + + viewSource = $$(".response", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource response").item(0); + if (file.responseHeadersText) + removeClass(viewSource, "collapsed"); + }, + + renderHeaders: function(parent, headers, rowName) + { + if (!parent.firstChild) + this.init(parent); + + this.insertHeaderRows(parent, headers, rowName); + } +}); + +var NetInfoHeaders = Firebug.NetMonitor.NetInfoHeaders; + +// ************************************************************************************************ + +/** + * @domplate Represents posted data within request info (the info, which is visible when + * a request entry is expanded. This template renders content of the Post tab. + */ +Firebug.NetMonitor.NetInfoPostData = domplate(Firebug.Rep, /*new Firebug.Listener(),*/ +{ + // application/x-www-form-urlencoded + paramsTable: + TABLE({"class": "netInfoPostParamsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parameters")}, + TR({"class": "netInfoPostParamsTitle", "role": "presentation"}, + TD({colspan: 3, "role": "presentation"}, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parameters"), + SPAN({"class": "netInfoPostContentType"}, + "application/x-www-form-urlencoded" + ) + ) + ) + ) + ) + ), + + // multipart/form-data + partsTable: + TABLE({"class": "netInfoPostPartsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parts")}, + TR({"class": "netInfoPostPartsTitle", "role": "presentation"}, + TD({colspan: 2, "role":"presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parts"), + SPAN({"class": "netInfoPostContentType"}, + "multipart/form-data" + ) + ) + ) + ) + ) + ), + + // application/json + jsonTable: + TABLE({"class": "netInfoPostJSONTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + ///TBODY({"role": "list", "aria-label": $STR("jsonviewer.tab.JSON")}, + TBODY({"role": "list", "aria-label": $STR("JSON")}, + TR({"class": "netInfoPostJSONTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + ///$STR("jsonviewer.tab.JSON") + $STR("JSON") + ) + ) + ), + TR( + TD({"class": "netInfoPostJSONBody"}) + ) + ) + ), + + // application/xml + xmlTable: + TABLE({"class": "netInfoPostXMLTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("xmlviewer.tab.XML")}, + TR({"class": "netInfoPostXMLTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("xmlviewer.tab.XML") + ) + ) + ), + TR( + TD({"class": "netInfoPostXMLBody"}) + ) + ) + ), + + sourceTable: + TABLE({"class": "netInfoPostSourceTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Source")}, + TR({"class": "netInfoPostSourceTitle", "role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + DIV({"class": "netInfoPostSource"}, + $STR("net.label.Source") + ) + ) + ) + ) + ), + + sourceBodyTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class":"focusRow subFocusRow" , "role": "listitem"},"$line") + ) + ) + ), + + getParamValueIterator: function(param) + { + return NetInfoBody.getParamValueIterator(param); + }, + + render: function(context, parentNode, file) + { + //debugger; + var spy = getAncestorByClass(parentNode, "spyHead"); + var spyObject = spy.repObject; + var data = spyObject.data; + + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + var contentType = file.mimeType; + + ///var text = Utils.getPostText(file, context, true); + ///if (text == undefined) + /// return; + + ///if (Utils.isURLEncodedRequest(file, context)) + // fake Utils.isURLEncodedRequest identification + if (contentType && contentType == "application/x-www-form-urlencoded" || + data && data.indexOf("=") != -1) + { + ///var lines = text.split("\n"); + ///var params = parseURLEncodedText(lines[lines.length-1]); + var params = parseURLEncodedTextArray(data); + if (params) + this.insertParameters(parentNode, params); + } + + ///if (Utils.isMultiPartRequest(file, context)) + ///{ + /// var data = this.parseMultiPartText(file, context); + /// if (data) + /// this.insertParts(parentNode, data); + ///} + + // moved to the top + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + + ///if (Firebug.JSONViewerModel.isJSON(contentType)) + var jsonData = { + responseText: data + }; + + if (Firebug.JSONViewerModel.isJSON(contentType, data)) + ///this.insertJSON(parentNode, file, context); + this.insertJSON(parentNode, jsonData, context); + + ///if (Firebug.XMLViewerModel.isXML(contentType)) + /// this.insertXML(parentNode, file, context); + + ///var postText = Utils.getPostText(file, context); + ///postText = Utils.formatPostText(postText); + var postText = data; + if (postText) + this.insertSource(parentNode, postText); + }, + + insertParameters: function(parentNode, params) + { + if (!params || !params.length) + return; + + var paramTable = this.paramsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostParamsTitle", paramTable)[0]; + //var paramTable = this.paramsTable.append(null, parentNode); + //var row = paramTable.getElementsByClassName("netInfoPostParamsTitle").item(0); + + var tbody = paramTable.getElementsByTagName("tbody")[0]; + + NetInfoBody.headerDataTag.insertRows({headers: params}, row); + }, + + insertParts: function(parentNode, data) + { + if (!data.params || !data.params.length) + return; + + var partsTable = this.partsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostPartsTitle", paramTable)[0]; + //var partsTable = this.partsTable.append(null, parentNode); + //var row = partsTable.getElementsByClassName("netInfoPostPartsTitle").item(0); + + NetInfoBody.headerDataTag.insertRows({headers: data.params}, row); + }, + + insertJSON: function(parentNode, file, context) + { + ///var text = Utils.getPostText(file, context); + var text = file.responseText; + ///var data = parseJSONString(text, "http://" + file.request.originalURI.host); + var data = parseJSONString(text); + if (!data) + return; + + ///var jsonTable = this.jsonTable.append(null, parentNode); + var jsonTable = this.jsonTable.append({}, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostJSONBody").item(0); + var jsonBody = $$(".netInfoPostJSONBody", jsonTable)[0]; + + if (!this.toggles) + this.toggles = {}; + + Firebug.DOMPanel.DirTable.tag.replace( + {object: data, toggles: this.toggles}, jsonBody); + }, + + insertXML: function(parentNode, file, context) + { + var text = Utils.getPostText(file, context); + + var jsonTable = this.xmlTable.append(null, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostXMLBody").item(0); + var jsonBody = $$(".netInfoPostXMLBody", jsonTable)[0]; + + Firebug.XMLViewerModel.insertXML(jsonBody, text); + }, + + insertSource: function(parentNode, text) + { + var sourceTable = this.sourceTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostSourceTitle", sourceTable)[0]; + //var sourceTable = this.sourceTable.append(null, parentNode); + //var row = sourceTable.getElementsByClassName("netInfoPostSourceTitle").item(0); + + var param = {value: [text]}; + this.sourceBodyTag.insertRows({param: param}, row); + }, + + parseMultiPartText: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text == undefined) + return null; + + FBTrace.sysout("net.parseMultiPartText; boundary: ", text); + + var boundary = text.match(/\s*boundary=\s*(.*)/)[1]; + + var divider = "\r\n\r\n"; + var bodyStart = text.indexOf(divider); + var body = text.substr(bodyStart + divider.length); + + var postData = {}; + postData.mimeType = "multipart/form-data"; + postData.params = []; + + var parts = body.split("--" + boundary); + for (var i=0; i 1) ? m[1] : "", + value: trim(part[1]) + }); + } + + return postData; + } +}); + +var NetInfoPostData = Firebug.NetMonitor.NetInfoPostData; + +// ************************************************************************************************ + + +// TODO: xxxpedro net i18n +var $STRP = function(a){return a;}; + +Firebug.NetMonitor.NetLimit = domplate(Firebug.Rep, +{ + collapsed: true, + + tableTag: + DIV( + TABLE({width: "100%", cellpadding: 0, cellspacing: 0}, + TBODY() + ) + ), + + limitTag: + TR({"class": "netRow netLimitRow", $collapsed: "$isCollapsed"}, + TD({"class": "netCol netLimitCol", colspan: 6}, + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY( + TR( + TD( + SPAN({"class": "netLimitLabel"}, + $STRP("plural.Limit_Exceeded", [0]) + ) + ), + TD({style: "width:100%"}), + TD( + BUTTON({"class": "netLimitButton", title: "$limitPrefsTitle", + onclick: "$onPreferences"}, + $STR("LimitPrefs") + ) + ), + TD(" ") + ) + ) + ) + ) + ), + + isCollapsed: function() + { + return this.collapsed; + }, + + onPreferences: function(event) + { + openNewTab("about:config"); + }, + + updateCounter: function(row) + { + removeClass(row, "collapsed"); + + // Update info within the limit row. + var limitLabel = row.getElementsByClassName("netLimitLabel").item(0); + limitLabel.firstChild.nodeValue = $STRP("plural.Limit_Exceeded", [row.limitInfo.totalCount]); + }, + + createTable: function(parent, limitInfo) + { + var table = this.tableTag.replace({}, parent); + var row = this.createRow(table.firstChild.firstChild, limitInfo); + return [table, row]; + }, + + createRow: function(parent, limitInfo) + { + var row = this.limitTag.insertRows(limitInfo, parent, this)[0]; + row.limitInfo = limitInfo; + return row; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + if (data.indexOf("net.logLimit") != -1) + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = Firebug.getPref(Firebug.prefDomain, "net.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + } +}); + +var NetLimit = Firebug.NetMonitor.NetLimit; + +// ************************************************************************************************ + +Firebug.NetMonitor.ResponseSizeLimit = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "netInfoResponseSizeLimit"}, + SPAN("$object.beforeLink"), + A({"class": "objectLink", onclick: "$onClickLink"}, + "$object.linkText" + ), + SPAN("$object.afterLink") + ), + + reLink: /^(.*)(.*)<\/a>(.*$)/, + append: function(obj, parent) + { + var m = obj.text.match(this.reLink); + return this.tag.append({onClickLink: obj.onClickLink, + object: { + beforeLink: m[1], + linkText: m[2], + afterLink: m[3] + }}, parent, this); + } +}); + +// ************************************************************************************************ +// ************************************************************************************************ + +Firebug.NetMonitor.Utils = +{ + findHeader: function(headers, name) + { + if (!headers) + return null; + + name = name.toLowerCase(); + for (var i = 0; i < headers.length; ++i) + { + var headerName = headers[i].name.toLowerCase(); + if (headerName == name) + return headers[i].value; + } + }, + + formatPostText: function(text) + { + if (text instanceof XMLDocument) + return getElementXML(text.documentElement); + else + return text; + }, + + getPostText: function(file, context, noLimit) + { + if (!file.postText) + { + file.postText = readPostTextFromRequest(file.request, context); + + if (!file.postText && context) + file.postText = readPostTextFromPage(file.href, context); + } + + if (!file.postText) + return file.postText; + + var limit = Firebug.netDisplayedPostBodyLimit; + if (file.postText.length > limit && !noLimit) + { + return cropString(file.postText, limit, + "\n\n... " + $STR("net.postDataSizeLimitMessage") + " ...\n\n"); + } + + return file.postText; + }, + + getResponseText: function(file, context) + { + // The response can be also empty string so, check agains "undefined". + return (typeof(file.responseText) != "undefined")? file.responseText : + context.sourceCache.loadText(file.href, file.method, file); + }, + + isURLEncodedRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded") == 0) + return true; + + // The header value doesn't have to be always exactly "application/x-www-form-urlencoded", + // there can be even charset specified. So, use indexOf rather than just "==". + var headerValue = Utils.findHeader(file.requestHeaders, "content-type"); + if (headerValue && headerValue.indexOf("application/x-www-form-urlencoded") == 0) + return true; + + return false; + }, + + isMultiPartRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: multipart/form-data") == 0) + return true; + return false; + }, + + getMimeType: function(mimeType, uri) + { + if (!mimeType || !(mimeCategoryMap.hasOwnProperty(mimeType))) + { + var ext = getFileExtension(uri); + if (!ext) + return mimeType; + else + { + var extMimeType = mimeExtensionMap[ext.toLowerCase()]; + return extMimeType ? extMimeType : mimeType; + } + } + else + return mimeType; + }, + + getDateFromSeconds: function(s) + { + var d = new Date(); + d.setTime(s*1000); + return d; + }, + + getHttpHeaders: function(request, file) + { + try + { + var http = QI(request, Ci.nsIHttpChannel); + file.status = request.responseStatus; + + // xxxHonza: is there any problem to do this in requestedFile method? + file.method = http.requestMethod; + file.urlParams = parseURLParams(file.href); + file.mimeType = Utils.getMimeType(request.contentType, request.name); + + if (!file.responseHeaders && Firebug.collectHttpHeaders) + { + var requestHeaders = [], responseHeaders = []; + + http.visitRequestHeaders({ + visitHeader: function(name, value) + { + requestHeaders.push({name: name, value: value}); + } + }); + http.visitResponseHeaders({ + visitHeader: function(name, value) + { + responseHeaders.push({name: name, value: value}); + } + }); + + file.requestHeaders = requestHeaders; + file.responseHeaders = responseHeaders; + } + } + catch (exc) + { + // An exception can be throwed e.g. when the request is aborted and + // request.responseStatus is accessed. + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("net.getHttpHeaders FAILS " + file.href, exc); + } + }, + + isXHR: function(request) + { + try + { + var callbacks = request.notificationCallbacks; + var xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null; + if (FBTrace.DBG_NET) + FBTrace.sysout("net.isXHR; " + (xhrRequest != null) + ", " + safeGetName(request)); + + return (xhrRequest != null); + } + catch (exc) + { + } + + return false; + }, + + getFileCategory: function(file) + { + if (file.category) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; current: " + file.category + " for: " + file.href, file); + return file.category; + } + + if (file.isXHR) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; XHR for: " + file.href, file); + return file.category = "xhr"; + } + + if (!file.mimeType) + { + var ext = getFileExtension(file.href); + if (ext) + file.mimeType = mimeExtensionMap[ext.toLowerCase()]; + } + + /*if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; " + mimeCategoryMap[file.mimeType] + + ", mimeType: " + file.mimeType + " for: " + file.href, file);*/ + + if (!file.mimeType) + return ""; + + // Solve cases when charset is also specified, eg "text/html; charset=UTF-8". + var mimeType = file.mimeType; + if (mimeType) + mimeType = mimeType.split(";")[0]; + + return (file.category = mimeCategoryMap[mimeType]); + } +}; + +var Utils = Firebug.NetMonitor.Utils; + +// ************************************************************************************************ + +//Firebug.registerRep(Firebug.NetMonitor.NetRequestTable); +//Firebug.registerActivableModule(Firebug.NetMonitor); +//Firebug.registerPanel(NetPanel); + +Firebug.registerModule(Firebug.NetMonitor); +//Firebug.registerRep(Firebug.NetMonitor.BreakpointRep); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +// List of contexts with XHR spy attached. +var contexts = []; + +// ************************************************************************************************ +// Spy Module + +/** + * @module Represents a XHR Spy module. The main purpose of the XHR Spy feature is to monitor + * XHR activity of the current page and create appropriate log into the Console panel. + * This feature can be controlled by an option Show XMLHttpRequests (from within the + * console panel). + * + * The module is responsible for attaching/detaching a HTTP Observers when Firebug is + * activated/deactivated for a site. + */ +Firebug.Spy = extend(Firebug.Module, +/** @lends Firebug.Spy */ +{ + dispatchName: "spy", + + initialize: function() + { + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + Firebug.Module.initialize.apply(this, arguments); + }, + + shutdown: function() + { + Firebug.Module.shutdown.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + }, + + initContext: function(context) + { + context.spies = []; + + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, context.window); + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.initContext " + contexts.length + " ", context.getName()); + }, + + destroyContext: function(context) + { + // For any spies that are in progress, remove our listeners so that they don't leak + this.detachObserver(context, null); + + if (FBTrace.DBG_SPY && context.spies.length) + FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies (" + + context.spies.length + ") " + context.getName()); + + delete context.spies; + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.destroyContext " + contexts.length + " ", context.getName()); + }, + + watchWindow: function(context, win) + { + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, win); + }, + + unwatchWindow: function(context, win) + { + try + { + // This make sure that the existing context is properly removed from "contexts" array. + this.detachObserver(context, win); + } + catch (ex) + { + // Get exceptions here sometimes, so let's just ignore them + // since the window is going away anyhow + ERROR(ex); + } + }, + + updateOption: function(name, value) + { + // XXXjjb Honza, if Console.isEnabled(context) false, then this can't be called, + // but somehow seems not correct + if (name == "showXMLHttpRequests") + { + var tach = value ? this.attachObserver : this.detachObserver; + for (var i = 0; i < TabWatcher.contexts.length; ++i) + { + var context = TabWatcher.contexts[i]; + iterateWindows(context.window, function(win) + { + tach.apply(this, [context, win]); + }); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Attaching Spy to XHR requests. + + /** + * Returns false if Spy should not be attached to XHRs executed by the specified window. + */ + skipSpy: function(win) + { + if (!win) + return true; + + // Don't attach spy to chrome. + var uri = safeGetWindowLocation(win); + if (uri && (uri.indexOf("about:") == 0 || uri.indexOf("chrome:") == 0)) + return true; + }, + + attachObserver: function(context, win) + { + if (Firebug.Spy.skipSpy(win)) + return; + + for (var i=0; insIHttpChannel. + * Returns null if the request doesn't represent XHR. + */ + getXHR: function(request) + { + // Does also query-interface for nsIHttpChannel. + if (!(request instanceof Ci.nsIHttpChannel)) + return null; + + try + { + var callbacks = request.notificationCallbacks; + return (callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null); + } + catch (exc) + { + if (exc.name == "NS_NOINTERFACE") + { + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.getXHR; Request is not nsIXMLHttpRequest: " + + safeGetRequestName(request)); + } + } + + return null; + } +}); + + + + + +// ************************************************************************************************ + +/* +function getSpyForXHR(request, xhrRequest, context, noCreate) +{ + var spy = null; + + // Iterate all existing spy objects in this context and look for one that is + // already created for this request. + var length = context.spies.length; + for (var i=0; i= 3) + { + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (netInfoBox) + { + netInfoBox.htmlPresented = false; + netInfoBox.responsePresented = false; + } + } + + // If the request is loading update the end time. + if (spy.xhrRequest.readyState == 3) + { + spy.responseTime = spy.endTime - spy.sendTime; + updateTime(spy); + } + + // Request loaded. Get all the info from the request now, just in case the + // XHR would be aborted in the original onReadyStateChange handler. + if (spy.xhrRequest.readyState == 4) + { + // Cumulate response so, multipart response content is properly displayed. + if (SpyHttpActivityObserver.getActivityDistributor()) + spy.responseText += spy.xhrRequest.responseText; + else + { + // xxxHonza: remove from FB 1.6 + if (!spy.responseText) + spy.responseText = spy.xhrRequest.responseText; + } + + // The XHR is loaded now (used also by the activity observer). + spy.loaded = true; + + // Update UI. + updateHttpSpyInfo(spy); + + // Notify Net pane about a request beeing loaded. + // xxxHonza: I don't think this is necessary. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.stopFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); + + // Notify registered listeners about finish of the XHR. + dispatch(Firebug.Spy.fbListeners, "onLoad", [spy.context, spy]); + } + + // Pass the event to the original page handler. + callPageHandler(spy, event, originalHandler); +} + +function onHTTPSpyLoad(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyLoad: " + spy.href, spy); + + // Detach must be done in onLoad (not in onreadystatechange) otherwise + // onAbort would not be handled. + spy.detach(); + + // xxxHonza: Still needed for Fx 3.5 (#502959) + if (!SpyHttpActivityObserver.getActivityDistributor()) + onHTTPSpyReadyStateChange(spy, null); +} + +function onHTTPSpyError(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyError; " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } +} + +function onHTTPSpyAbort(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyAbort: " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } + + spy.statusText = "Aborted"; + updateLogRow(spy); + + // Notify Net pane about a request beeing aborted. + // xxxHonza: the net panel shoud find out this itself. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.abortFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); +} +/**/ + +// ************************************************************************************************ + +/** + * @domplate Represents a template for XHRs logged in the Console panel. The body of the + * log (displayed when expanded) is rendered using {@link Firebug.NetMonitor.NetInfoBody}. + */ + +Firebug.Spy.XHR = domplate(Firebug.Rep, +/** @lends Firebug.Spy.XHR */ + +{ + tag: + DIV({"class": "spyHead", _repObject: "$object"}, + TABLE({"class": "spyHeadTable focusRow outerFocusRow", cellpadding: 0, cellspacing: 0, + "role": "listitem", "aria-expanded": "false"}, + TBODY({"role": "presentation"}, + TR({"class": "spyRow"}, + TD({"class": "spyTitleCol spyCol", onclick: "$onToggleBody"}, + DIV({"class": "spyTitle"}, + "$object|getCaption" + ), + DIV({"class": "spyFullTitle spyTitle"}, + "$object|getFullUri" + ) + ), + TD({"class": "spyCol"}, + DIV({"class": "spyStatus"}, "$object|getStatus") + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyIcon"}) + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyTime"}) + ), + TD({"class": "spyCol"}, + TAG(FirebugReps.SourceLink.tag, {object: "$object.sourceLink"}) + ) + ) + ) + ) + ), + + getCaption: function(spy) + { + return spy.method.toUpperCase() + " " + cropString(spy.getURL(), 100); + }, + + getFullUri: function(spy) + { + return spy.method.toUpperCase() + " " + spy.getURL(); + }, + + getStatus: function(spy) + { + var text = ""; + if (spy.statusCode) + text += spy.statusCode + " "; + + if (spy.statusText) + return text += spy.statusText; + + return text; + }, + + onToggleBody: function(event) + { + var target = event.currentTarget || event.srcElement; + var logRow = getAncestorByClass(target, "logRow-spy"); + + if (isLeftClick(event)) + { + toggleClass(logRow, "opened"); + + var spy = getChildByClass(logRow, "spyHead").repObject; + var spyHeadTable = getAncestorByClass(target, "spyHeadTable"); + + if (hasClass(logRow, "opened")) + { + updateHttpSpyInfo(spy, logRow); + if (spyHeadTable) + spyHeadTable.setAttribute('aria-expanded', 'true'); + } + else + { + //var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + //dispatch(Firebug.NetMonitor.NetInfoBody.fbListeners, "destroyTabBody", [netInfoBox, spy]); + //if (spyHeadTable) + // spyHeadTable.setAttribute('aria-expanded', 'false'); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(spy) + { + copyToClipboard(spy.getURL()); + }, + + copyParams: function(spy) + { + var text = spy.postText; + if (!text) + return; + + var url = reEncodeURL(spy, text, true); + copyToClipboard(url); + }, + + copyResponse: function(spy) + { + copyToClipboard(spy.responseText); + }, + + openInTab: function(spy) + { + openNewTab(spy.getURL(), spy.postText); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object) + { + // TODO: xxxpedro spy xhr + return false; + + return object instanceof Firebug.Spy.XMLHttpRequestSpy; + }, + + browseObject: function(spy, context) + { + var url = spy.getURL(); + openNewTab(url); + return true; + }, + + getRealObject: function(spy, context) + { + return spy.xhrRequest; + }, + + getContextMenuItems: function(spy) + { + var items = [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, spy) } + ]; + + if (spy.postText) + { + items.push( + {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, spy) } + ); + } + + items.push( + {label: "CopyResponse", command: bindFixed(this.copyResponse, this, spy) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, spy) } + ); + + return items; + } +}); + +// ************************************************************************************************ + +function updateTime(spy) +{ + var timeBox = spy.logRow.getElementsByClassName("spyTime").item(0); + if (spy.responseTime) + timeBox.textContent = " " + formatTime(spy.responseTime); +} + +function updateLogRow(spy) +{ + updateTime(spy); + + var statusBox = spy.logRow.getElementsByClassName("spyStatus").item(0); + statusBox.textContent = Firebug.Spy.XHR.getStatus(spy); + + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "loaded"); + + try + { + var errorRange = Math.floor(spy.xhrRequest.status/100); + if (errorRange == 4 || errorRange == 5) + setClass(spy.logRow, "error"); + } + catch (exc) + { + } +} + +var updateHttpSpyInfo = function updateHttpSpyInfo(spy, logRow) +{ + if (!spy.logRow && logRow) + spy.logRow = logRow; + + if (!spy.logRow || !hasClass(spy.logRow, "opened")) + return; + + if (!spy.params) + //spy.params = parseURLParams(spy.href+""); + spy.params = parseURLParams(spy.href+""); + + if (!spy.requestHeaders) + spy.requestHeaders = getRequestHeaders(spy); + + if (!spy.responseHeaders && spy.loaded) + spy.responseHeaders = getResponseHeaders(spy); + + var template = Firebug.NetMonitor.NetInfoBody; + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (!netInfoBox) + { + var head = getChildByClass(spy.logRow, "spyHead"); + netInfoBox = template.tag.append({"file": spy}, head); + dispatch(template.fbListeners, "initTabBody", [netInfoBox, spy]); + template.selectTabByName(netInfoBox, "Response"); + } + else + { + template.updateInfo(netInfoBox, spy, spy.context); + } +}; + + + +// ************************************************************************************************ + +function getRequestHeaders(spy) +{ + var headers = []; + + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitRequestHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + + return headers; +} + +function getResponseHeaders(spy) +{ + var headers = []; + + try + { + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitResponseHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + } + catch (exc) + { + if (FBTrace.DBG_SPY || FBTrace.DBG_ERRORS) + FBTrace.sysout("spy.getResponseHeaders; EXCEPTION " + + safeGetRequestName(spy.request), exc); + } + + return headers; +} + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.Spy); +//Firebug.registerRep(Firebug.Spy.XHR); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ + +// List of JSON content types. +var contentTypes = +{ + "text/plain": 1, + "text/javascript": 1, + "text/x-javascript": 1, + "text/json": 1, + "text/x-json": 1, + "application/json": 1, + "application/x-json": 1, + "application/javascript": 1, + "application/x-javascript": 1, + "application/json-rpc": 1 +}; + +// ************************************************************************************************ +// Model implementation + +Firebug.JSONViewerModel = extend(Firebug.Module, +{ + dispatchName: "jsonViewer", + initialize: function() + { + Firebug.NetMonitor.NetInfoBody.addListener(this); + + // Used by Firebug.DOMPanel.DirTable domplate. + this.toggles = {}; + }, + + shutdown: function() + { + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody", infoBox); + + // Let listeners to parse the JSON. + dispatch(this.fbListeners, "onParseJSON", [file]); + + // The JSON is still no there, try to parse most common cases. + if (!file.jsonObject) + { + ///if (this.isJSON(safeGetContentType(file.request), file.responseText)) + if (this.isJSON(file.mimeType, file.responseText)) + file.jsonObject = this.parseJSON(file); + } + + // The jsonObject is created so, the JSON tab can be displayed. + if (file.jsonObject && hasProperties(file.jsonObject)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "JSON", + ///$STR("jsonviewer.tab.JSON")); + $STR("JSON")); + + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody; JSON object available " + + (typeof(file.jsonObject) != "undefined"), file.jsonObject); + } + }, + + isJSON: function(contentType, data) + { + // Workaround for JSON responses without proper content type + // Let's consider all responses starting with "{" as JSON. In the worst + // case there will be an exception when parsing. This means that no-JSON + // responses (and post data) (with "{") can be parsed unnecessarily, + // which represents a little overhead, but this happens only if the request + // is actually expanded by the user in the UI (Net & Console panels). + + ///var responseText = data ? trimLeft(data) : null; + ///if (responseText && responseText.indexOf("{") == 0) + /// return true; + var responseText = data ? trim(data) : null; + if (responseText && responseText.indexOf("{") == 0) + return true; + + if (!contentType) + return false; + + contentType = contentType.split(";")[0]; + contentType = trim(contentType); + return contentTypes[contentType]; + }, + + // Update listener for TabView + updateTabBody: function(infoBox, file, context) + { + var tab = infoBox.selectedTab; + ///var tabBody = infoBox.getElementsByClassName("netInfoJSONText").item(0); + var tabBody = $$(".netInfoJSONText", infoBox)[0]; + if (!hasClass(tab, "netInfoJSONTab") || tabBody.updated) + return; + + tabBody.updated = true; + + if (file.jsonObject) { + Firebug.DOMPanel.DirTable.tag.replace( + {object: file.jsonObject, toggles: this.toggles}, tabBody); + } + }, + + parseJSON: function(file) + { + var jsonString = new String(file.responseText); + ///return parseJSONString(jsonString, "http://" + file.request.originalURI.host); + return parseJSONString(jsonString); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.JSONViewerModel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +// List of XML related content types. +var xmlContentTypes = +[ + "text/xml", + "application/xml", + "application/xhtml+xml", + "application/rss+xml", + "application/atom+xml",, + "application/vnd.mozilla.maybe.feed", + "application/rdf+xml", + "application/vnd.mozilla.xul+xml" +]; + +// ************************************************************************************************ +// Model implementation + +/** + * @module Implements viewer for XML based network responses. In order to create a new + * tab wihin network request detail, a listener is registered into + * Firebug.NetMonitor.NetInfoBody object. + */ +Firebug.XMLViewerModel = extend(Firebug.Module, +{ + dispatchName: "xmlViewer", + + initialize: function() + { + ///Firebug.ActivableModule.initialize.apply(this, arguments); + Firebug.Module.initialize.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.addListener(this); + }, + + shutdown: function() + { + ///Firebug.ActivableModule.shutdown.apply(this, arguments); + Firebug.Module.shutdown.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + /** + * Check response's content-type and if it's a XML, create a new tab with XML preview. + */ + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody", infoBox); + + // If the response is XML let's display a pretty preview. + ///if (this.isXML(safeGetContentType(file.request))) + if (this.isXML(file.mimeType, file.responseText)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML", + ///$STR("xmlviewer.tab.XML")); + $STR("XML")); + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody; XML response available"); + } + }, + + isXML: function(contentType) + { + if (!contentType) + return false; + + // Look if the response is XML based. + for (var i=0; i\s*/, ""); + + var div = parentNode.ownerDocument.createElement("div"); + div.innerHTML = xmlText; + + var root = div.getElementsByTagName("*")[0]; + + /*** + var parser = CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser"); + var doc = parser.parseFromString(text, "text/xml"); + var root = doc.documentElement; + + // Error handling + var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml"; + if (root.namespaceURI == nsURI && root.nodeName == "parsererror") + { + this.ParseError.tag.replace({error: { + message: root.firstChild.nodeValue, + source: root.lastChild.textContent + }}, parentNode); + return; + } + /**/ + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc); + + // Override getHidden in these templates. The parsed XML documen is + // hidden, but we want to display it using 'visible' styling. + /* + var templates = [ + Firebug.HTMLPanel.CompleteElement, + Firebug.HTMLPanel.Element, + Firebug.HTMLPanel.TextElement, + Firebug.HTMLPanel.EmptyElement, + Firebug.HTMLPanel.XEmptyElement, + ]; + + var originals = []; + for (var i=0; iFirebug.XMLViewerModel. + */ +Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "xmlInfoError"}, + DIV({"class": "xmlInfoErrorMsg"}, "$error.message"), + PRE({"class": "xmlInfoErrorSource"}, "$error|getSource") + ), + + getSource: function(error) + { + var parts = error.source.split("\n"); + if (parts.length != 2) + return error.source; + + var limit = 50; + var column = parts[1].length; + if (column >= limit) { + parts[0] = "..." + parts[0].substr(column - limit); + parts[1] = "..." + parts[1].substr(column - limit); + } + + if (parts[0].length > 80) + parts[0] = parts[0].substr(0, 80) + "..."; + + return parts.join("\n"); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.XMLViewerModel); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var ElementCache = Firebug.Lite.Cache.Element; +var cacheID = Firebug.Lite.Cache.ID; + +var ignoreHTMLProps = +{ + // ignores the attributes injected by Sizzle, otherwise it will + // be visible on IE (when enumerating element.attributes) + sizcache: 1, + sizset: 1 +}; + +// ignores also the cache property injected by firebug +ignoreHTMLProps[cacheID] = 1; + + +// ************************************************************************************************ +// HTML Module + +Firebug.HTML = extend(Firebug.Module, +{ + appendTreeNode: function(nodeArray, html) + { + var reTrim = /^\s+|\s+$/g; + + if (!nodeArray.length) nodeArray = [nodeArray]; + + for (var n=0, node; node=nodeArray[n]; n++) + { + if (node.nodeType == 1) + { + if (Firebug.ignoreFirebugElements && node.firebugIgnore) continue; + + var uid = ElementCache(node); + var child = node.childNodes; + var childLength = child.length; + + var nodeName = node.nodeName.toLowerCase(); + + var nodeVisible = isVisible(node); + + var hasSingleTextChild = childLength == 1 && node.firstChild.nodeType == 3 && + nodeName != "script" && nodeName != "style"; + + var nodeControl = !hasSingleTextChild && childLength > 0 ? + ('
      ') : ''; + + var isIE = false; + + if(isIE && nodeControl) + html.push(nodeControl); + + if (typeof uid != 'undefined') + html.push( + '
      ', + !isIE && nodeControl ? nodeControl: "", + '<', nodeName, '' + ); + else + html.push( + '
      <', + nodeName, '' + ); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || Firebug.ignoreFirebugElements && + ignoreHTMLProps.hasOwnProperty(attr.nodeName)) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? formatStyles(node.style.cssText) : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + /* + // source code nodes + if (nodeName == 'script' || nodeName == 'style') + { + + if(document.all){ + var src = node.innerHTML+'\n'; + + }else { + var src = '\n'+node.innerHTML+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + '
      '; + } + + html.push('>
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ', + '
      </', + nodeName, + '>
      ', + '
      ' + ); + + + }/**/ + + // Just a single text node child + if (hasSingleTextChild) + { + var value = child[0].nodeValue.replace(reTrim, ''); + if(value) + { + html.push( + '>', + escapeHTML(value), + '</', + nodeName, + '>' + ); + } + else + html.push('/>'); // blank text, print as childless node + + } + else if (childLength > 0) + { + html.push('>'); + } + else + html.push('/>'); + + } + else if (node.nodeType == 3) + { + if ( node.parentNode && ( node.parentNode.nodeName.toLowerCase() == "script" || + node.parentNode.nodeName.toLowerCase() == "style" ) ) + { + var value = node.nodeValue.replace(reTrim, ''); + + if(isIE){ + var src = value+'\n'; + + }else { + var src = '\n'+value+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + ''; + } + + html.push('
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ' + ); + + } + else + { + var value = node.nodeValue.replace(reTrim, ''); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + } + } + }, + + appendTreeChildren: function(treeNode) + { + var doc = Firebug.chrome.document; + var uid = treeNode.id; + var parentNode = ElementCache.get(uid); + + if (parentNode.childNodes.length == 0) return; + + var treeNext = treeNode.nextSibling; + var treeParent = treeNode.parentNode; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl nodeMaximized'; + + var html = []; + var children = doc.createElement("div"); + children.className = "nodeChildren"; + this.appendTreeNode(parentNode.childNodes, html); + children.innerHTML = html.join(""); + + treeParent.insertBefore(children, treeNext); + + var closeElement = doc.createElement("div"); + closeElement.className = "objectBox-element"; + closeElement.innerHTML = '</' + + parentNode.nodeName.toLowerCase() + '>' + + treeParent.insertBefore(closeElement, treeNext); + + }, + + removeTreeChildren: function(treeNode) + { + var children = treeNode.nextSibling; + var closeTag = children.nextSibling; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl'; + + children.parentNode.removeChild(children); + closeTag.parentNode.removeChild(closeTag); + }, + + isTreeNodeVisible: function(id) + { + return $(id); + }, + + select: function(el) + { + var id = el && ElementCache(el); + if (id) + this.selectTreeNode(id); + }, + + selectTreeNode: function(id) + { + id = ""+id; + var node, stack = []; + while(id && !this.isTreeNodeVisible(id)) + { + stack.push(id); + + var node = ElementCache.get(id).parentNode; + + if (node) + id = ElementCache(node); + else + break; + } + + stack.push(id); + + while(stack.length > 0) + { + id = stack.pop(); + node = $(id); + + if (stack.length > 0 && ElementCache.get(id).childNodes.length > 0) + this.appendTreeChildren(node); + } + + selectElement(node); + + // TODO: xxxpedro + if (fbPanel1) + fbPanel1.scrollTop = Math.round(node.offsetTop - fbPanel1.clientHeight/2); + } + +}); + +Firebug.registerModule(Firebug.HTML); + +// ************************************************************************************************ +// HTML Panel + +function HTMLPanel(){}; + +HTMLPanel.prototype = extend(Firebug.Panel, +{ + name: "HTML", + title: "HTML", + + options: { + hasSidePanel: true, + //hasToolButtons: true, + isPreRendered: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "4px 3px 1px 15px"; + this.panelNode.style.minWidth = "500px"; + + if (Env.Options.enablePersistent || Firebug.chrome.type != "popup") + this.createUI(); + + if(!this.sidePanelBar.selectedPanel) + { + this.sidePanelBar.selectPanel("css"); + } + }, + + destroy: function() + { + selectedElement = null + fbPanel1 = null; + + selectedSidePanelTS = null; + selectedSidePanelTimer = null; + + Firebug.Panel.destroy.apply(this, arguments); + }, + + createUI: function() + { + var rootNode = Firebug.browser.document.documentElement; + var html = []; + Firebug.HTML.appendTreeNode(rootNode, html); + + this.panelNode.innerHTML = html.join(""); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + addEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = $("fbPanel1"); + + if(!selectedElement) + { + Firebug.HTML.selectTreeNode(ElementCache(Firebug.browser.document.body)); + } + + // TODO: xxxpedro + addEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + addEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + addEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + }, + + shutdown: function() + { + // TODO: xxxpedro + removeEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + removeEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + removeEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + + removeEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = null; + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + reattach: function() + { + // TODO: panel reattach + if(FirebugChrome.selectedHTMLElementId) + Firebug.HTML.selectTreeNode(FirebugChrome.selectedHTMLElementId); + }, + + updateSelection: function(object) + { + var id = ElementCache(object); + + if (id) + { + Firebug.HTML.selectTreeNode(id); + } + } +}); + +Firebug.registerPanel(HTMLPanel); + +// ************************************************************************************************ + +var formatStyles = function(styles) +{ + return isIE ? + // IE return CSS property names in upper case, so we need to convert them + styles.replace(/([^\s]+)\s*:/g, function(m,g){return g.toLowerCase()+":"}) : + // other browsers are just fine + styles; +}; + +// ************************************************************************************************ + +var selectedElement = null +var fbPanel1 = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +var selectedSidePanelTS, selectedSidePanelTimer; + +var selectElement= function selectElement(e) +{ + if (e != selectedElement) + { + if (selectedElement) + selectedElement.className = "objectBox-element"; + + e.className = e.className + " selectedElement"; + + if (FBL.isFirefox) + e.style.MozBorderRadius = "2px"; + + else if (FBL.isSafari) + e.style.WebkitBorderRadius = "2px"; + + selectedElement = e; + + FirebugChrome.selectedHTMLElementId = e.id; + + var target = ElementCache.get(e.id); + var selectedSidePanel = Firebug.chrome.getPanel("HTML").sidePanelBar.selectedPanel; + + var stack = FirebugChrome.htmlSelectionStack; + + stack.unshift(target); + + if (stack.length > 2) + stack.pop(); + + var lazySelect = function() + { + selectedSidePanelTS = new Date().getTime(); + + selectedSidePanel.select(target, true); + }; + + if (selectedSidePanelTimer) + { + clearTimeout(selectedSidePanelTimer); + selectedSidePanelTimer = null; + } + + if (new Date().getTime() - selectedSidePanelTS > 100) + setTimeout(lazySelect, 0) + else + selectedSidePanelTimer = setTimeout(lazySelect, 150); + } +} + + +// ************************************************************************************************ +// *** TODO: REFACTOR ************************************************************************** +// ************************************************************************************************ +Firebug.HTML.onTreeClick = function (e) +{ + e = e || event; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + + if (targ.className.indexOf('nodeControl') != -1 || targ.className == 'nodeTag') + { + var isIE = false; + + if(targ.className == 'nodeTag') + { + var control = isIE ? (targ.parentNode.previousSibling || targ) : + (targ.parentNode.previousSibling || targ); + + selectElement(targ.parentNode.parentNode); + + if (control.className.indexOf('nodeControl') == -1) + return; + + } else + control = targ; + + FBL.cancelEvent(e); + + var treeNode = isIE ? control.nextSibling : control.parentNode; + + //FBL.Firebug.Console.log(treeNode); + + if (control.className.indexOf(' nodeMaximized') != -1) { + FBL.Firebug.HTML.removeTreeChildren(treeNode); + } else { + FBL.Firebug.HTML.appendTreeChildren(treeNode); + } + } + else if (targ.className == 'nodeValue' || targ.className == 'nodeName') + { + /* + var input = FBL.Firebug.chrome.document.getElementById('treeInput'); + + input.style.display = "block"; + input.style.left = targ.offsetLeft + 'px'; + input.style.top = FBL.topHeight + targ.offsetTop - FBL.fbPanel1.scrollTop + 'px'; + input.style.width = targ.offsetWidth + 6 + 'px'; + input.value = targ.textContent || targ.innerText; + input.focus(); + /**/ + } +} + +function onListMouseOut(e) +{ + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + if (hasClass(targ, "fbPanel")) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + } +}; + +var hoverElement = null; +var hoverElementTS = 0; + +Firebug.HTML.onListMouseMove = function onListMouseMove(e) +{ + try + { + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + var found = false; + while (targ && !found) { + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) + targ = targ.parentNode; + else + found = true; + } + + if (!targ) + { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + /* + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + /**/ + + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + + var el = ElementCache.get(uid.value); + + var nodeName = el.nodeName.toLowerCase(); + + if (FBL.isIE && " meta title script link ".indexOf(" "+nodeName+" ") != -1) + return; + + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) return; + + if (el.id == "FirebugUI" || " html head body br script link iframe ".indexOf(" "+nodeName+" ") != -1) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + if ((new Date().getTime() - hoverElementTS > 40) && hoverElement != el) { + hoverElementTS = new Date().getTime(); + hoverElement = el; + FBL.Firebug.Inspector.drawBoxModel(el); + } + } + catch(E) + { + } +} + + +// ************************************************************************************************ + +Firebug.Reps = { + + appendText: function(object, html) + { + html.push(escapeHTML(objectToString(object))); + }, + + appendNull: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendString: function(object, html) + { + html.push('"', escapeHTML(objectToString(object)), + '"'); + }, + + appendInteger: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFloat: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFunction: function(object, html) + { + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m && m[1] ? m[1] : "function"; + html.push('', escapeHTML(name), '()'); + }, + + appendObject: function(object, html) + { + /* + var rep = Firebug.getRep(object); + var outputs = []; + + rep.tag.tag.compile(); + + var str = rep.tag.renderHTML({object: object}, outputs); + html.push(str); + /**/ + + try + { + if (object == undefined) + this.appendNull("undefined", html); + else if (object == null) + this.appendNull("null", html); + else if (typeof object == "string") + this.appendString(object, html); + else if (typeof object == "number") + this.appendInteger(object, html); + else if (typeof object == "boolean") + this.appendInteger(object, html); + else if (typeof object == "function") + this.appendFunction(object, html); + else if (object.nodeType == 1) + this.appendSelector(object, html); + else if (typeof object == "object") + { + if (typeof object.length != "undefined") + this.appendArray(object, html); + else + this.appendObjectFormatted(object, html); + } + else + this.appendText(object, html); + } + catch (exc) + { + } + /**/ + }, + + appendObjectFormatted: function(object, html) + { + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push('', m ? m[1] : text, '') + }, + + appendSelector: function(object, html) + { + var uid = ElementCache(object); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push(''); + + html.push('', escapeHTML(object.nodeName.toLowerCase()), ''); + if (object.id) + html.push('#', escapeHTML(object.id), ''); + if (object.className) + html.push('.', escapeHTML(object.className), ''); + + html.push(''); + }, + + appendNode: function(node, html) + { + if (node.nodeType == 1) + { + var uid = ElementCache(node); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push( + '
      ', + '', + '<', node.nodeName.toLowerCase(), ''); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || attr.nodeName == cacheID) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? node.style.cssText : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + if (node.firstChild) + { + html.push('>
      '); + + for (var child = node.firstChild; child; child = child.nextSibling) + this.appendNode(child, html); + + html.push('
      </', + node.nodeName.toLowerCase(), '>
      '); + } + else + html.push('/>'); + } + else if (node.nodeType == 3) + { + var value = trim(node.nodeValue); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + }, + + appendArray: function(object, html) + { + html.push('[ '); + + for (var i = 0, l = object.length, obj; i < l; ++i) + { + this.appendObject(object[i], html); + + if (i < l-1) + html.push(', '); + } + + html.push(' ]'); + } + +}; + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +/* + +Hack: +Firebug.chrome.currentPanel = Firebug.chrome.selectedPanel; +Firebug.showInfoTips = true; +Firebug.InfoTip.initializeBrowser(Firebug.chrome); + +/**/ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var maxWidth = 100, maxHeight = 80; +var infoTipMargin = 10; +var infoTipWindowPadding = 25; + +// ************************************************************************************************ + +Firebug.InfoTip = extend(Firebug.Module, +{ + dispatchName: "infoTip", + tags: domplate( + { + infoTipTag: DIV({"class": "infoTip"}), + + colorTag: + DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, " "), + + imgTag: + DIV({"class": "infoTipImageBox infoTipLoading"}, + IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat", + onload: "$onLoadImage"}), + IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}), + DIV({"class": "infoTipCaption"}) + ), + + onLoadImage: function(event) + { + var img = event.currentTarget || event.srcElement; + ///var bgImg = img.nextSibling; + ///if (!bgImg) + /// return; // Sometimes gets called after element is dead + + ///var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + /// TODO: xxxpedro infoTip hack + var caption = getElementByClass(innerBox, "infoTipCaption"); + var bgImg = getElementByClass(innerBox, "infoTipBgImage"); + if (!bgImg) + return; // Sometimes gets called after element is dead + + // TODO: xxxpedro infoTip IE and timing issue + // TODO: use offline document to avoid flickering + if (isIE) + removeClass(innerBox, "infoTipLoading"); + + var updateInfoTip = function(){ + + var w = img.naturalWidth || img.width || 10, + h = img.naturalHeight || img.height || 10; + + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + //caption.innerHTML = $STRF("Dimensions", [w, h]); + caption.innerHTML = $STRF(w + " x " + h); + + + }; + + if (isIE) + setTimeout(updateInfoTip, 0); + else + { + updateInfoTip(); + removeClass(innerBox, "infoTipLoading"); + } + + /// + } + + /* + /// onLoadImage original + onLoadImage: function(event) + { + var img = event.currentTarget; + var bgImg = img.nextSibling; + if (!bgImg) + return; // Sometimes gets called after element is dead + + var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + var w = img.naturalWidth, h = img.naturalHeight; + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + caption.innerHTML = $STRF("Dimensions", [w, h]); + + removeClass(innerBox, "infoTipLoading"); + } + /**/ + + }), + + initializeBrowser: function(browser) + { + browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser); + browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser); + + ///var doc = browser.contentDocument; + var doc = browser.document; + if (!doc) + return; + + ///doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true); + addEvent(doc, "mouseover", browser.onInfoTipMouseMove); + addEvent(doc, "mouseout", browser.onInfoTipMouseOut); + addEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc)); + }, + + uninitializeBrowser: function(browser) + { + if (browser.infoTip) + { + ///var doc = browser.contentDocument; + var doc = browser.document; + ///doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true); + removeEvent(doc, "mouseover", browser.onInfoTipMouseMove); + removeEvent(doc, "mouseout", browser.onInfoTipMouseOut); + removeEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + browser.infoTip.parentNode.removeChild(browser.infoTip); + delete browser.infoTip; + delete browser.onInfoTipMouseMove; + } + }, + + showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset) + { + if (!Firebug.showInfoTips) + return; + + var scrollParent = getOverflowParent(target); + var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0); + + if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset)) + { + var htmlElt = infoTip.ownerDocument.documentElement; + var panelWidth = htmlElt.clientWidth; + var panelHeight = htmlElt.clientHeight; + + if (x+infoTip.offsetWidth+infoTipMargin > panelWidth) + { + infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px"; + infoTip.style.right = "auto"; + } + else + { + infoTip.style.left = (x+infoTipMargin) + "px"; + infoTip.style.right = "auto"; + } + + if (y+infoTip.offsetHeight+infoTipMargin > panelHeight) + { + infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px"; + infoTip.style.bottom = "auto"; + } + else + { + infoTip.style.top = (y+infoTipMargin) + "px"; + infoTip.style.bottom = "auto"; + } + + if (FBTrace.DBG_INFOTIP) + FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top + + ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom + + ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight + + ", offsetWidth: " + infoTip.offsetWidth + + ", x: " + x + ", panelWidth: " + panelWidth + + ", y: " + y + ", panelHeight: " + panelHeight); + + infoTip.setAttribute("active", "true"); + } + else + this.hideInfoTip(infoTip); + }, + + hideInfoTip: function(infoTip) + { + if (infoTip) + infoTip.removeAttribute("active"); + }, + + onMouseOut: function(event, browser) + { + if (!event.relatedTarget) + this.hideInfoTip(browser.infoTip); + }, + + onMouseMove: function(event, browser) + { + // Ignore if the mouse is moving over the existing info tip. + if (getAncestorByClass(event.target, "infoTip")) + return; + + if (browser.currentPanel) + { + var x = event.clientX, y = event.clientY, target = event.target || event.srcElement; + this.showInfoTip(browser.infoTip, browser.currentPanel, target, x, y, event.rangeParent, event.rangeOffset); + } + else + this.hideInfoTip(browser.infoTip); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + populateColorInfoTip: function(infoTip, color) + { + this.tags.colorTag.replace({rgbValue: color}, infoTip); + return true; + }, + + populateImageInfoTip: function(infoTip, url, repeat) + { + if (!repeat) + repeat = "no-repeat"; + + this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip); + + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + disable: function() + { + // XXXjoe For each browser, call uninitializeBrowser + }, + + showPanel: function(browser, panel) + { + if (panel) + { + var infoTip = panel.panelBrowser.infoTip; + if (!infoTip) + infoTip = this.initializeBrowser(panel.panelBrowser); + this.hideInfoTip(infoTip); + } + + }, + + showSidePanel: function(browser, panel) + { + this.showPanel(browser, panel); + } +}); + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.InfoTip); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +// move to FBL +(function() { + +// ************************************************************************************************ +// XPath + +/** + * Gets an XPath for an element which describes its hierarchical location. + */ +this.getElementXPath = function(element) +{ + if (element && element.id) + return '//*[@id="' + element.id + '"]'; + else + return this.getElementTreeXPath(element); +}; + +this.getElementTreeXPath = function(element) +{ + var paths = []; + + for (; element && element.nodeType == 1; element = element.parentNode) + { + var index = 0; + for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) + { + if (sibling.nodeName == element.nodeName) + ++index; + } + + var tagName = element.nodeName.toLowerCase(); + var pathIndex = (index ? "[" + (index+1) + "]" : ""); + paths.splice(0, 0, tagName + pathIndex); + } + + return paths.length ? "/" + paths.join("/") : null; +}; + +this.getElementsByXPath = function(doc, xpath) +{ + var nodes = []; + + try { + var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + for (var item = result.iterateNext(); item; item = result.iterateNext()) + nodes.push(item); + } + catch (exc) + { + // Invalid xpath expressions make their way here sometimes. If that happens, + // we still want to return an empty set without an exception. + } + + return nodes; +}; + +this.getRuleMatchingElements = function(rule, doc) +{ + var css = rule.selectorText; + var xpath = this.cssToXPath(css); + return this.getElementsByXPath(doc, xpath); +}; + + +}).call(FBL); + + + + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + +var toCamelCase = function toCamelCase(s) +{ + return s.replace(reSelectorCase, toCamelCaseReplaceFn); +}; + +var toSelectorCase = function toSelectorCase(s) +{ + return s.replace(reCamelCase, "-$1").toLowerCase(); + +}; + +var reCamelCase = /([A-Z])/g; +var reSelectorCase = /\-(.)/g; +var toCamelCaseReplaceFn = function toCamelCaseReplaceFn(m,g) +{ + return g.toUpperCase(); +}; + + + + + +// ************************************************************************************************ + +var ElementCache = Firebug.Lite.Cache.Element; +var StyleSheetCache = Firebug.Lite.Cache.StyleSheet; + +var globalCSSRuleIndex; + +var externalStyleSheetURLs = []; +var externalStyleSheetWarning = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "warning focusRow", style: "font-weight:normal;", role: 'listitem'}, + SPAN("$object|STR"), + A({"href": "$href", target:"_blank"}, "$link|STR") + ) +}); + + +var processAllStyleSheetsTimeout = null; +var loadExternalStylesheet = function(doc, styleSheetIterator, styleSheet) +{ + var url = styleSheet.href; + styleSheet.firebugIgnore = true; + + var source = Firebug.Lite.Proxy.load(url); + + // TODO: check for null and error responses + + + // remove comments + //var reMultiComment = /(\/\*([^\*]|\*(?!\/))*\*\/)/g; + //source = source.replace(reMultiComment, ""); + + // convert relative addresses to absolute ones + source = source.replace(/url\(([^\)]+)\)/g, function(a,name){ + + var hasDomain = /\w+:\/\/./.test(name); + + if (!hasDomain) + { + name = name.replace(/^(["'])(.+)\1$/, "$2"); + var first = name.charAt(0); + + // relative path, based on root + if (first == "/") + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLRoot + var m = /^([^:]+:\/{1,3}[^\/]+)/.exec(url); + + return m ? + "url(" + m[1] + name + ")" : + "url(" + name + ")"; + } + // relative path, based on current location + else + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLPath + var path = url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g, ""); + + path = path + name; + + var reBack = /[^\/]+\/\.\.\//; + while(reBack.test(path)) + { + path = path.replace(reBack, ""); + } + + //console.log("url(" + path + ")"); + + return "url(" + path + ")"; + } + } + + // if it is an absolute path, there is nothing to do + return a; + }); + + var oldStyle = styleSheet.ownerNode; + + if (!oldStyle) return; + + if (!oldStyle.parentNode) return; + + var style = createGlobalElement("style"); + style.setAttribute("charset","utf-8"); + style.setAttribute("type", "text/css"); + style.innerHTML = source; + + //debugger; + oldStyle.parentNode.insertBefore(style, oldStyle.nextSibling); + oldStyle.parentNode.removeChild(oldStyle); + + + //doc.getElementsByTagName("head")[0].appendChild(style); + + doc.styleSheets[doc.styleSheets.length-1].externalURL = url; + + console.log(url, "call " + externalStyleSheetURLs.length, source); + + externalStyleSheetURLs.pop(); + + if (processAllStyleSheetsTimeout) + { + clearTimeout(processAllStyleSheetsTimeout); + } + + processAllStyleSheetsTimeout = setTimeout(function(){ + console.log("processing"); + FBL.processAllStyleSheets(doc, styleSheetIterator); + processAllStyleSheetsTimeout = null; + },200); + +}; + + +FBL.processAllStyleSheets = function(doc, styleSheetIterator) +{ + styleSheetIterator = styleSheetIterator || processStyleSheet; + + globalCSSRuleIndex = -1; + + var styleSheets = doc.styleSheets; + var importedStyleSheets = []; + + if (FBTrace.DBG_CSS) + var start = new Date().getTime(); + + for(var i=0, length=styleSheets.length; i maxSpecificity) + { + maxSpecificity = spec; + mostSpecificSelector = sel; + } + } + } + + rule.specificity = maxSpecificity; + } + } + + rules.sort(sortElementRules); + //rules.sort(solveRulesTied); + + return rules; +}; + +var sortElementRules = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + var specificityA = ruleA.specificity; + var specificityB = ruleB.specificity; + + if (specificityA > specificityB) + return 1; + + else if (specificityA < specificityB) + return -1; + + else + return ruleA.order > ruleB.order ? 1 : -1; +}; + +var solveRulesTied = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + if (ruleA.specificity == ruleB.specificity) + return ruleA.order > ruleB.order ? 1 : -1; + + return null; +}; + +var reSelectorTag = /(^|\s)(?:\w+)/g; +var reSelectorClass = /\.[\w\d_-]+/g; +var reSelectorId = /#[\w\d_-]+/g; + +var getCSSRuleSpecificity = function(selector) +{ + var match = selector.match(reSelectorTag); + var tagCount = match ? match.length : 0; + + match = selector.match(reSelectorClass); + var classCount = match ? match.length : 0; + + match = selector.match(reSelectorId); + var idCount = match ? match.length : 0; + + return tagCount + 10*classCount + 100*idCount; +}; + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; +//const nsIDOMCSSStyleRule = Ci.nsIDOMCSSStyleRule; +//const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor; +//const nsISelectionDisplay = Ci.nsISelectionDisplay; +//const nsISelectionController = Ci.nsISelectionController; + +// See: http://mxr.mozilla.org/mozilla1.9.2/source/content/events/public/nsIEventStateManager.h#153 +//const STATE_ACTIVE = 0x01; +//const STATE_FOCUS = 0x02; +//const STATE_HOVER = 0x04; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +Firebug.SourceBoxPanel = Firebug.Panel; + +var domUtils = null; + +var textContent = isIE ? "innerText" : "textContent"; +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var CSSDomplateBase = { + isEditable: function(rule) + { + return !rule.isSystemSheet; + }, + isSelectorEditable: function(rule) + { + return rule.isSelectorEditable && this.isEditable(rule); + } +}; + +var CSSPropTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssProp focusRow", $disabledStyle: "$prop.disabled", + $editGroup: "$rule|isEditable", + $cssOverridden: "$prop.overridden", role : "option"}, + A({"class": "cssPropDisable"}, "  "), + SPAN({"class": "cssPropName", $editable: "$rule|isEditable"}, "$prop.name"), + SPAN({"class": "cssColon"}, ":"), + SPAN({"class": "cssPropValue", $editable: "$rule|isEditable"}, "$prop.value$prop.important"), + SPAN({"class": "cssSemi"}, ";") + ) +}); + +var CSSRuleTag = + TAG("$rule.tag", {rule: "$rule"}); + +var CSSImportRuleTag = domplate({ + tag: DIV({"class": "cssRule insertInto focusRow importRule", _repObject: "$rule.rule"}, + "@import "", + A({"class": "objectLink", _repObject: "$rule.rule.styleSheet"}, "$rule.rule.href"), + "";" + ) +}); + +var CSSStyleRuleTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssRule insertInto", + $cssEditableRule: "$rule|isEditable", + $editGroup: "$rule|isSelectorEditable", + _repObject: "$rule.rule", + "ruleId": "$rule.id", role : 'presentation'}, + DIV({"class": "cssHead focusRow", role : 'listitem'}, + SPAN({"class": "cssSelector", $editable: "$rule|isSelectorEditable"}, "$rule.selector"), " {" + ), + DIV({role : 'group'}, + DIV({"class": "cssPropertyListBox", role : 'listbox'}, + FOR("prop", "$rule.props", + TAG(CSSPropTag.tag, {rule: "$rule", prop: "$prop"}) + ) + ) + ), + DIV({"class": "editable insertBefore", role:"presentation"}, "}") + ) +}); + +var reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/; + +var reURL = /url\("?([^"\)]+)?"?\)/; + +var reRepeat = /no-repeat|repeat-x|repeat-y|repeat/; + +//const sothinkInstalled = !!$("swfcatcherKey_sidebar"); +var sothinkInstalled = false; +var styleGroups = +{ + text: [ + "font-family", + "font-size", + "font-weight", + "font-style", + "color", + "text-transform", + "text-decoration", + "letter-spacing", + "word-spacing", + "line-height", + "text-align", + "vertical-align", + "direction", + "column-count", + "column-gap", + "column-width" + ], + + background: [ + "background-color", + "background-image", + "background-repeat", + "background-position", + "background-attachment", + "opacity" + ], + + box: [ + "width", + "height", + "top", + "right", + "bottom", + "left", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + "-moz-border-top-radius", + "-moz-border-right-radius", + "-moz-border-bottom-radius", + "-moz-border-left-radius", + "outline-top-width", + "outline-right-width", + "outline-bottom-width", + "outline-left-width", + "outline-top-color", + "outline-right-color", + "outline-bottom-color", + "outline-left-color", + "outline-top-style", + "outline-right-style", + "outline-bottom-style", + "outline-left-style" + ], + + layout: [ + "position", + "display", + "visibility", + "z-index", + "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow + "overflow-y", + "overflow-clip", + "white-space", + "clip", + "float", + "clear", + "-moz-box-sizing" + ], + + other: [ + "cursor", + "list-style-image", + "list-style-position", + "list-style-type", + "marker-offset", + "user-focus", + "user-select", + "user-modify", + "user-input" + ] +}; + +var styleGroupTitles = +{ + text: "Text", + background: "Background", + box: "Box Model", + layout: "Layout", + other: "Other" +}; + +Firebug.CSSModule = extend(Firebug.Module, +{ + freeEdit: function(styleSheet, value) + { + if (!styleSheet.editStyleSheet) + { + var ownerNode = getStyleSheetOwnerNode(styleSheet); + styleSheet.disabled = true; + + var url = CCSV("@mozilla.org/network/standard-url;1", Components.interfaces.nsIURL); + url.spec = styleSheet.href; + + var editStyleSheet = ownerNode.ownerDocument.createElementNS( + "http://www.w3.org/1999/xhtml", + "style"); + unwrapObject(editStyleSheet).firebugIgnore = true; + editStyleSheet.setAttribute("type", "text/css"); + editStyleSheet.setAttributeNS( + "http://www.w3.org/XML/1998/namespace", + "base", + url.directory); + if (ownerNode.hasAttribute("media")) + { + editStyleSheet.setAttribute("media", ownerNode.getAttribute("media")); + } + + // Insert the edited stylesheet directly after the old one to ensure the styles + // cascade properly. + ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling); + + styleSheet.editStyleSheet = editStyleSheet; + } + + styleSheet.editStyleSheet.innerHTML = value; + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n"); + + dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]); + }, + + insertRule: function(styleSheet, cssText, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("Insert: " + ruleIndex + " " + cssText); + var insertIndex = styleSheet.insertRule(cssText, ruleIndex); + + dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]); + + return insertIndex; + }, + + deleteRule: function(styleSheet, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("deleteRule: " + ruleIndex + " " + styleSheet.cssRules.length, styleSheet.cssRules); + dispatch(this.fbListeners, "onCSSDeleteRule", [styleSheet, ruleIndex]); + + styleSheet.deleteRule(ruleIndex); + }, + + setProperty: function(rule, propName, propValue, propPriority) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + // good browsers + if (style.getPropertyValue) + { + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect + // unless we remove the property first + style.removeProperty(propName); + + style.setProperty(propName, propValue, propPriority); + } + // sad browsers + else + { + // TODO: xxxpedro parse CSS rule to find property priority in IE? + //console.log(propName, propValue); + style[toCamelCase(propName)] = propValue; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue, propPriority, prevValue, prevPriority, rule, baseText]); + } + }, + + removeProperty: function(rule, propName, parent) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + if (style.getPropertyValue) + { + + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + style.removeProperty(propName); + } + else + { + style[toCamelCase(propName)] = ""; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue, prevPriority, rule, baseText]); + } + }/*, + + cleanupSheets: function(doc, context) + { + // Due to the manner in which the layout engine handles multiple + // references to the same sheet we need to kick it a little bit. + // The injecting a simple stylesheet then removing it will force + // Firefox to regenerate it's CSS hierarchy. + // + // WARN: This behavior was determined anecdotally. + // See http://code.google.com/p/fbug/issues/detail?id=2440 + var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + style.setAttribute("charset","utf-8"); + unwrapObject(style).firebugIgnore = true; + style.setAttribute("type", "text/css"); + style.innerHTML = "#fbIgnoreStyleDO_NOT_USE {}"; + addStyleSheet(doc, style); + style.parentNode.removeChild(style); + + // https://bugzilla.mozilla.org/show_bug.cgi?id=500365 + // This voodoo touches each style sheet to force some Firefox internal change to allow edits. + var styleSheets = getAllStyleSheets(context); + for(var i = 0; i < styleSheets.length; i++) + { + try + { + var rules = styleSheets[i].cssRules; + if (rules.length > 0) + var touch = rules[0]; + if (FBTrace.DBG_CSS && touch) + FBTrace.sysout("css.show() touch "+typeof(touch)+" in "+(styleSheets[i].href?styleSheets[i].href:context.getName())); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.show: sheet.cssRules FAILS for "+(styleSheets[i]?styleSheets[i].href:"null sheet")+e, e); + } + } + }, + cleanupSheetHandler: function(event, context) + { + var target = event.target || event.srcElement, + tagName = (target.tagName || "").toLowerCase(); + if (tagName == "link") + { + this.cleanupSheets(target.ownerDocument, context); + } + }, + watchWindow: function(context, win) + { + var cleanupSheets = bind(this.cleanupSheets, this), + cleanupSheetHandler = bind(this.cleanupSheetHandler, this, context), + doc = win.document; + + //doc.addEventListener("DOMAttrModified", cleanupSheetHandler, false); + //doc.addEventListener("DOMNodeInserted", cleanupSheetHandler, false); + }, + loadedContext: function(context) + { + var self = this; + iterateWindows(context.browser.contentWindow, function(subwin) + { + self.cleanupSheets(subwin.document, context); + }); + } + /**/ +}); + +// ************************************************************************************************ + +Firebug.CSSStyleSheetPanel = function() {}; + +Firebug.CSSStyleSheetPanel.prototype = extend(Firebug.SourceBoxPanel, +{ + template: domplate( + { + tag: + DIV({"class": "cssSheet insertInto a11yCSSView"}, + FOR("rule", "$rules", + CSSRuleTag + ), + DIV({"class": "cssSheet editable insertBefore"}, "") + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + refresh: function() + { + if (this.location) + this.updateLocation(this.location); + else if (this.selection) + this.updateSelection(this.selection); + }, + + toggleEditing: function() + { + if (!this.stylesheetEditor) + this.stylesheetEditor = new StyleSheetEditor(this.document); + + if (this.editing) + Firebug.Editor.stopEditing(); + else + { + if (!this.location) + return; + + var styleSheet = this.location.editStyleSheet + ? this.location.editStyleSheet.sheet + : this.location; + + var css = getStyleSheetCSS(styleSheet, this.context); + //var topmost = getTopmostRuleLine(this.panelNode); + + this.stylesheetEditor.styleSheet = this.location; + Firebug.Editor.startEditing(this.panelNode, css, this.stylesheetEditor); + //this.stylesheetEditor.scrollToLine(topmost.line, topmost.offset); + } + }, + + getStylesheetURL: function(rule) + { + if (this.location.href) + return this.location.href; + else + return this.context.window.location.href; + }, + + getRuleByLine: function(styleSheet, line) + { + if (!domUtils) + return null; + + var cssRules = styleSheet.cssRules; + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + if (rule instanceof CSSStyleRule) + { + var ruleLine = domUtils.getRuleLine(rule); + if (ruleLine >= line) + return rule; + } + } + }, + + highlightRule: function(rule) + { + var ruleElement = Firebug.getElementByRepObject(this.panelNode.firstChild, rule); + if (ruleElement) + { + scrollIntoCenterView(ruleElement, this.panelNode); + setClassTimed(ruleElement, "jumpHighlight", this.context); + } + }, + + getStyleSheetRules: function(context, styleSheet) + { + var isSystemSheet = isSystemStyleSheet(styleSheet); + + function appendRules(cssRules) + { + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + + // TODO: xxxpedro opera instanceof stylesheet remove the following comments when + // the issue with opera and style sheet Classes has been solved. + + //if (rule instanceof CSSStyleRule) + if (instanceOf(rule, "CSSStyleRule")) + { + var props = this.getRuleProperties(context, rule); + //var line = domUtils.getRuleLine(rule); + var line = null; + + var selector = rule.selectorText; + + if (isIE) + { + selector = selector.replace(reSelectorTag, + function(s){return s.toLowerCase();}); + } + + var ruleId = rule.selectorText+"/"+line; + rules.push({tag: CSSStyleRuleTag.tag, rule: rule, id: ruleId, + selector: selector, props: props, + isSystemSheet: isSystemSheet, + isSelectorEditable: true}); + } + //else if (rule instanceof CSSImportRule) + else if (instanceOf(rule, "CSSImportRule")) + rules.push({tag: CSSImportRuleTag.tag, rule: rule}); + //else if (rule instanceof CSSMediaRule) + else if (instanceOf(rule, "CSSMediaRule")) + appendRules.apply(this, [rule.cssRules]); + else + { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_CSS) + FBTrace.sysout("css getStyleSheetRules failed to classify a rule ", rule); + } + } + } + + var rules = []; + appendRules.apply(this, [styleSheet.cssRules || styleSheet.rules]); + return rules; + }, + + parseCSSProps: function(style, inheritMode) + { + var props = []; + + if (Firebug.expandShorthandProps) + { + var count = style.length-1, + index = style.length; + while (index--) + { + var propName = style.item(count - index); + this.addProperty(propName, style.getPropertyValue(propName), !!style.getPropertyPriority(propName), false, inheritMode, props); + } + } + else + { + var lines = style.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g); + var propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/; + var line,i=0; + // TODO: xxxpedro port to firebug: variable leaked into global namespace + var m; + + while(line=lines[i++]){ + m = propRE.exec(line); + if(!m) + continue; + //var name = m[1], value = m[2], important = !!m[3]; + if (m[2]) + this.addProperty(m[1], m[2], !!m[3], false, inheritMode, props); + }; + } + + return props; + }, + + getRuleProperties: function(context, rule, inheritMode) + { + var props = this.parseCSSProps(rule.style, inheritMode); + + // TODO: xxxpedro port to firebug: variable leaked into global namespace + //var line = domUtils.getRuleLine(rule); + var line; + var ruleId = rule.selectorText+"/"+line; + this.addOldProperties(context, ruleId, inheritMode, props); + sortProperties(props); + + return props; + }, + + addOldProperties: function(context, ruleId, inheritMode, props) + { + if (context.selectorMap && context.selectorMap.hasOwnProperty(ruleId) ) + { + var moreProps = context.selectorMap[ruleId]; + for (var i = 0; i < moreProps.length; ++i) + { + var prop = moreProps[i]; + this.addProperty(prop.name, prop.value, prop.important, true, inheritMode, props); + } + } + }, + + addProperty: function(name, value, important, disabled, inheritMode, props) + { + name = name.toLowerCase(); + + if (inheritMode && !inheritedStyleNames[name]) + return; + + name = this.translateName(name, value); + if (name) + { + value = stripUnits(rgbToHex(value)); + important = important ? " !important" : ""; + + var prop = {name: name, value: value, important: important, disabled: disabled}; + props.push(prop); + } + }, + + translateName: function(name, value) + { + // Don't show these proprietary Mozilla properties + if ((value == "-moz-initial" + && (name == "-moz-background-clip" || name == "-moz-background-origin" + || name == "-moz-background-inline-policy")) + || (value == "physical" + && (name == "margin-left-ltr-source" || name == "margin-left-rtl-source" + || name == "margin-right-ltr-source" || name == "margin-right-rtl-source")) + || (value == "physical" + && (name == "padding-left-ltr-source" || name == "padding-left-rtl-source" + || name == "padding-right-ltr-source" || name == "padding-right-rtl-source"))) + return null; + + // Translate these back to the form the user probably expects + if (name == "margin-left-value") + return "margin-left"; + else if (name == "margin-right-value") + return "margin-right"; + else if (name == "margin-top-value") + return "margin-top"; + else if (name == "margin-bottom-value") + return "margin-bottom"; + else if (name == "padding-left-value") + return "padding-left"; + else if (name == "padding-right-value") + return "padding-right"; + else if (name == "padding-top-value") + return "padding-top"; + else if (name == "padding-bottom-value") + return "padding-bottom"; + // XXXjoe What about border! + else + return name; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + editElementStyle: function() + { + ///var rulesBox = this.panelNode.getElementsByClassName("cssElementRuleContainer")[0]; + var rulesBox = $$(".cssElementRuleContainer", this.panelNode)[0]; + var styleRuleBox = rulesBox && Firebug.getElementByRepObject(rulesBox, this.selection); + if (!styleRuleBox) + { + var rule = {rule: this.selection, inherited: false, selector: "element.style", props: []}; + if (!rulesBox) + { + // The element did not have any displayed styles. We need to create the whole tree and remove + // the no styles message + styleRuleBox = this.template.cascadedTag.replace({ + rules: [rule], inherited: [], inheritLabel: "Inherited from" // $STR("InheritedFrom") + }, this.panelNode); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("cssElementRuleContainer")[0]; + styleRuleBox = $$(".cssElementRuleContainer", styleRuleBox)[0]; + } + else + styleRuleBox = this.template.ruleTag.insertBefore({rule: rule}, rulesBox); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("insertInto")[0]; + styleRuleBox = $$(".insertInto", styleRuleBox)[0]; + } + + Firebug.Editor.insertRowForObject(styleRuleBox); + }, + + insertPropertyRow: function(row) + { + Firebug.Editor.insertRowForObject(row); + }, + + insertRule: function(row) + { + var location = getAncestorByClass(row, "cssRule"); + if (!location) + { + location = getChildByClass(this.panelNode, "cssSheet"); + Firebug.Editor.insertRowForObject(location); + } + else + { + Firebug.Editor.insertRow(location, "before"); + } + }, + + editPropertyRow: function(row) + { + var propValueBox = getChildByClass(row, "cssPropValue"); + Firebug.Editor.startEditing(propValueBox); + }, + + deletePropertyRow: function(row) + { + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + Firebug.CSSModule.removeProperty(rule, propName); + + // Remove the property from the selector map, if it was disabled + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if ( this.context.selectorMap && this.context.selectorMap.hasOwnProperty(ruleId) ) + { + var map = this.context.selectorMap[ruleId]; + for (var i = 0; i < map.length; ++i) + { + if (map[i].name == propName) + { + map.splice(i, 1); + break; + } + } + } + if (this.name == "stylesheet") + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [this, row.firstChild, true]); + row.parentNode.removeChild(row); + + this.markChange(this.name == "stylesheet"); + }, + + disablePropertyRow: function(row) + { + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + + if (!this.context.selectorMap) + this.context.selectorMap = {}; + + // XXXjoe Generate unique key for elements too + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if (!(this.context.selectorMap.hasOwnProperty(ruleId))) + this.context.selectorMap[ruleId] = []; + + var map = this.context.selectorMap[ruleId]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + if (hasClass(row, "disabledStyle")) + { + Firebug.CSSModule.removeProperty(rule, propName); + + map.push({"name": propName, "value": parsedValue.value, + "important": parsedValue.priority}); + } + else + { + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + + var index = findPropByName(map, propName); + map.splice(index, 1); + } + + this.markChange(this.name == "stylesheet"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onMouseDown: function(event) + { + //console.log("onMouseDown", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + // XXjoe Hack to only allow clicking on the checkbox + if (!isLeftClick(event) || offset > 20) + return; + + var target = event.target || event.srcElement; + if (hasClass(target, "textEditor")) + return; + + var row = getAncestorByClass(target, "cssProp"); + if (row && hasClass(row, "editGroup")) + { + this.disablePropertyRow(row); + cancelEvent(event); + } + }, + + onDoubleClick: function(event) + { + //console.log("onDoubleClick", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + if (!isLeftClick(event) || offset <= 20) + return; + + var target = event.target || event.srcElement; + + //console.log("ok", target, hasClass(target, "textEditorInner"), !isLeftClick(event), offset <= 20); + + // if the inline editor was clicked, don't insert a new rule + if (hasClass(target, "textEditorInner")) + return; + + var row = getAncestorByClass(target, "cssRule"); + if (row && !getAncestorByClass(target, "cssPropName") + && !getAncestorByClass(target, "cssPropValue")) + { + this.insertPropertyRow(row); + cancelEvent(event); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "stylesheet", + title: "CSS", + parentPanel: null, + searchable: true, + dependents: ["css", "stylesheet", "dom", "domSide", "layout"], + + options: + { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onMouseDown = bind(this.onMouseDown, this); + this.onDoubleClick = bind(this.onDoubleClick, this); + + if (this.name == "stylesheet") + { + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var selectNode = this.selectNode = createElement("select"); + + processAllStyleSheets(doc, function(doc, styleSheet) + { + var key = StyleSheetCache.key(styleSheet); + var fileName = getFileName(styleSheet.href) || getFileName(doc.location.href); + var option = createElement("option", {value: key}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }); + + this.toolButtonsNode.appendChild(selectNode); + } + /**/ + }, + + onChangeSelect: function(event) + { + event = event || window.event; + var target = event.srcElement || event.currentTarget; + var key = target.value; + var styleSheet = StyleSheetCache.get(key); + + this.updateLocation(styleSheet); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + + //if (!domUtils) + //{ + // try { + // domUtils = CCSV("@mozilla.org/inspector/dom-utils;1", "inIDOMUtils"); + // } catch (exc) { + // if (FBTrace.DBG_ERRORS) + // FBTrace.sysout("@mozilla.org/inspector/dom-utils;1 FAILED to load: "+exc, exc); + // } + //} + + //TODO: xxxpedro + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + this.initializeNode(); + + if (this.name == "stylesheet") + { + var styleSheets = Firebug.browser.document.styleSheets; + + if (styleSheets.length > 0) + { + addEvent(this.selectNode, "change", this.onChangeSelect); + + this.updateLocation(styleSheets[0]); + } + } + + //Firebug.SourceBoxPanel.initialize.apply(this, arguments); + }, + + shutdown: function() + { + // must destroy the editor when we leave the panel to avoid problems (Issue 2981) + Firebug.Editor.stopEditing(); + + if (this.name == "stylesheet") + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + } + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + destroy: function(state) + { + //state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop; + + //persistObjects(this, state); + + // xxxpedro we are stopping the editor in the shutdown method already + //Firebug.Editor.stopEditing(); + Firebug.Panel.destroy.apply(this, arguments); + }, + + initializeNode: function(oldPanelNode) + { + addEvent(this.panelNode, "mousedown", this.onMouseDown); + addEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.initializeNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'css']); + }, + + destroyNode: function() + { + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + removeEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.destroyNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'css']); + }, + + ishow: function(state) + { + Firebug.Inspector.stopInspecting(true); + + this.showToolbarButtons("fbCSSButtons", true); + + if (this.context.loaded && !this.location) // wait for loadedContext to restore the panel + { + restoreObjects(this, state); + + if (!this.location) + this.location = this.getDefaultLocation(); + + if (state && state.scrollTop) + this.panelNode.scrollTop = state.scrollTop; + } + }, + + ihide: function() + { + this.showToolbarButtons("fbCSSButtons", false); + + this.lastScrollTop = this.panelNode.scrollTop; + }, + + supportsObject: function(object) + { + if (object instanceof CSSStyleSheet) + return 1; + else if (object instanceof CSSStyleRule) + return 2; + else if (object instanceof CSSStyleDeclaration) + return 2; + else if (object instanceof SourceLink && object.type == "css" && reCSS.test(object.href)) + return 2; + else + return 0; + }, + + updateLocation: function(styleSheet) + { + if (!styleSheet) + return; + if (styleSheet.editStyleSheet) + styleSheet = styleSheet.editStyleSheet.sheet; + + // if it is a restricted stylesheet, show the warning message and abort the update process + if (styleSheet.restricted) + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, this.panelNode); + + // TODO: xxxpedro remove when there the external resource problem is fixed + externalStyleSheetWarning.tag.append({ + object: "The stylesheet could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22" + }, this.panelNode); + + return; + } + + var rules = this.getStyleSheetRules(this.context, styleSheet); + + var result; + if (rules.length) + result = this.template.tag.replace({rules: rules}, this.panelNode); + else + result = FirebugReps.Warning.tag.replace({object: "EmptyStyleSheet"}, this.panelNode); + + // TODO: xxxpedro need to fix showToolbarButtons function + //this.showToolbarButtons("fbCSSButtons", !isSystemStyleSheet(this.location)); + + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, this.panelNode]); + }, + + updateSelection: function(object) + { + this.selection = null; + + if (object instanceof CSSStyleDeclaration) { + object = object.parentRule; + } + + if (object instanceof CSSStyleRule) + { + this.navigate(object.parentStyleSheet); + this.highlightRule(object); + } + else if (object instanceof CSSStyleSheet) + { + this.navigate(object); + } + else if (object instanceof SourceLink) + { + try + { + var sourceLink = object; + + var sourceFile = getSourceFileByHref(sourceLink.href, this.context); + if (sourceFile) + { + clearNode(this.panelNode); // replace rendered stylesheets + this.showSourceFile(sourceFile); + + var lineNo = object.line; + if (lineNo) + this.scrollToLine(lineNo, this.jumpHighlightFactory(lineNo, this.context)); + } + else // XXXjjb we should not be taking this path + { + var stylesheet = getStyleSheetByHref(sourceLink.href, this.context); + if (stylesheet) + this.navigate(stylesheet); + else + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href, sourceLink); + } + } + } + catch(exc) { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.upDateSelection FAILS "+exc, exc); + } + } + }, + + updateOption: function(name, value) + { + if (name == "expandShorthandProps") + this.refresh(); + }, + + getLocationList: function() + { + var styleSheets = getAllStyleSheets(this.context); + return styleSheets; + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") }, + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ]; + }, + + getContextMenuItems: function(style, target) + { + var items = []; + + if (this.infoTipType == "color") + { + items.push( + {label: "CopyColor", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) } + ); + } + else if (this.infoTipType == "image") + { + items.push( + {label: "CopyImageLocation", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) }, + {label: "OpenImageInNewTab", + command: bindFixed(openNewTab, FBL, this.infoTipObject) } + ); + } + + ///if (this.selection instanceof Element) + if (isElement(this.selection)) + { + items.push( + //"-", + {label: "EditStyle", + command: bindFixed(this.editElementStyle, this) } + ); + } + else if (!isSystemStyleSheet(this.selection)) + { + items.push( + //"-", + {label: "NewRule", + command: bindFixed(this.insertRule, this, target) } + ); + } + + var cssRule = getAncestorByClass(target, "cssRule"); + if (cssRule && hasClass(cssRule, "cssEditableRule")) + { + items.push( + "-", + {label: "NewProp", + command: bindFixed(this.insertPropertyRow, this, target) } + ); + + var propRow = getAncestorByClass(target, "cssProp"); + if (propRow) + { + var propName = getChildByClass(propRow, "cssPropName")[textContent]; + var isDisabled = hasClass(propRow, "disabledStyle"); + + items.push( + {label: $STRF("EditProp", [propName]), nol10n: true, + command: bindFixed(this.editPropertyRow, this, propRow) }, + {label: $STRF("DeleteProp", [propName]), nol10n: true, + command: bindFixed(this.deletePropertyRow, this, propRow) }, + {label: $STRF("DisableProp", [propName]), nol10n: true, + type: "checkbox", checked: isDisabled, + command: bindFixed(this.disablePropertyRow, this, propRow) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ); + + return items; + }, + + browseObject: function(object) + { + if (this.infoTipType == "image") + { + openNewTab(this.infoTipObject); + return true; + } + }, + + showInfoTip: function(infoTip, target, x, y) + { + var propValue = getAncestorByClass(target, "cssPropValue"); + if (propValue) + { + var offset = getClientOffset(propValue); + var offsetX = x-offset.x; + + var text = propValue[textContent]; + var charWidth = propValue.offsetWidth/text.length; + var charOffset = Math.floor(offsetX/charWidth); + + var cssValue = parseCSSValue(text, charOffset); + if (cssValue) + { + if (cssValue.value == this.infoTipValue) + return true; + + this.infoTipValue = cssValue.value; + + if (cssValue.type == "rgb" || (!cssValue.type && isColorKeyword(cssValue.value))) + { + this.infoTipType = "color"; + this.infoTipObject = cssValue.value; + + return Firebug.InfoTip.populateColorInfoTip(infoTip, cssValue.value); + } + else if (cssValue.type == "url") + { + ///var propNameNode = target.parentNode.getElementsByClassName("cssPropName").item(0); + var propNameNode = getElementByClass(target.parentNode, "cssPropName"); + if (propNameNode && isImageRule(propNameNode[textContent])) + { + var rule = Firebug.getRepObject(target); + var baseURL = this.getStylesheetURL(rule); + var relURL = parseURLValue(cssValue.value); + var absURL = isDataURL(relURL) ? relURL:absoluteURL(relURL, baseURL); + var repeat = parseRepeatValue(text); + + this.infoTipType = "image"; + this.infoTipObject = absURL; + + return Firebug.InfoTip.populateImageInfoTip(infoTip, absURL, repeat); + } + } + } + } + + delete this.infoTipType; + delete this.infoTipValue; + delete this.infoTipObject; + }, + + getEditor: function(target, value) + { + if (target == this.panelNode + || hasClass(target, "cssSelector") || hasClass(target, "cssRule") + || hasClass(target, "cssSheet")) + { + if (!this.ruleEditor) + this.ruleEditor = new CSSRuleEditor(this.document); + + return this.ruleEditor; + } + else + { + if (!this.editor) + this.editor = new CSSEditor(this.document); + + return this.editor; + } + }, + + getDefaultLocation: function() + { + try + { + var styleSheets = this.context.window.document.styleSheets; + if (styleSheets.length) + { + var sheet = styleSheets[0]; + return (Firebug.filterSystemURLs && isSystemURL(getURLForStyleSheet(sheet))) ? null : sheet; + } + } + catch (exc) + { + if (FBTrace.DBG_LOCATIONS) + FBTrace.sysout("css.getDefaultLocation FAILS "+exc, exc); + } + }, + + getObjectDescription: function(styleSheet) + { + var url = getURLForStyleSheet(styleSheet); + var instance = getInstanceForStyleSheet(styleSheet); + + var baseDescription = splitURLBase(url); + if (instance) { + baseDescription.name = baseDescription.name + " #" + (instance + 1); + } + return baseDescription; + }, + + search: function(text, reverse) + { + var curDoc = this.searchCurrentDoc(!Firebug.searchGlobal, text, reverse); + if (!curDoc && Firebug.searchGlobal) + { + return this.searchOtherDocs(text, reverse); + } + return curDoc; + }, + + searchOtherDocs: function(text, reverse) + { + var scanRE = Firebug.Search.getTestingRegex(text); + function scanDoc(styleSheet) { + // we don't care about reverse here as we are just looking for existence, + // if we do have a result we will handle the reverse logic on display + for (var i = 0; i < styleSheet.cssRules.length; i++) + { + if (scanRE.test(styleSheet.cssRules[i].cssText)) + { + return true; + } + } + } + + if (this.navigateToNextDocument(scanDoc, reverse)) + { + return this.searchCurrentDoc(true, text, reverse); + } + }, + + searchCurrentDoc: function(wrapSearch, text, reverse) + { + if (!text) + { + delete this.currentSearch; + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + { + row = this.currentSearch.findNext(wrapSearch, false, reverse, Firebug.Search.isCaseSensitive(text)); + } + else + { + if (this.editing) + { + this.currentSearch = new TextSearch(this.stylesheetEditor.box); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + scrollSelectionIntoView(this); + return true; + } + else + return false; + } + else + { + function findRow(node) { return node.nodeType == 1 ? node : node.parentNode; } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + } + } + + if (row) + { + this.document.defaultView.getSelection().selectAllChildren(row); + scrollIntoCenterView(row, this.panelNode); + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, null]); + return false; + } + }, + + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive"), + Firebug.Search.searchOptionMenu("search.Multiple_Files", "searchGlobal") + ]; + } +}); +/**/ +// ************************************************************************************************ + +function CSSElementPanel() {} + +CSSElementPanel.prototype = extend(Firebug.CSSStyleSheetPanel.prototype, +{ + template: domplate( + { + cascadedTag: + DIV({"class": "a11yCSSView", role : 'presentation'}, + DIV({role : 'list', 'aria-label' : $STR('aria.labels.style rules') }, + FOR("rule", "$rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ), + DIV({role : "list", 'aria-label' :$STR('aria.labels.inherited style rules')}, + FOR("section", "$inherited", + H1({"class": "cssInheritHeader groupHeader focusRow", role : 'listitem' }, + SPAN({"class": "cssInheritLabel"}, "$inheritLabel"), + TAG(FirebugReps.Element.shortTag, {object: "$section.element"}) + ), + DIV({role : 'group'}, + FOR("rule", "$section.rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ) + ) + ) + ), + + ruleTag: + isIE ? + // IE needs the sourceLink first, otherwise it will be rendered outside the panel + DIV({"class": "cssElementRuleContainer"}, + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}), + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}) + ) + : + // other browsers need the sourceLink last, otherwise it will cause an extra space + // before the rule representation + DIV({"class": "cssElementRuleContainer"}, + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}), + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateCascadeView: function(element) + { + //dispatch([Firebug.A11yModel], 'onBeforeCSSRulesAdded', [this]); + var rules = [], sections = [], usedProps = {}; + this.getInheritedRules(element, sections, usedProps); + this.getElementRules(element, rules, usedProps); + + if (rules.length || sections.length) + { + var inheritLabel = "Inherited from"; // $STR("InheritedFrom"); + var result = this.template.cascadedTag.replace({rules: rules, inherited: sections, + inheritLabel: inheritLabel}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + else + { + var result = FirebugReps.Warning.tag.replace({object: "EmptyElementCSS"}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + + // TODO: xxxpedro remove when there the external resource problem is fixed + if (externalStyleSheetURLs.length > 0) + externalStyleSheetWarning.tag.append({ + object: "The results here may be inaccurate because some " + + "stylesheets could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22" + }, this.panelNode); + }, + + getStylesheetURL: function(rule) + { + // if the parentStyleSheet.href is null, CSS std says its inline style. + // TODO: xxxpedro IE doesn't have rule.parentStyleSheet so we must fall back to the doc.location + if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href) + return rule.parentStyleSheet.href; + else + return this.selection.ownerDocument.location.href; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getInheritedRules: function(element, sections, usedProps) + { + var parent = element.parentNode; + if (parent && parent.nodeType == 1) + { + this.getInheritedRules(parent, sections, usedProps); + + var rules = []; + this.getElementRules(parent, rules, usedProps, true); + + if (rules.length) + sections.splice(0, 0, {element: parent, rules: rules}); + } + }, + + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + + // TODO: xxxpedro remove document specificity issue + //var eid = ElementCache(element); + //inspectedRules = ElementCSSRulesMap[eid]; + + inspectedRules = getElementCSSRules(element); + + if (inspectedRules) + { + for (var i = 0, length=inspectedRules.length; i < length; ++i) + { + var ruleId = inspectedRules[i]; + var ruleData = CSSRuleMap[ruleId]; + var rule = ruleData.rule; + + var ssid = ruleData.styleSheetId; + var parentStyleSheet = StyleSheetCache.get(ssid); + + var href = parentStyleSheet.externalURL ? parentStyleSheet.externalURL : parentStyleSheet.href; // Null means inline + + var instance = null; + //var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = false; + //var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + // + //var line = domUtils.getRuleLine(rule); + var line; + + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: ruleData.selector, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /* + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + try + { + inspectedRules = domUtils ? domUtils.getCSSStyleRules(element) : null; + } catch (exc) {} + + if (inspectedRules) + { + for (var i = 0; i < inspectedRules.Count(); ++i) + { + var rule = QI(inspectedRules.GetElementAt(i), nsIDOMCSSStyleRule); + + var href = rule.parentStyleSheet.href; // Null means inline + + var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + var line = domUtils.getRuleLine(rule); + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: rule.selectorText, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /**/ + markOverridenProps: function(props, usedProps, inheritMode) + { + for (var i = 0; i < props.length; ++i) + { + var prop = props[i]; + if ( usedProps.hasOwnProperty(prop.name) ) + { + var deadProps = usedProps[prop.name]; // all previous occurrences of this property + for (var j = 0; j < deadProps.length; ++j) + { + var deadProp = deadProps[j]; + if (!deadProp.disabled && !deadProp.wasInherited && deadProp.important && !prop.important) + prop.overridden = true; // new occurrence overridden + else if (!prop.disabled) + deadProp.overridden = true; // previous occurrences overridden + } + } + else + usedProps[prop.name] = []; + + prop.wasInherited = inheritMode ? true : false; + usedProps[prop.name].push(prop); // all occurrences of a property seen so far, by name + } + }, + + getStyleProperties: function(element, rules, usedProps, inheritMode) + { + var props = this.parseCSSProps(element.style, inheritMode); + this.addOldProperties(this.context, getElementXPath(element), inheritMode, props); + + sortProperties(props); + this.markOverridenProps(props, usedProps, inheritMode); + + if (props.length) + rules.splice(0, 0, + {rule: element, id: getElementXPath(element), + selector: "element.style", props: props, inherited: inheritMode}); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "css", + title: "Style", + parentPanel: "HTML", + order: 0, + + initialize: function() + { + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + Firebug.CSSStyleSheetPanel.prototype.initialize.apply(this, arguments); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + + //this.updateCascadeView(document.getElementsByTagName("h1")[0]); + //this.updateCascadeView(document.getElementById("build")); + + /* + this.onStateChange = bindFixed(this.contentStateCheck, this); + this.onHoverChange = bindFixed(this.contentStateCheck, this, STATE_HOVER); + this.onActiveChange = bindFixed(this.contentStateCheck, this, STATE_ACTIVE); + /**/ + }, + + ishow: function(state) + { + }, + + watchWindow: function(win) + { + if (domUtils) + { + // Normally these would not be required, but in order to update after the state is set + // using the options menu we need to monitor these global events as well + var doc = win.document; + ///addEvent(doc, "mouseover", this.onHoverChange); + ///addEvent(doc, "mousedown", this.onActiveChange); + } + }, + unwatchWindow: function(win) + { + var doc = win.document; + ///removeEvent(doc, "mouseover", this.onHoverChange); + ///removeEvent(doc, "mousedown", this.onActiveChange); + + if (isAncestor(this.stateChangeEl, doc)) + { + this.removeStateChangeHandlers(); + } + }, + + supportsObject: function(object) + { + return object instanceof Element ? 1 : 0; + }, + + updateView: function(element) + { + this.updateCascadeView(element); + if (domUtils) + { + this.contentState = safeGetContentState(element); + this.addStateChangeHandlers(element); + } + }, + + updateSelection: function(element) + { + if ( !instanceOf(element , "Element") ) // html supports SourceLink + return; + + if (sothinkInstalled) + { + FirebugReps.Warning.tag.replace({object: "SothinkWarning"}, this.panelNode); + return; + } + + /* + if (!domUtils) + { + FirebugReps.Warning.tag.replace({object: "DOMInspectorWarning"}, this.panelNode); + return; + } + /**/ + + if (!element) + return; + + this.updateView(element); + }, + + updateOption: function(name, value) + { + if (name == "showUserAgentCSS" || name == "expandShorthandProps") + this.refresh(); + }, + + getOptionsMenuItems: function() + { + var ret = [ + {label: "Show User Agent CSS", type: "checkbox", checked: Firebug.showUserAgentCSS, + command: bindFixed(Firebug.togglePref, Firebug, "showUserAgentCSS") }, + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") } + ]; + if (domUtils && this.selection) + { + var state = safeGetContentState(this.selection); + + ret.push("-"); + ret.push({label: ":active", type: "checkbox", checked: state & STATE_ACTIVE, + command: bindFixed(this.updateContentState, this, STATE_ACTIVE, state & STATE_ACTIVE)}); + ret.push({label: ":hover", type: "checkbox", checked: state & STATE_HOVER, + command: bindFixed(this.updateContentState, this, STATE_HOVER, state & STATE_HOVER)}); + } + return ret; + }, + + updateContentState: function(state, remove) + { + domUtils.setContentState(remove ? this.selection.ownerDocument.documentElement : this.selection, state); + this.refresh(); + }, + + addStateChangeHandlers: function(el) + { + this.removeStateChangeHandlers(); + + /* + addEvent(el, "focus", this.onStateChange); + addEvent(el, "blur", this.onStateChange); + addEvent(el, "mouseup", this.onStateChange); + addEvent(el, "mousedown", this.onStateChange); + addEvent(el, "mouseover", this.onStateChange); + addEvent(el, "mouseout", this.onStateChange); + /**/ + + this.stateChangeEl = el; + }, + + removeStateChangeHandlers: function() + { + var sel = this.stateChangeEl; + if (sel) + { + /* + removeEvent(sel, "focus", this.onStateChange); + removeEvent(sel, "blur", this.onStateChange); + removeEvent(sel, "mouseup", this.onStateChange); + removeEvent(sel, "mousedown", this.onStateChange); + removeEvent(sel, "mouseover", this.onStateChange); + removeEvent(sel, "mouseout", this.onStateChange); + /**/ + } + }, + + contentStateCheck: function(state) + { + if (!state || this.contentState & state) + { + var timeoutRunner = bindFixed(function() + { + var newState = safeGetContentState(this.selection); + if (newState != this.contentState) + { + this.context.invalidatePanels(this.name); + } + }, this); + + // Delay exec until after the event has processed and the state has been updated + setTimeout(timeoutRunner, 0); + } + } +}); + +function safeGetContentState(selection) +{ + try + { + return domUtils.getContentState(selection); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.safeGetContentState; EXCEPTION", e); + } +} + +// ************************************************************************************************ + +function CSSComputedElementPanel() {} + +CSSComputedElementPanel.prototype = extend(CSSElementPanel.prototype, +{ + template: domplate( + { + computedTag: + DIV({"class": "a11yCSSView", role : "list", "aria-label" : $STR('aria.labels.computed styles')}, + FOR("group", "$groups", + H1({"class": "cssInheritHeader groupHeader focusRow", role : "listitem"}, + SPAN({"class": "cssInheritLabel"}, "$group.title") + ), + TABLE({width: "100%", role : 'group'}, + TBODY({role : 'presentation'}, + FOR("prop", "$group.props", + TR({"class": 'focusRow computedStyleRow', role : 'listitem'}, + TD({"class": "stylePropName", role : 'presentation'}, "$prop.name"), + TD({"class": "stylePropValue", role : 'presentation'}, "$prop.value") + ) + ) + ) + ) + ) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateComputedView: function(element) + { + var win = isIE ? + element.ownerDocument.parentWindow : + element.ownerDocument.defaultView; + + var style = isIE ? + element.currentStyle : + win.getComputedStyle(element, ""); + + var groups = []; + + for (var groupName in styleGroups) + { + // TODO: xxxpedro i18n $STR + //var title = $STR("StyleGroup-" + groupName); + var title = styleGroupTitles[groupName]; + var group = {title: title, props: []}; + groups.push(group); + + var props = styleGroups[groupName]; + for (var i = 0; i < props.length; ++i) + { + var propName = props[i]; + var propValue = style.getPropertyValue ? + style.getPropertyValue(propName) : + ""+style[toCamelCase(propName)]; + + if (propValue === undefined || propValue === null) + continue; + + propValue = stripUnits(rgbToHex(propValue)); + if (propValue) + group.props.push({name: propName, value: propValue}); + } + } + + var result = this.template.computedTag.replace({groups: groups}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "computed", + title: "Computed", + parentPanel: "HTML", + order: 1, + + updateView: function(element) + { + this.updateComputedView(element); + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Refresh", command: bind(this.refresh, this) } + ]; + } +}); + +// ************************************************************************************************ +// CSSEditor + +function CSSEditor(doc) +{ + this.initializeInline(doc); +} + +CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var rule = Firebug.getRepObject(target); + var emptyProp = + { + // TODO: xxxpedro - uses charCode(255) to force the element being rendered, + // allowing webkit to get the correct position of the property name "span", + // when inserting a new CSS rule? + name: "", + value: "", + important: "" + }; + + if (insertWhere == "before") + return CSSPropTag.tag.insertBefore({prop: emptyProp, rule: rule}, target); + else + return CSSPropTag.tag.insertAfter({prop: emptyProp, rule: rule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + // We need to check the value first in order to avoid a problem in IE8 + // See Issue 3038: Empty (null) styles when adding CSS styles in Firebug Lite + if (!value) return; + + target.innerHTML = escapeForCss(value); + + var row = getAncestorByClass(target, "cssProp"); + if (hasClass(row, "disabledStyle")) + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(target); + + if (hasClass(target, "cssPropName")) + { + if (value && previousValue != value) // name of property has changed. + { + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + + if (propValue && propValue != "undefined") { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSEditor.saveEdit : "+previousValue+"->"+value+" = "+propValue+"\n"); + if (previousValue) + Firebug.CSSModule.removeProperty(rule, previousValue); + Firebug.CSSModule.setProperty(rule, value, parsedValue.value, parsedValue.priority); + } + } + else if (!value) // name of the property has been deleted, so remove the property. + Firebug.CSSModule.removeProperty(rule, previousValue); + } + else if (getAncestorByClass(target, "cssPropValue")) + { + var propName = getChildByClass(row, "cssPropName")[textContent]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + + if (FBTrace.DBG_CSS) + { + FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName +" = "+propValue+"\n"); + // FBTrace.sysout("CSSEditor.saveEdit BEFORE style:",style); + } + + if (value && value != "null") + { + var parsedValue = parsePriority(value); + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + } + else if (previousValue && previousValue != "null") + Firebug.CSSModule.removeProperty(rule, propName); + } + + this.panel.markChange(this.panel.name == "stylesheet"); + }, + + advanceToNext: function(target, charCode) + { + if (charCode == 58 /*":"*/ && hasClass(target, "cssPropName")) + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + if (hasClass(this.target, "cssPropName")) + return {start: 0, end: value.length-1}; + else + return parseCSSValue(value, offset); + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + if (hasClass(this.target, "cssPropName")) + { + return getCSSPropertyNames(); + } + else + { + var row = getAncestorByClass(this.target, "cssProp"); + var propName = getChildByClass(row, "cssPropName")[textContent]; + return getCSSKeywordsByProperty(propName); + } + } +}); + +//************************************************************************************************ +//CSSRuleEditor + +function CSSRuleEditor(doc) +{ + this.initializeInline(doc); + this.completeAsYouType = false; +} +CSSRuleEditor.uniquifier = 0; +CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var emptyRule = { + selector: "", + id: "", + props: [], + isSelectorEditable: true + }; + + if (insertWhere == "before") + return CSSStyleRuleTag.tag.insertBefore({rule: emptyRule}, target); + else + return CSSStyleRuleTag.tag.insertAfter({rule: emptyRule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSRuleEditor.saveEdit: '" + value + "' '" + previousValue + "'", target); + + target.innerHTML = escapeForCss(value); + + if (value === previousValue) return; + + var row = getAncestorByClass(target, "cssRule"); + var styleSheet = this.panel.location; + styleSheet = styleSheet.editStyleSheet ? styleSheet.editStyleSheet.sheet : styleSheet; + + var cssRules = styleSheet.cssRules; + var rule = Firebug.getRepObject(target), oldRule = rule; + var ruleIndex = cssRules.length; + if (rule || Firebug.getRepObject(row.nextSibling)) + { + var searchRule = rule || Firebug.getRepObject(row.nextSibling); + for (ruleIndex=0; ruleIndex b.name ? 1 : -1; + }); +} + +function getTopmostRuleLine(panelNode) +{ + for (var child = panelNode.firstChild; child; child = child.nextSibling) + { + if (child.offsetTop+child.offsetHeight > panelNode.scrollTop) + { + var rule = child.repObject; + if (rule) + return { + line: domUtils.getRuleLine(rule), + offset: panelNode.scrollTop-child.offsetTop + }; + } + } + return 0; +} + +function getStyleSheetCSS(sheet, context) +{ + if (sheet.ownerNode instanceof HTMLStyleElement) + return sheet.ownerNode.innerHTML; + else + return context.sourceCache.load(sheet.href).join(""); +} + +function getStyleSheetOwnerNode(sheet) { + for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet); + + return sheet.ownerNode; +} + +function scrollSelectionIntoView(panel) +{ + var selCon = getSelectionController(panel); + selCon.scrollSelectionIntoView( + nsISelectionController.SELECTION_NORMAL, + nsISelectionController.SELECTION_FOCUS_REGION, true); +} + +function getSelectionController(panel) +{ + var browser = Firebug.chrome.getPanelBrowser(panel); + return browser.docShell.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsISelectionDisplay) + .QueryInterface(nsISelectionController); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.CSSModule); +Firebug.registerPanel(Firebug.CSSStyleSheetPanel); +Firebug.registerPanel(CSSElementPanel); +Firebug.registerPanel(CSSComputedElementPanel); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Script Module + +Firebug.Script = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Script") : null; + }, + + selectSourceCode: function(index) + { + this.getPanel().selectSourceCode(index); + } +}); + +Firebug.registerModule(Firebug.Script); + + +// ************************************************************************************************ +// Script Panel + +function ScriptPanel(){}; + +ScriptPanel.prototype = extend(Firebug.Panel, +{ + name: "Script", + title: "Script", + + selectIndex: 0, // index of the current selectNode's option + sourceIndex: -1, // index of the script node, based in doc.getElementsByTagName("script") + + options: { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var scripts = doc.getElementsByTagName("script"); + var selectNode = this.selectNode = createElement("select"); + + for(var i=0, script; script=scripts[i]; i++) + { + // Don't show Firebug Lite source code in the list of options + if (Firebug.ignoreFirebugElements && script.getAttribute("firebugIgnore")) + continue; + + var fileName = getFileName(script.src) || getFileName(doc.location.href); + var option = createElement("option", {value:i}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }; + + this.toolButtonsNode.appendChild(selectNode); + }, + + initialize: function() + { + // we must render the code first, so the persistent state can be restore + this.selectSourceCode(this.selectIndex); + + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.selectNode, "change", this.onChangeSelect); + }, + + shutdown: function() + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + detach: function(oldChrome, newChrome) + { + Firebug.Panel.detach.apply(this, arguments); + + var oldPanel = oldChrome.getPanel("Script"); + var index = oldPanel.selectIndex; + + this.selectNode.selectedIndex = index; + this.selectIndex = index; + this.sourceIndex = -1; + }, + + onChangeSelect: function(event) + { + var select = this.selectNode; + + this.selectIndex = select.selectedIndex; + + var option = select.options[select.selectedIndex]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + selectSourceCode: function(index) + { + var select = this.selectNode; + select.selectedIndex = index; + + var option = select.options[index]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + renderSourceCode: function(index) + { + if (this.sourceIndex != index) + { + var renderProcess = function renderProcess(src) + { + var html = [], + hl = 0; + + src = isIE && !isExternal ? + src+'\n' : // IE put an extra line when reading source of local resources + '\n'+src; + + // find the number of lines of code + src = src.replace(/\n\r|\r\n/g, "\n"); + var match = src.match(/[\n]/g); + var lines=match ? match.length : 0; + + // render the full source code + line numbers html + html[hl++] = '
      ';
      +                html[hl++] = escapeHTML(src);
      +                html[hl++] = '
      '; + + // render the line number divs + for(var l=1, lines; l<=lines; l++) + { + html[hl++] = '
      '; + html[hl++] = l; + html[hl++] = '
      '; + } + + html[hl++] = '
      '; + + updatePanel(html); + }; + + var updatePanel = function(html) + { + self.panelNode.innerHTML = html.join(""); + + // IE needs this timeout, otherwise the panel won't scroll + setTimeout(function(){ + self.synchronizeUI(); + },0); + }; + + var onFailure = function() + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, self.panelNode); + }; + + var self = this; + + var doc = Firebug.browser.document; + var script = doc.getElementsByTagName("script")[index]; + var url = getScriptURL(script); + var isExternal = url && url != doc.location.href; + + try + { + if (isExternal) + { + Ajax.request({url: url, onSuccess: renderProcess, onFailure: onFailure}); + } + else + { + var src = script.innerHTML; + renderProcess(src); + } + } + catch(e) + { + onFailure(); + } + + this.sourceIndex = index; + } + } +}); + +Firebug.registerPanel(ScriptPanel); + + +// ************************************************************************************************ + + +var getScriptURL = function getScriptURL(script) +{ + var reFile = /([^\/\?#]+)(#.+)?$/; + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = Firebug.browser.document; + + var file = reFile.exec(script.src); + + if (file) + { + var fileName = file[1]; + var fileOptions = file[2]; + + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; + + } + // relative path + else + { + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(doc.location.href)[1]; + + // "../some/path" + if (backDir) + { + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + return path + fileName; + } +}; + +var getFileName = function getFileName(path) +{ + if (!path) return ""; + + var match = path && path.match(/[^\/]+(\?.*)?(#.*)?$/); + + return match && match[0] || path; +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var ElementCache = Firebug.Lite.Cache.Element; + +var insertSliceSize = 18; +var insertInterval = 40; + +var ignoreVars = +{ + "__firebug__": 1, + "eval": 1, + + // We are forced to ignore Java-related variables, because + // trying to access them causes browser freeze + "java": 1, + "sun": 1, + "Packages": 1, + "JavaArray": 1, + "JavaMember": 1, + "JavaObject": 1, + "JavaClass": 1, + "JavaPackage": 1, + "_firebug": 1, + "_FirebugConsole": 1, + "_FirebugCommandLine": 1 +}; + +if (Firebug.ignoreFirebugElements) + ignoreVars[Firebug.Lite.Cache.ID] = 1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var memberPanelRep = + isIE6 ? + {"class": "memberLabel $member.type\\Label", href: "javacript:void(0)"} + : + {"class": "memberLabel $member.type\\Label"}; + +var RowTag = + TR({"class": "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren", role : 'presentation', + level: "$member.level"}, + TD({"class": "memberLabelCell", style: "padding-left: $member.indent\\px", role : 'presentation'}, + A(memberPanelRep, + SPAN({}, "$member.name") + ) + ), + TD({"class": "memberValueCell", role : 'presentation'}, + TAG("$member.tag", {object: "$member.value"}) + ) + ); + +var WatchRowTag = + TR({"class": "watchNewRow", level: 0}, + TD({"class": "watchEditCell", colspan: 2}, + DIV({"class": "watchEditBox a11yFocusNoTab", role: "button", 'tabindex' : '0', + 'aria-label' : $STR('press enter to add new watch expression')}, + $STR("NewWatch") + ) + ) + ); + +var SizerRow = + TR({role : 'presentation'}, + TD({width: "30%"}), + TD({width: "70%"}) + ); + +var domTableClass = isIElt8 ? "domTable domTableIE" : "domTable"; +var DirTablePlate = domplate(Firebug.Rep, +{ + tag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, onclick: "$onClick", role :"tree"}, + TBODY({role: 'presentation'}, + SizerRow, + FOR("member", "$object|memberIterator", RowTag) + ) + ), + + watchTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow, + WatchRowTag + ) + ), + + tableTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow + ) + ), + + rowTag: + FOR("member", "$members", RowTag), + + memberIterator: function(object, level) + { + return getMembers(object, level); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + if (!isLeftClick(event)) + return; + + var target = event.target || event.srcElement; + + var row = getAncestorByClass(target, "memberRow"); + var label = getAncestorByClass(target, "memberLabel"); + if (label && hasClass(row, "hasChildren")) + { + var row = label.parentNode.parentNode; + this.toggleRow(row); + } + else + { + var object = Firebug.getRepObject(target); + if (typeof(object) == "function") + { + Firebug.chrome.select(object, "script"); + cancelEvent(event); + } + else if (event.detail == 2 && !object) + { + var panel = row.parentNode.parentNode.domPanel; + if (panel) + { + var rowValue = panel.getRowPropertyValue(row); + if (typeof(rowValue) == "boolean") + panel.setPropertyValue(row, !rowValue); + else + panel.editProperty(row); + + cancelEvent(event); + } + } + } + + return false; + }, + + toggleRow: function(row) + { + var level = parseInt(row.getAttribute("level")); + var toggles = row.parentNode.parentNode.toggles; + + if (hasClass(row, "opened")) + { + removeClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Remove the path from the toggle tree + for (var i = 0; i < path.length; ++i) + { + if (i == path.length-1) + delete toggles[path[i]]; + else + toggles = toggles[path[i]]; + } + } + + var rowTag = this.rowTag; + var tbody = row.parentNode; + + setTimeout(function() + { + for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling) + { + if (parseInt(firstRow.getAttribute("level")) <= level) + break; + + tbody.removeChild(firstRow); + } + }, row.insertTimeout ? row.insertTimeout : 0); + } + else + { + setClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Mark the path in the toggle tree + for (var i = 0; i < path.length; ++i) + { + var name = path[i]; + if (toggles.hasOwnProperty(name)) + toggles = toggles[name]; + else + toggles = toggles[name] = {}; + } + } + + var value = row.lastChild.firstChild.repObject; + var members = getMembers(value, level+1); + + var rowTag = this.rowTag; + var lastRow = row; + + var delay = 0; + //var setSize = members.length; + //var rowCount = 1; + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + setTimeout(function() + { + if (lastRow.parentNode) + { + var result = rowTag.insertRows({members: slice}, lastRow); + lastRow = result[1]; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [null, result, rowCount, setSize]); + //rowCount += insertSliceSize; + } + if (isLast) + row.removeAttribute("insertTimeout"); + }, delay); + } + + delay += insertInterval; + } + + row.insertTimeout = delay; + } + } +}); + + + +// ************************************************************************************************ + +Firebug.DOMBasePanel = function() {} + +Firebug.DOMBasePanel.prototype = extend(Firebug.Panel, +{ + tag: DirTablePlate.tableTag, + + getRealObject: function(object) + { + // TODO: Move this to some global location + // TODO: Unwrapping should be centralized rather than sprinkling it around ad hoc. + // TODO: We might be able to make this check more authoritative with QueryInterface. + if (!object) return object; + if (object.wrappedJSObject) return object.wrappedJSObject; + return object; + }, + + rebuild: function(update, scrollTop) + { + //dispatch([Firebug.A11yModel], 'onBeforeDomUpdateSelection', [this]); + var members = getMembers(this.selection); + expandMembers(members, this.toggles, 0, 0); + + this.showMembers(members, update, scrollTop); + + //TODO: xxxpedro statusbar + if (!this.parentPanel) + updateStatusBar(this); + }, + + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!tbody.lastChild) return; + + result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //rowCount += insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop) + panelNode.scrollTop = priorScrollTop; + + + // enable to measure rendering performance + //if (isLast) alert(new Date().getTime() - renderStart + "ms"); + + + }, delay)); + + delay += insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + + /* + // new + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + var _insertSliceSize = insertSliceSize; + var _insertInterval = insertInterval; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + var lastSkip = renderStart, now; + + while (members.length) + { + with({slice: members.splice(0, _insertSliceSize), isLast: !members.length}) + { + var _tbody = tbody; + var _rowTag = rowTag; + var _panelNode = panelNode; + var _priorScrollTop = priorScrollTop; + + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!_tbody.lastChild) return; + + result = _rowTag.insertRows({members: slice}, _tbody.lastChild); + + //rowCount += _insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((_panelNode.scrollHeight + _panelNode.offsetHeight) >= _priorScrollTop) + _panelNode.scrollTop = _priorScrollTop; + + + // enable to measure rendering performance + //alert("gap: " + (new Date().getTime() - lastSkip)); + //lastSkip = new Date().getTime(); + + //if (isLast) alert("new: " + (new Date().getTime() - renderStart) + "ms"); + + }, delay)); + + delay += _insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + /**/ + + showEmptyMembers: function() + { + FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode); + }, + + findPathObject: function(object) + { + var pathIndex = -1; + for (var i = 0; i < this.objectPath.length; ++i) + { + // IE needs === instead of == or otherwise some objects will + // be considered equal to different objects, returning the + // wrong index of the objectPath array + if (this.getPathObject(i) === object) + return i; + } + + return -1; + }, + + getPathObject: function(index) + { + var object = this.objectPath[index]; + + if (object instanceof Property) + return object.getObject(); + else + return object; + }, + + getRowObject: function(row) + { + var object = getRowOwnerObject(row); + return object ? object : this.selection; + }, + + getRowPropertyValue: function(row) + { + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object) + { + var propName = getRowName(row); + + if (object instanceof jsdIStackFrame) + return Firebug.Debugger.evaluate(propName, this.context); + else + return object[propName]; + } + }, + /* + copyProperty: function(row) + { + var value = this.getRowPropertyValue(row); + copyToClipboard(value); + }, + + editProperty: function(row, editValue) + { + if (hasClass(row, "watchNewRow")) + { + if (this.context.stopped) + Firebug.Editor.startEditing(row, ""); + else if (Firebug.Console.isAlwaysEnabled()) // not stopped in debugger, need command line + { + if (Firebug.CommandLine.onCommandLineFocus()) + Firebug.Editor.startEditing(row, ""); + else + row.innerHTML = $STR("warning.Command line blocked?"); + } + else + row.innerHTML = $STR("warning.Console must be enabled"); + } + else if (hasClass(row, "watchRow")) + Firebug.Editor.startEditing(row, getRowName(row)); + else + { + var object = this.getRowObject(row); + this.context.thisValue = object; + + if (!editValue) + { + var propValue = this.getRowPropertyValue(row); + + var type = typeof(propValue); + if (type == "undefined" || type == "number" || type == "boolean") + editValue = propValue; + else if (type == "string") + editValue = "\"" + escapeJS(propValue) + "\""; + else if (propValue == null) + editValue = "null"; + else if (object instanceof Window || object instanceof jsdIStackFrame) + editValue = getRowName(row); + else + editValue = "this." + getRowName(row); + } + + + Firebug.Editor.startEditing(row, editValue); + } + }, + + deleteProperty: function(row) + { + if (hasClass(row, "watchRow")) + this.deleteWatch(row); + else + { + var object = getRowOwnerObject(row); + if (!object) + object = this.selection; + object = this.getRealObject(object); + + if (object) + { + var name = getRowName(row); + try + { + delete object[name]; + } + catch (exc) + { + return; + } + + this.rebuild(true); + this.markChange(); + } + } + }, + + setPropertyValue: function(row, value) // value must be string + { + if(FBTrace.DBG_DOM) + { + FBTrace.sysout("row: "+row); + FBTrace.sysout("value: "+value+" type "+typeof(value), value); + } + + var name = getRowName(row); + if (name == "this") + return; + + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object && !(object instanceof jsdIStackFrame)) + { + // unwrappedJSObject.property = unwrappedJSObject + Firebug.CommandLine.evaluate(value, this.context, object, this.context.getGlobalScope(), + function success(result, context) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate success object["+name+"]="+result+" type "+typeof(result), result); + object[name] = result; + }, + function failed(exc, context) + { + try + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate failed with exc:"+exc+" object["+name+"]="+value+" type "+typeof(value), exc); + // If the value doesn't parse, then just store it as a string. Some users will + // not realize they're supposed to enter a JavaScript expression and just type + // literal text + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + ); + } + else if (this.context.stopped) + { + try + { + Firebug.CommandLine.evaluate(name+"="+value, this.context); + } + catch (exc) + { + try + { + // See catch block above... + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + } + + this.rebuild(true); + this.markChange(); + }, + + highlightRow: function(row) + { + if (this.highlightedRow) + cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context); + + this.highlightedRow = row; + + if (row) + setClassTimed(row, "jumpHighlight", this.context); + },/**/ + + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + create: function() + { + // TODO: xxxpedro + this.context = Firebug.browser; + + this.objectPath = []; + this.propertyPath = []; + this.viewPath = []; + this.pathIndex = -1; + this.toggles = {}; + + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.panelNode, "mousemove", this.onMouseMove); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + /* + destroy: function(state) + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + + if (this.pathIndex) + state.pathIndex = this.pathIndex; + if (this.viewPath) + state.viewPath = this.viewPath; + if (this.propertyPath) + state.propertyPath = this.propertyPath; + + if (this.propertyPath.length > 0 && !this.propertyPath[1]) + state.firstSelection = persistObject(this.getPathObject(1), this.context); + + Firebug.Panel.destroy.apply(this, arguments); + }, + /**/ + + ishow: function(state) + { + if (this.context.loaded && !this.selection) + { + if (!state) + { + this.select(null); + return; + } + if (state.viewPath) + this.viewPath = state.viewPath; + if (state.propertyPath) + this.propertyPath = state.propertyPath; + + var defaultObject = this.getDefaultSelection(this.context); + var selectObject = defaultObject; + + if (state.firstSelection) + { + var restored = state.firstSelection(this.context); + if (restored) + { + selectObject = restored; + this.objectPath = [defaultObject, restored]; + } + else + this.objectPath = [defaultObject]; + } + else + this.objectPath = [defaultObject]; + + if (this.propertyPath.length > 1) + { + for (var i = 1; i < this.propertyPath.length; ++i) + { + var name = this.propertyPath[i]; + if (!name) + continue; + + var object = selectObject; + try + { + selectObject = object[name]; + } + catch (exc) + { + selectObject = null; + } + + if (selectObject) + { + this.objectPath.push(new Property(object, name)); + } + else + { + // If we can't access a property, just stop + this.viewPath.splice(i); + this.propertyPath.splice(i); + this.objectPath.splice(i); + selectObject = this.getPathObject(this.objectPath.length-1); + break; + } + } + } + + var selection = state.pathIndex <= this.objectPath.length-1 + ? this.getPathObject(state.pathIndex) + : this.getPathObject(this.objectPath.length-1); + + this.select(selection); + } + }, + /* + hide: function() + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + }, + /**/ + + supportsObject: function(object) + { + if (object == null) + return 1000; + + if (typeof(object) == "undefined") + return 1000; + else if (object instanceof SourceLink) + return 0; + else + return 1; // just agree to support everything but not agressively. + }, + + refresh: function() + { + this.rebuild(true); + }, + + updateSelection: function(object) + { + var previousIndex = this.pathIndex; + var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex]; + + var newPath = this.pathToAppend; + delete this.pathToAppend; + + var pathIndex = this.findPathObject(object); + if (newPath || pathIndex == -1) + { + this.toggles = {}; + + if (newPath) + { + // Remove everything after the point where we are inserting, so we + // essentially replace it with the new path + if (previousView) + { + if (this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + var start = previousIndex + 1, + // Opera needs the length argument in splice(), otherwise + // it will consider that only one element should be removed + length = this.objectPath.length - start; + + this.objectPath.splice(start, length); + this.propertyPath.splice(start, length); + this.viewPath.splice(start, length); + } + + var value = this.getPathObject(previousIndex); + if (!value) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection no pathObject for "+previousIndex+"\n"); + return; + } + + for (var i = 0, length = newPath.length; i < length; ++i) + { + var name = newPath[i]; + var object = value; + try + { + value = value[name]; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection FAILS at path_i="+i+" for name:"+name+"\n"); + return; + } + + ++this.pathIndex; + this.objectPath.push(new Property(object, name)); + this.propertyPath.push(name); + this.viewPath.push({toggles: this.toggles, scrollTop: 0}); + } + } + else + { + this.toggles = {}; + + var win = Firebug.browser.window; + //var win = this.context.getGlobalScope(); + if (object === win) + { + this.pathIndex = 0; + this.objectPath = [win]; + this.propertyPath = [null]; + this.viewPath = [{toggles: this.toggles, scrollTop: 0}]; + } + else + { + this.pathIndex = 1; + this.objectPath = [win, object]; + this.propertyPath = [null, null]; + this.viewPath = [ + {toggles: {}, scrollTop: 0}, + {toggles: this.toggles, scrollTop: 0} + ]; + } + } + + this.panelNode.scrollTop = 0; + this.rebuild(); + } + else + { + this.pathIndex = pathIndex; + + var view = this.viewPath[pathIndex]; + this.toggles = view.toggles; + + // Persist the current scroll location + if (previousView && this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + this.rebuild(false, view.scrollTop); + } + }, + + getObjectPath: function(object) + { + return this.objectPath; + }, + + getDefaultSelection: function() + { + return Firebug.browser.window; + //return this.context.getGlobalScope(); + }/*, + + updateOption: function(name, value) + { + const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1, + showDOMFuncs: 1, showDOMConstants: 1}; + if ( optionMap.hasOwnProperty(name) ) + this.rebuild(true); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowUserProps", "showUserProps"), + optionMenu("ShowUserFuncs", "showUserFuncs"), + optionMenu("ShowDOMProps", "showDOMProps"), + optionMenu("ShowDOMFuncs", "showDOMFuncs"), + optionMenu("ShowDOMConstants", "showDOMConstants"), + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ]; + }, + + getContextMenuItems: function(object, target) + { + var row = getAncestorByClass(target, "memberRow"); + + var items = []; + + if (row) + { + var rowName = getRowName(row); + var rowObject = this.getRowObject(row); + var rowValue = this.getRowPropertyValue(row); + + var isWatch = hasClass(row, "watchRow"); + var isStackFrame = rowObject instanceof jsdIStackFrame; + + if (typeof(rowValue) == "string" || typeof(rowValue) == "number") + { + // Functions already have a copy item in their context menu + items.push( + "-", + {label: "CopyValue", + command: bindFixed(this.copyProperty, this, row) } + ); + } + + items.push( + "-", + {label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"), + command: bindFixed(this.editProperty, this, row) } + ); + + if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName))) + { + items.push( + {label: isWatch ? "DeleteWatch" : "DeleteProperty", + command: bindFixed(this.deleteProperty, this, row) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ); + + return items; + }, + + getEditor: function(target, value) + { + if (!this.editor) + this.editor = new DOMEditor(this.document); + + return this.editor; + }/**/ +}); + +// ************************************************************************************************ + +// TODO: xxxpedro statusbar +var updateStatusBar = function(panel) +{ + var path = panel.propertyPath; + var index = panel.pathIndex; + + var r = []; + + for (var i=0, l=path.length; i'); + r.push(i==0 ? "window" : path[i] || "Object"); + r.push('
      '); + + if(i < l-1) + r.push('>'); + } + panel.statusBarNode.innerHTML = r.join(""); +}; + + +var DOMMainPanel = Firebug.DOMPanel = function () {}; + +Firebug.DOMPanel.DirTable = DirTablePlate; + +DOMMainPanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + onClickStatusBar: function(event) + { + var target = event.srcElement || event.target; + var element = getAncestorByClass(target, "fbHover"); + + if(element) + { + var pathIndex = element.getAttribute("pathIndex"); + + if(pathIndex) + { + this.select(this.getPathObject(pathIndex)); + } + } + }, + + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + this.select(target.repObject, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOM", + title: "DOM", + searchable: true, + statusSeparator: ">", + + options: { + hasToolButtons: true, + hasStatusBar: true + }, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + + //TODO: xxxpedro + this.onClickStatusBar = bind(this.onClickStatusBar, this); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(oldPanelNode) + { + //this.panelNode.addEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'console']); + + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro dom + this.ishow(); + + //TODO: xxxpedro + addEvent(this.statusBarNode, "click", this.onClickStatusBar); + }, + + shutdown: function() + { + //this.panelNode.removeEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'console']); + + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }/*, + + search: function(text, reverse) + { + if (!text) + { + delete this.currentSearch; + this.highlightRow(null); + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + row = this.currentSearch.findNext(true, undefined, reverse, Firebug.searchCaseSensitive); + else + { + function findRow(node) { return getAncestorByClass(node, "memberRow"); } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.searchCaseSensitive); + } + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + + scrollIntoCenterView(row, this.panelNode); + + this.highlightRow(row); + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, null]); + return false; + } + }/**/ +}); + +Firebug.registerPanel(DOMMainPanel); + + +// ************************************************************************************************ + + + +// ************************************************************************************************ +// Local Helpers + +var getMembers = function getMembers(object, level) // we expect object to be user-level object wrapped in security blanket +{ + if (!level) + level = 0; + + var ordinals = [], userProps = [], userClasses = [], userFuncs = [], + domProps = [], domFuncs = [], domConstants = []; + + try + { + var domMembers = getDOMMembers(object); + //var domMembers = {}; // TODO: xxxpedro + //var domConstantMap = {}; // TODO: xxxpedro + + if (object.wrappedJSObject) + var insecureObject = object.wrappedJSObject; + else + var insecureObject = object; + + // IE function prototype is not listed in (for..in) + if (isIE && isFunction(object)) + addMember("user", userProps, "prototype", object.prototype, level); + + for (var name in insecureObject) // enumeration is safe + { + if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined. + continue; + + var val; + try + { + val = insecureObject[name]; // getter is safe + } + catch (exc) + { + // Sometimes we get exceptions trying to access certain members + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers cannot access "+name, exc); + } + + var ordinal = parseInt(name); + if (ordinal || ordinal == 0) + { + addMember("ordinal", ordinals, name, val, level); + } + else if (isFunction(val)) + { + if (isClassFunction(val) && !(name in domMembers)) + addMember("userClass", userClasses, name, val, level); + else if (name in domMembers) + addMember("domFunction", domFuncs, name, val, level, domMembers[name]); + else + addMember("userFunction", userFuncs, name, val, level); + } + else + { + //TODO: xxxpedro + /* + var getterFunction = insecureObject.__lookupGetter__(name), + setterFunction = insecureObject.__lookupSetter__(name), + prefix = ""; + + if(getterFunction && !setterFunction) + prefix = "get "; + /**/ + + var prefix = ""; + + if (name in domMembers && !(name in domConstantMap)) + addMember("dom", domProps, (prefix+name), val, level, domMembers[name]); + else if (name in domConstantMap) + addMember("dom", domConstants, (prefix+name), val, level); + else + addMember("user", userProps, (prefix+name), val, level); + } + } + } + catch (exc) + { + // Sometimes we get exceptions just from trying to iterate the members + // of certain objects, like StorageList, but don't let that gum up the works + throw exc; + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers FAILS: ", exc); + //throw exc; + } + + function sortName(a, b) { return a.name > b.name ? 1 : -1; } + function sortOrder(a, b) { return a.order > b.order ? 1 : -1; } + + var members = []; + + members.push.apply(members, ordinals); + + Firebug.showUserProps = true; // TODO: xxxpedro + Firebug.showUserFuncs = true; // TODO: xxxpedro + Firebug.showDOMProps = true; + Firebug.showDOMFuncs = true; + Firebug.showDOMConstants = true; + + if (Firebug.showUserProps) + { + userProps.sort(sortName); + members.push.apply(members, userProps); + } + + if (Firebug.showUserFuncs) + { + userClasses.sort(sortName); + members.push.apply(members, userClasses); + + userFuncs.sort(sortName); + members.push.apply(members, userFuncs); + } + + if (Firebug.showDOMProps) + { + domProps.sort(sortName); + members.push.apply(members, domProps); + } + + if (Firebug.showDOMFuncs) + { + domFuncs.sort(sortName); + members.push.apply(members, domFuncs); + } + + if (Firebug.showDOMConstants) + members.push.apply(members, domConstants); + + return members; +} + +function expandMembers(members, toggles, offset, level) // recursion starts with offset=0, level=0 +{ + var expanded = 0; + for (var i = offset; i < members.length; ++i) + { + var member = members[i]; + if (member.level > level) + break; + + if ( toggles.hasOwnProperty(member.name) ) + { + member.open = "opened"; // member.level <= level && member.name in toggles. + + var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1 + + var args = [i+1, 0]; + args.push.apply(args, newMembers); + members.splice.apply(members, args); + + /* + if (FBTrace.DBG_DOM) + { + FBTrace.sysout("expandMembers member.name", member.name); + FBTrace.sysout("expandMembers toggles", toggles); + FBTrace.sysout("expandMembers toggles[member.name]", toggles[member.name]); + FBTrace.sysout("dom.expandedMembers level: "+level+" member", member); + } + /**/ + + expanded += newMembers.length; + i += newMembers.length + expandMembers(members, toggles[member.name], i+1, level+1); + } + } + + return expanded; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +function isClassFunction(fn) +{ + try + { + for (var name in fn.prototype) + return true; + } catch (exc) {} + return false; +} + +var hasProperties = function hasProperties(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + + // IE function prototype is not listed in (for..in) + if (isFunction(ob)) return true; + + return false; +} + +FBL.ErrorCopy = function(message) +{ + this.message = message; +}; + +var addMember = function addMember(type, props, name, value, level, order) +{ + var rep = Firebug.getRep(value); // do this first in case a call to instanceof reveals contents + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var ErrorCopy = function(){}; //TODO: xxxpedro + + var valueType = typeof(value); + var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) && + (isFunction(value) || (valueType == "object" && value != null) + || (valueType == "string" && value.length > Firebug.stringCropLength)); + + props.push({ + name: name, + value: value, + type: type, + rowClass: "memberRow-"+type, + open: "", + order: order, + level: level, + indent: level*16, + hasChildren: hasChildren, + tag: tag + }); +} + +var getWatchRowIndex = function getWatchRowIndex(row) +{ + var index = -1; + for (; row && hasClass(row, "watchRow"); row = row.previousSibling) + ++index; + return index; +} + +var getRowName = function getRowName(row) +{ + var node = row.firstChild; + return node.textContent ? node.textContent : node.innerText; +} + +var getRowValue = function getRowValue(row) +{ + return row.lastChild.firstChild.repObject; +} + +var getRowOwnerObject = function getRowOwnerObject(row) +{ + var parentRow = getParentRow(row); + if (parentRow) + return getRowValue(parentRow); +} + +var getParentRow = function getParentRow(row) +{ + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + return row; + } +} + +var getPath = function getPath(row) +{ + var name = getRowName(row); + var path = [name]; + + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + { + var name = getRowName(row); + path.splice(0, 0, name); + + --level; + } + } + + return path; +} + +// ************************************************************************************************ + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// DOM Module + +Firebug.DOM = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("DOM") : null; + } +}); + +Firebug.registerModule(Firebug.DOM); + + +// ************************************************************************************************ +// DOM Panel + +var lastHighlightedObject; + +function DOMSidePanel(){}; + +DOMSidePanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + var object = target.repObject; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + /* + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + object = object ? object.repObject : null; + + if(!object) return; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + /**/ + + + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOMSidePanel", + parentPanel: "HTML", + title: "DOM", + + options: { + hasToolButtons: true + }, + + isInitialized: false, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + }, + + initialize: function(){ + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }, + + reattach: function(oldChrome) + { + //this.isInitialized = oldChrome.getPanel("DOM").isInitialized; + this.toggles = oldChrome.getPanel("DOMSidePanel").toggles; + } + +}); + +Firebug.registerPanel(DOMSidePanel); + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.FBTrace = {}; + +(function() { +// ************************************************************************************************ + +var traceOptions = { + DBG_TIMESTAMP: 1, + DBG_INITIALIZE: 1, + DBG_CHROME: 1, + DBG_ERRORS: 1, + DBG_DISPATCH: 1, + DBG_CSS: 1 +}; + +this.module = null; + +this.initialize = function() +{ + if (!this.messageQueue) + this.messageQueue = []; + + for (var name in traceOptions) + this[name] = traceOptions[name]; +}; + +// ************************************************************************************************ +// FBTrace API + +this.sysout = function() +{ + return this.logFormatted(arguments, ""); +}; + +this.dumpProperties = function(title, object) +{ + return this.logFormatted("dumpProperties() not supported.", "warning"); +}; + +this.dumpStack = function() +{ + return this.logFormatted("dumpStack() not supported.", "warning"); +}; + +this.flush = function(module) +{ + this.module = module; + + var queue = this.messageQueue; + this.messageQueue = []; + + for (var i = 0; i < queue.length; ++i) + this.writeMessage(queue[i][0], queue[i][1], queue[i][2]); +}; + +this.getPanel = function() +{ + return this.module ? this.module.getPanel() : null; +}; + +//************************************************************************************************* + +this.logFormatted = function(objects, className) +{ + var html = this.DBG_TIMESTAMP ? [getTimestamp(), " | "] : []; + var length = objects.length; + + for (var i = 0; i < length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + + if (i == 0) + { + html.push(""); + appendText(object, html); + html.push(""); + } + else + appendText(object, html); + } + + return this.logRow(html, className); +}; + +this.logRow = function(message, className) +{ + var panel = this.getPanel(); + + if (panel && panel.panelNode) + this.writeMessage(message, className); + else + { + this.messageQueue.push([message, className]); + } + + return this.LOG_COMMAND; +}; + +this.writeMessage = function(message, className) +{ + var container = this.getPanel().containerNode; + var isScrolledToBottom = + container.scrollTop + container.offsetHeight >= container.scrollHeight; + + this.writeRow.call(this, message, className); + + if (isScrolledToBottom) + container.scrollTop = container.scrollHeight - container.offsetHeight; +}; + +this.appendRow = function(row) +{ + var container = this.getPanel().panelNode; + container.appendChild(row); +}; + +this.writeRow = function(message, className) +{ + var row = this.getPanel().panelNode.ownerDocument.createElement("div"); + row.className = "logRow" + (className ? " logRow-"+className : ""); + row.innerHTML = message.join(""); + this.appendRow(row); +}; + +//************************************************************************************************* + +function appendText(object, html) +{ + html.push(escapeHTML(objectToString(object))); +}; + +function getTimestamp() +{ + var now = new Date(); + var ms = "" + (now.getMilliseconds() / 1000).toFixed(3); + ms = ms.substr(2); + + return now.toLocaleTimeString() + "." + ms; +}; + +//************************************************************************************************* + +var HTMLtoEntity = +{ + "<": "<", + ">": ">", + "&": "&", + "'": "'", + '"': """ +}; + +function replaceChars(ch) +{ + return HTMLtoEntity[ch]; +}; + +function escapeHTML(value) +{ + return (value+"").replace(/[<>&"']/g, replaceChars); +}; + +//************************************************************************************************* + +function objectToString(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +}).apply(FBL.FBTrace); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// If application isn't in trace mode, the FBTrace panel won't be loaded +if (!Env.Options.enableTrace) return; + +// ************************************************************************************************ +// FBTrace Module + +Firebug.Trace = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Trace") : null; + }, + + clear: function() + { + this.getPanel().panelNode.innerHTML = ""; + } +}); + +Firebug.registerModule(Firebug.Trace); + + +// ************************************************************************************************ +// FBTrace Panel + +function TracePanel(){}; + +TracePanel.prototype = extend(Firebug.Panel, +{ + name: "Trace", + title: "Trace", + + options: { + hasToolButtons: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.clearButton = new Button({ + caption: "Clear", + title: "Clear FBTrace logs", + owner: Firebug.Trace, + onClick: Firebug.Trace.clear + }); + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + this.clearButton.initialize(); + } + +}); + +Firebug.registerPanel(TracePanel); + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; + +var parentPanelMap = {}; + + +var registerModule = Firebug.registerModule; +var registerPanel = Firebug.registerPanel; + +// ************************************************************************************************ +append(Firebug, +{ + extend: function(fn) + { + if (Firebug.chrome && Firebug.chrome.addPanel) + { + var namespace = ns(fn); + fn.call(namespace, FBL); + } + else + { + setTimeout(function(){Firebug.extend(fn);},100); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + registerModule.apply(Firebug, arguments); + + modules.push.apply(modules, arguments); + + dispatch(modules, "initialize", []); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + registerPanel.apply(Firebug, arguments); + + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + // TODO: xxxpedro investigate why Dev Panel throws an error + if (panelType.prototype.name == "Dev") continue; + + panelTypeMap[panelType.prototype.name] = arguments[i]; + + var parentPanelName = panelType.prototype.parentPanel; + if (parentPanelName) + { + parentPanelMap[parentPanelName] = 1; + } + else + { + var panelName = panelType.prototype.name; + var chrome = Firebug.chrome; + chrome.addPanel(panelName); + + // tab click handler + var onTabClick = function onTabClick() + { + chrome.selectPanel(panelName); + return false; + }; + + chrome.addController([chrome.panelMap[panelName].tabNode, "mousedown", onTabClick]); + } + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + } + +}); + + + + +// ************************************************************************************************ +}}); + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +FirebugChrome.Skin = +{ + CSS: '.collapsed{display:none;}[collapsed="true"]{display:none;}#fbCSS{padding:0 !important;}.cssPropDisable{float:left;display:block;width:2em;cursor:default;}.infoTip{z-index:2147483647;position:fixed;padding:2px 3px;border:1px solid #CBE087;background:LightYellow;font-family:Monaco,monospace;color:#000000;display:none;white-space:nowrap;pointer-events:none;}.infoTip[active="true"]{display:block;}.infoTipLoading{width:16px;height:16px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif) no-repeat;}.infoTipImageBox{font-size:11px;min-width:100px;text-align:center;}.infoTipCaption{font-size:11px;font:Monaco,monospace;}.infoTipLoading > .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) no-repeat !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;}#fbPanelBarBox{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}', + HTML: '
       
       
      >>>
      2 errors' +}; + +// ************************************************************************************************ +}}); + +// ************************************************************************************************ +FBL.initialize(); +// ************************************************************************************************ + +})(); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite-debug.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite-debug.js new file mode 100755 index 0000000..41c7d58 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite-debug.js @@ -0,0 +1,29624 @@ +(function(){ + +/*!************************************************************* + * + * Firebug Lite 1.3.2 + * + * Copyright (c) 2007, Parakey Inc. + * Released under BSD license. + * More information: http://getfirebug.com/firebuglite + * + **************************************************************/ + +/*! + * CSS selectors powered by: + * + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ + +/** @namespace describe lib */ +var FBL = {}; + +/** @name ns @namespace */ + +( /** @scope ns-lib @this FBL */ function() { +// ************************************************************************************************ + +// ************************************************************************************************ +// Constants + +var productionDir = "http://getfirebug.com/releases/lite/"; +var bookmarkletVersion = 4; + +// ************************************************************************************************ + +var reNotWhitespace = /[^\s]/; +var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; + +// Globals +this.reJavascript = /\s*javascript:\s*(.*)/; +this.reChrome = /chrome:\/\/([^\/]*)\//; +this.reFile = /file:\/\/([^\/]*)\//; + + +// ************************************************************************************************ +// properties + +var userAgent = navigator.userAgent.toLowerCase(); +this.isFirefox = /firefox/.test(userAgent); +this.isOpera = /opera/.test(userAgent); +this.isSafari = /webkit/.test(userAgent); +this.isIE = /msie/.test(userAgent) && !/opera/.test(userAgent); +this.isIE6 = /msie 6/i.test(navigator.appVersion); +this.browserVersion = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]; +this.isIElt8 = this.isIE && (this.browserVersion-0 < 8); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.NS = null; +this.pixelsPerInch = null; + + +// ************************************************************************************************ +// Namespaces + +var namespaces = []; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.ns = function(fn) +{ + var ns = {}; + namespaces.push(fn, ns); + return ns; +}; + +var FBTrace = null; + +this.initialize = function() +{ + // Firebug Lite is already running in persistent mode so we just quit + if (window.firebug && firebug.firebuglite || window.console && console.firebuglite) + return; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize environment + + // point the FBTrace object to the local variable + if (FBL.FBTrace) + FBTrace = FBL.FBTrace; + else + FBTrace = FBL.FBTrace = {}; + + FBL.Ajax.initialize(); + + // check if the actual window is a persisted chrome context + var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object"; + + // chrome context of the persistent application + if (isChromeContext) + { + // TODO: xxxpedro persist - make a better synchronization + sharedEnv = window.Firebug.SharedEnv; + delete window.Firebug.SharedEnv; + + FBL.Env = sharedEnv; + FBL.Env.isChromeContext = true; + FBTrace.messageQueue = FBL.Env.traceMessageQueue; + } + // non-persistent application + else + { + FBL.NS = document.documentElement.namespaceURI; + FBL.Env.browser = window; + FBL.Env.destroy = destroyEnvironment; + + if (document.documentElement.getAttribute("debug") == "true") + FBL.Env.Options.startOpened = true; + + // find the URL location of the loaded application + findLocation(); + + // TODO: get preferences here... + var prefs = eval("(" + FBL.readCookie("FirebugLite") + ")"); + if (prefs) + { + FBL.Env.Options.startOpened = prefs.startOpened; + FBL.Env.Options.enableTrace = prefs.enableTrace; + FBL.Env.Options.enablePersistent = prefs.enablePersistent; + FBL.Env.Options.disableXHRListener = prefs.disableXHRListener; + } + + if (FBL.isFirefox && + typeof FBL.Env.browser.console == "object" && + FBL.Env.browser.console.firebug && + FBL.Env.Options.disableWhenFirebugActive) + return; + } + + // exposes the FBL to the global namespace when in debug mode + if (FBL.Env.isDebugMode) + { + FBL.Env.browser.FBL = FBL; + } + + // check browser compatibilities + this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat"; + this.isIEQuiksMode = this.isIE && this.isQuiksMode; + this.isIEStantandMode = this.isIE && !this.isQuiksMode; + + this.noFixedPosition = this.isIE6 || this.isIEQuiksMode; + + // after creating/synchronizing the environment, initialize the FBTrace module + if (FBL.Env.Options.enableTrace) FBTrace.initialize(); + + if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize namespaces + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN"); + + for (var i = 0; i < namespaces.length; i += 2) + { + var fn = namespaces[i]; + var ns = namespaces[i+1]; + fn.apply(ns); + } + + if (FBTrace.DBG_INITIALIZE) { + FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END"); + FBTrace.sysout("FBL waitForDocument", "waiting document load"); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // finish environment initialization + + FBL.Firebug.loadPrefs(prefs); + + if (FBL.Env.Options.enablePersistent) + { + // TODO: xxxpedro persist - make a better synchronization + if (isChromeContext) + { + FBL.FirebugChrome.clone(FBL.Env.FirebugChrome); + } + else + { + FBL.Env.FirebugChrome = FBL.FirebugChrome; + FBL.Env.traceMessageQueue = FBTrace.messageQueue; + } + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // wait document load + + waitForDocument(); +}; + +var waitForDocument = function waitForDocument() +{ + // document.body not available in XML+XSL documents in Firefox + var doc = FBL.Env.browser.document; + var body = doc.getElementsByTagName("body")[0]; + + if (body) + { + calculatePixelsPerInch(doc, body); + onDocumentLoad(); + } + else + setTimeout(waitForDocument, 50); +}; + +var onDocumentLoad = function onDocumentLoad() +{ + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded"); + + // fix IE6 problem with cache of background images, causing a lot of flickering + if (FBL.isIE6) + fixIE6BackgroundImageCache(); + + // chrome context of the persistent application + if (FBL.Env.Options.enablePersistent && FBL.Env.isChromeContext) + { + // finally, start the application in the chrome context + FBL.Firebug.initialize(); + + // if is not development mode, remove the shared environment cache object + // used to synchronize the both persistent contexts + if (!FBL.Env.isDevelopmentMode) + { + sharedEnv.destroy(); + sharedEnv = null; + } + } + // non-persistent application + else + { + FBL.FirebugChrome.create(); + } +}; + +// ************************************************************************************************ +// Env + +var sharedEnv; + +this.Env = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env Options (will be transported to Firebug options) + Options: + { + saveCookies: false, + + saveWindowPosition: false, + saveCommandLineHistory: false, + + startOpened: false, + startInNewWindow: false, + showIconWhenHidden: true, + + overrideConsole: true, + ignoreFirebugElements: true, + disableWhenFirebugActive: true, + + disableXHRListener: false, + + enableTrace: false, + enablePersistent: false + + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Library location + Location: + { + sourceDir: null, + baseDir: null, + skinDir: null, + skin: null, + app: null + }, + + skin: "xp", + useLocalSkin: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env states + isDevelopmentMode: false, + isDebugMode: false, + isChromeContext: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env references + browser: null, + chrome: null +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var destroyEnvironment = function destroyEnvironment() +{ + setTimeout(function() + { + FBL = null; + }, 100); +}; + +// ************************************************************************************************ +// Library location + +var findLocation = function findLocation() +{ + var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/; + + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = document; + + // Firebug Lite 1.3.0 bookmarklet identification + var script = doc.getElementById("FirebugLite"); + + if (script) + { + file = reFirebugFile.exec(script.src); + + var version = script.getAttribute("FirebugLite"); + var number = version ? parseInt(version) : 0; + + if (!version || !number || number < bookmarkletVersion) + { + FBL.Env.bookmarkletOutdated = true; + } + } + else + { + for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++) + { + var file = null; + if ( si.nodeName.toLowerCase() == "script" && (file = reFirebugFile.exec(si.src)) ) + { + script = si; + break; + } + } + } + + if (script) + script.firebugIgnore = true; + + if (file) + { + var fileName = file[1]; + var fileOptions = file[2]; + + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; + + } + // relative path + else + { + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(location.href)[1]; + + // "../some/path" + if (backDir) + { + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; + if (FBL.Env.isChromeExtension) + { + path = productionDir; + FBL.Env.bookmarkletOutdated = false; + script = {innerHTML: "{showIconWhenHidden:false}"}; + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + var Env = FBL.Env; + + // Always use the local skin when running in the same domain + // See Issue 3554: Firebug Lite should use local images when loaded locally + Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0; + + // detecting development and debug modes via file name + if (fileName == "firebug-lite-dev.js") + { + Env.isDevelopmentMode = true; + Env.isDebugMode = true; + } + else if (fileName == "firebug-lite-debug.js") + { + Env.isDebugMode = true; + } + + // process the + if (Env.browser.document.documentElement.getAttribute("debug") == "true") + { + Env.Options.startOpened = true; + } + + // process the Script URL Options + if (fileOptions) + { + var options = fileOptions.split(","); + + for (var i = 0, length = options.length; i < length; i++) + { + var option = options[i]; + var name, value; + + if (option.indexOf("=") != -1) + { + var parts = option.split("="); + name = parts[0]; + value = eval(unescape(parts[1])); + } + else + { + name = option; + value = true; + } + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Script JSON Options + var innerOptions = FBL.trim(script.innerHTML); + if (innerOptions) + { + var innerOptionsObject = eval("(" + innerOptions + ")"); + + for (var name in innerOptionsObject) + { + var value = innerOptionsObject[name]; + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } + } + } + + // process the Debug Mode + if (Env.isDebugMode) + { + Env.Options.startOpened = true; + Env.Options.enableTrace = true; + Env.Options.disableWhenFirebugActive = false; + } + + var loc = Env.Location; + var isProductionRelease = path.indexOf(productionDir) != -1; + + loc.sourceDir = path; + loc.baseDir = path.substr(0, path.length - m[1].length - 1); + loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/"; + loc.skin = loc.skinDir + "firebug.html"; + loc.app = path + fileName; + } + else + { + throw new Error("Firebug Error: Library path not found"); + } +}; + +// ************************************************************************************************ +// Basics + +this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }; +}; + +this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args); +{ + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, args); }; +}; + +this.extend = function(l, r) +{ + var newOb = {}; + for (var n in l) + newOb[n] = l[n]; + for (var n in r) + newOb[n] = r[n]; + return newOb; +}; + +this.descend = function(prototypeParent, childProperties) +{ + function protoSetter() {}; + protoSetter.prototype = prototypeParent; + var newOb = new protoSetter(); + for (var n in childProperties) + newOb[n] = childProperties[n]; + return newOb; +}; + +this.append = function(l, r) +{ + for (var n in r) + l[n] = r[n]; + + return l; +}; + +this.keys = function(map) // At least sometimes the keys will be on user-level window objects +{ + var keys = []; + try + { + for (var name in map) // enumeration is safe + keys.push(name); // name is string, safe + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + } + + return keys; // return is safe +}; + +this.values = function(map) +{ + var values = []; + try + { + for (var name in map) + { + try + { + values.push(map[name]); + } + catch (exc) + { + // Sometimes we get exceptions trying to access properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + } + } + catch (exc) + { + // Sometimes we get exceptions trying to iterate properties + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.values FAILED ", exc); + } + + return values; +}; + +this.remove = function(list, item) +{ + for (var i = 0; i < list.length; ++i) + { + if (list[i] == item) + { + list.splice(i, 1); + break; + } + } +}; + +this.sliceArray = function(array, index) +{ + var slice = []; + for (var i = index; i < array.length; ++i) + slice.push(array[i]); + + return slice; +}; + +function cloneArray(array, fn) +{ + var newArray = []; + + if (fn) + for (var i = 0; i < array.length; ++i) + newArray.push(fn(array[i])); + else + for (var i = 0; i < array.length; ++i) + newArray.push(array[i]); + + return newArray; +} + +function extendArray(array, array2) +{ + var newArray = []; + newArray.push.apply(newArray, array); + newArray.push.apply(newArray, array2); + return newArray; +} + +this.extendArray = extendArray; +this.cloneArray = cloneArray; + +function arrayInsert(array, index, other) +{ + for (var i = 0; i < other.length; ++i) + array.splice(i+index, 0, other[i]); + + return array; +} + +// ************************************************************************************************ + +this.createStyleSheet = function(doc, url) +{ + //TODO: xxxpedro + //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + var style = this.createElement("link"); + style.setAttribute("charset","utf-8"); + style.firebugIgnore = true; + style.setAttribute("rel", "stylesheet"); + style.setAttribute("type", "text/css"); + style.setAttribute("href", url); + + //TODO: xxxpedro + //style.innerHTML = this.getResource(url); + return style; +}; + +this.addStyleSheet = function(doc, style) +{ + var heads = doc.getElementsByTagName("head"); + if (heads.length) + heads[0].appendChild(style); + else + doc.documentElement.appendChild(style); +}; + +this.appendStylesheet = function(doc, uri) +{ + // Make sure the stylesheet is not appended twice. + if (this.$(uri, doc)) + return; + + var styleSheet = this.createStyleSheet(doc, uri); + styleSheet.setAttribute("id", uri); + this.addStyleSheet(doc, styleSheet); +}; + +this.addScript = function(doc, id, src) +{ + var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script"); + element.setAttribute("type", "text/javascript"); + element.setAttribute("id", id); + if (!FBTrace.DBG_CONSOLE) + FBL.unwrapObject(element).firebugIgnore = true; + + element.innerHTML = src; + if (doc.documentElement) + doc.documentElement.appendChild(element); + else + { + // See issue 1079, the svg test case gives this error + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.addScript doc has no documentElement:", doc); + } + return element; +}; + + +// ************************************************************************************************ + +this.getStyle = this.isIE ? + function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : + function(el, name) + { + return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + }; + + +// ************************************************************************************************ +// Whitespace and Entity conversions + +var entityConversionLists = this.entityConversionLists = { + normal : { + whitespace : { + '\t' : '\u200c\u2192', + '\n' : '\u200c\u00b6', + '\r' : '\u200c\u00ac', + ' ' : '\u200c\u00b7' + } + }, + reverse : { + whitespace : { + ' ' : '\t', + ' ' : '\n', + '\u200c\u2192' : '\t', + '\u200c\u00b6' : '\n', + '\u200c\u00ac' : '\r', + '\u200c\u00b7' : ' ' + } + } +}; + +var normal = entityConversionLists.normal, + reverse = entityConversionLists.reverse; + +function addEntityMapToList(ccode, entity) +{ + var lists = Array.prototype.slice.call(arguments, 2), + len = lists.length, + ch = String.fromCharCode(ccode); + for (var i = 0; i < len; i++) + { + var list = lists[i]; + normal[list]=normal[list] || {}; + normal[list][ch] = '&' + entity + ';'; + reverse[list]=reverse[list] || {}; + reverse[list]['&' + entity + ';'] = ch; + } +}; + +var e = addEntityMapToList, + white = 'whitespace', + text = 'text', + attr = 'attributes', + css = 'css', + editor = 'editor'; + +e(0x0022, 'quot', attr, css); +e(0x0026, 'amp', attr, text, css); +e(0x0027, 'apos', css); +e(0x003c, 'lt', attr, text, css); +e(0x003e, 'gt', attr, text, css); +e(0xa9, 'copy', text, editor); +e(0xae, 'reg', text, editor); +e(0x2122, 'trade', text, editor); + +// See http://en.wikipedia.org/wiki/Dash +e(0x2012, '#8210', attr, text, editor); // figure dash +e(0x2013, 'ndash', attr, text, editor); // en dash +e(0x2014, 'mdash', attr, text, editor); // em dash +e(0x2015, '#8213', attr, text, editor); // horizontal bar + +e(0x00a0, 'nbsp', attr, text, white, editor); +e(0x2002, 'ensp', attr, text, white, editor); +e(0x2003, 'emsp', attr, text, white, editor); +e(0x2009, 'thinsp', attr, text, white, editor); +e(0x200c, 'zwnj', attr, text, white, editor); +e(0x200d, 'zwj', attr, text, white, editor); +e(0x200e, 'lrm', attr, text, white, editor); +e(0x200f, 'rlm', attr, text, white, editor); +e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP) + +//************************************************************************************************ +// Entity escaping + +var entityConversionRegexes = { + normal : {}, + reverse : {} + }; + +var escapeEntitiesRegEx = { + normal : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('([' + chars.join('') + '])', 'gm'); + }, + reverse : function(list) + { + var chars = []; + for ( var ch in list) + { + chars.push(ch); + } + return new RegExp('(' + chars.join('|') + ')', 'gm'); + } +}; + +function getEscapeRegexp(direction, lists) +{ + var name = '', re; + var groups = [].concat(lists); + for (i = 0; i < groups.length; i++) + { + name += groups[i].group; + } + re = entityConversionRegexes[direction][name]; + if (!re) + { + var list = {}; + if (groups.length > 1) + { + for ( var i = 0; i < groups.length; i++) + { + var aList = entityConversionLists[direction][groups[i].group]; + for ( var item in aList) + list[item] = aList[item]; + } + } else if (groups.length==1) + { + list = entityConversionLists[direction][groups[0].group]; // faster for special case + } else { + list = {}; // perhaps should print out an error here? + } + re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list); + } + return re; +}; + +function createSimpleEscape(name, direction) +{ + return function(value) + { + var list = entityConversionLists[direction][name]; + return String(value).replace( + getEscapeRegexp(direction, { + group : name, + list : list + }), + function(ch) + { + return list[ch]; + } + ); + }; +}; + +function escapeGroupsForEntities(str, lists) +{ + lists = [].concat(lists); + var re = getEscapeRegexp('normal', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list, last = ''; + if (!len) + return [ { + str : String(str), + group : '', + name : '' + } ]; + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.normal[list.group][cur]; + // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space + // r = ' '; + if (r) + { + results[ri] = { + 'str' : r, + 'class' : list['class'], + 'extra' : list.extra[cur] ? list['class'] + + list.extra[cur] : '' + }; + break; + } + } + // last=cur; + if (!r) + results[ri] = { + 'str' : cur, + 'class' : '', + 'extra' : '' + }; + ri++; + } + return results; +}; + +this.escapeGroupsForEntities = escapeGroupsForEntities; + + +function unescapeEntities(str, lists) +{ + var re = getEscapeRegexp('reverse', lists), + split = String(str).split(re), + len = split.length, + results = [], + cur, r, i, ri = 0, l, list; + if (!len) + return str; + lists = [].concat(lists); + for (i = 0; i < len; i++) + { + cur = split[i]; + if (cur == '') + continue; + for (l = 0; l < lists.length; l++) + { + list = lists[l]; + r = entityConversionLists.reverse[list.group][cur]; + if (r) + { + results[ri] = r; + break; + } + } + if (!r) + results[ri] = cur; + ri++; + } + return results.join('') || ''; +}; + + +// ************************************************************************************************ +// String escaping + +var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal'); +var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal'); +var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal'); +var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal'); + +// deprecated compatibility functions +//this.deprecateEscapeHTML = createSimpleEscape('text', 'normal'); +//this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse'); +//this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML); +//this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML); + +var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); + +var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); + +this.unescapeForTextNode = function(str) +{ + if (Firebug.showTextNodesWithWhitespace) + str = unescapeWhitespace(str); + if (!Firebug.showTextNodesWithEntities) + str = escapeForElementAttribute(str); + return str; +}; + +this.escapeNewLines = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); +}; + +this.stripNewLines = function(value) +{ + return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; +}; + +this.escapeJS = function(value) +{ + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); +}; + +function escapeHTMLAttribute(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "&": + return "&"; + case "'": + return apos; + case '"': + return quot; + } + return "?"; + }; + var apos = "'", quot = """, around = '"'; + if( value.indexOf('"') == -1 ) { + quot = '"'; + apos = "'"; + } else if( value.indexOf("'") == -1 ) { + quot = '"'; + around = "'"; + } + return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; +} + + +function escapeHTML(value) +{ + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); +} + +this.escapeHTML = escapeHTML; + +this.cropString = function(text, limit) +{ + text = text + ""; + + if (!limit) + var halfLimit = 50; + else + var halfLimit = limit / 2; + + if (text.length > limit) + return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); + else + return this.escapeNewLines(text); +}; + +this.isWhitespace = function(text) +{ + return !reNotWhitespace.exec(text); +}; + +this.splitLines = function(text) +{ + var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; + var lines; + if (text.match) + { + lines = text.match(reSplitLines2); + } + else + { + var str = text+""; + lines = str.match(reSplitLines2); + } + lines.pop(); + return lines; +}; + + +// ************************************************************************************************ + +this.safeToString = function(ob) +{ + if (this.isIE) + return ob + ""; + + try + { + if (ob && "toString" in ob && typeof ob.toString == "function") + return ob.toString(); + } + catch (exc) + { + // xxxpedro it is not safe to use ob+""? + return ob + ""; + ///return "[an object with no toString() function]"; + } +}; + +// ************************************************************************************************ + +this.hasProperties = function(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + return false; +}; + +// ************************************************************************************************ +// String Util + +var reTrim = /^\s+|\s+$/g; +this.trim = function(s) +{ + return s.replace(reTrim, ""); +}; + + +// ************************************************************************************************ +// Empty + +this.emptyFn = function(){}; + + + +// ************************************************************************************************ +// Visibility + +this.isVisible = function(elt) +{ + /* + if (elt instanceof XULElement) + { + //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); + return (!elt.hidden && !elt.collapsed); + } + /**/ + + return this.getStyle(elt, "visibility") != "hidden" && + ( elt.offsetWidth > 0 || elt.offsetHeight > 0 + || elt.tagName in invisibleTags + || elt.namespaceURI == "http://www.w3.org/2000/svg" + || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" ); +}; + +this.collapse = function(elt, collapsed) +{ + // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector, + // but it is causing a bug (the element disappears when you set the "collapsed" + // attribute, but it doesn't appear when you remove the attribute. So, for those + // cases, we need to use the class attribute. + if (this.isIElt8) + { + if (collapsed) + this.setClass(elt, "collapsed"); + else + this.removeClass(elt, "collapsed"); + } + else + elt.setAttribute("collapsed", collapsed ? "true" : "false"); +}; + +this.obscure = function(elt, obscured) +{ + if (obscured) + this.setClass(elt, "obscured"); + else + this.removeClass(elt, "obscured"); +}; + +this.hide = function(elt, hidden) +{ + elt.style.visibility = hidden ? "hidden" : "visible"; +}; + +this.clearNode = function(node) +{ + var nodeName = " " + node.nodeName.toLowerCase() + " "; + var ignoreTags = " table tbody thead tfoot th tr td "; + + // IE can't use innerHTML of table elements + if (this.isIE && ignoreTags.indexOf(nodeName) != -1) + this.eraseNode(node); + else + node.innerHTML = ""; +}; + +this.eraseNode = function(node) +{ + while (node.lastChild) + node.removeChild(node.lastChild); +}; + +// ************************************************************************************************ +// Window iteration + +this.iterateWindows = function(win, handler) +{ + if (!win || !win.document) + return; + + handler(win); + + if (win == top || !win.frames) return; // XXXjjb hack for chromeBug + + for (var i = 0; i < win.frames.length; ++i) + { + var subWin = win.frames[i]; + if (subWin != win) + this.iterateWindows(subWin, handler); + } +}; + +this.getRootWindow = function(win) +{ + for (; win; win = win.parent) + { + if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) + return win; + } + return null; +}; + +// ************************************************************************************************ +// Graphics + +this.getClientOffset = function(elt) +{ + var addOffset = function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + + var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, ""); + + if (elt.offsetLeft) + coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth); + if (elt.offsetTop) + coords.y += elt.offsetTop + parseInt(style.borderTopWidth); + + if (p) + { + if (p.nodeType == 1) + addOffset(p, coords, view); + } + else + { + var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + if (otherView.frameElement) + addOffset(otherView.frameElement, coords, otherView); + } + }; + + var isIE = this.isIE; + var coords = {x: 0, y: 0}; + if (elt) + { + var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; + addOffset(elt, coords, view); + } + + return coords; +}; + +this.getViewOffset = function(elt, singleFrame) +{ + function addOffset(elt, coords, view) + { + var p = elt.offsetParent; + coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); + coords.y += elt.offsetTop - (p ? p.scrollTop : 0); + + if (p) + { + if (p.nodeType == 1) + { + var parentStyle = view.getComputedStyle(p, ""); + if (parentStyle.position != "static") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + + if (p.localName == "TABLE") + { + coords.x += parseInt(parentStyle.paddingLeft); + coords.y += parseInt(parentStyle.paddingTop); + } + else if (p.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.marginLeft); + coords.y += parseInt(style.marginTop); + } + } + else if (p.localName == "BODY") + { + coords.x += parseInt(parentStyle.borderLeftWidth); + coords.y += parseInt(parentStyle.borderTopWidth); + } + + var parent = elt.parentNode; + while (p != parent) + { + coords.x -= parent.scrollLeft; + coords.y -= parent.scrollTop; + parent = parent.parentNode; + } + addOffset(p, coords, view); + } + } + else + { + if (elt.localName == "BODY") + { + var style = view.getComputedStyle(elt, ""); + coords.x += parseInt(style.borderLeftWidth); + coords.y += parseInt(style.borderTopWidth); + + var htmlStyle = view.getComputedStyle(elt.parentNode, ""); + coords.x -= parseInt(htmlStyle.paddingLeft); + coords.y -= parseInt(htmlStyle.paddingTop); + } + + if (elt.scrollLeft) + coords.x += elt.scrollLeft; + if (elt.scrollTop) + coords.y += elt.scrollTop; + + var win = elt.ownerDocument.defaultView; + if (win && (!singleFrame && win.frameElement)) + addOffset(win.frameElement, coords, win); + } + + } + + var coords = {x: 0, y: 0}; + if (elt) + addOffset(elt, coords, elt.ownerDocument.defaultView); + + return coords; +}; + +this.getLTRBWH = function(elt) +{ + var bcrect, + dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; + + if (elt) + { + bcrect = elt.getBoundingClientRect(); + dims.left = bcrect.left; + dims.top = bcrect.top; + dims.right = bcrect.right; + dims.bottom = bcrect.bottom; + + if(bcrect.width) + { + dims.width = bcrect.width; + dims.height = bcrect.height; + } + else + { + dims.width = dims.right - dims.left; + dims.height = dims.bottom - dims.top; + } + } + return dims; +}; + +this.applyBodyOffsets = function(elt, clientRect) +{ + var od = elt.ownerDocument; + if (!od.body) + return clientRect; + + var style = od.defaultView.getComputedStyle(od.body, null); + + var pos = style.getPropertyValue('position'); + if(pos === 'absolute' || pos === 'relative') + { + var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0; + var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0; + var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0; + var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0; + var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0; + var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0; + + var offsetX = borderLeft + paddingLeft + marginLeft; + var offsetY = borderTop + paddingTop + marginTop; + + clientRect.left -= offsetX; + clientRect.top -= offsetY; + clientRect.right -= offsetX; + clientRect.bottom -= offsetY; + } + + return clientRect; +}; + +this.getOffsetSize = function(elt) +{ + return {width: elt.offsetWidth, height: elt.offsetHeight}; +}; + +this.getOverflowParent = function(element) +{ + for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) + { + if (scrollParent.scrollHeight > scrollParent.offsetHeight) + return scrollParent; + } +}; + +this.isScrolledToBottom = function(element) +{ + var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight; + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom); + return onBottom; +}; + +this.scrollToBottom = function(element) +{ + element.scrollTop = element.scrollHeight; + + if (FBTrace.DBG_CONSOLE) + { + FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); + if (element.scrollHeight == element.offsetHeight) + FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element); + } + + return (element.scrollTop == element.scrollHeight); +}; + +this.move = function(element, x, y) +{ + element.style.left = x + "px"; + element.style.top = y + "px"; +}; + +this.resize = function(element, w, h) +{ + element.style.width = w + "px"; + element.style.height = h + "px"; +}; + +this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} +{ + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var split = (scrollBox.clientHeight/2); + var centerY = offset.y - split; + scrollBox.scrollTop = centerY; + topSpace = split; + bottomSpace = split - element.offsetHeight; + } + + return {before: Math.round((topSpace/element.offsetHeight) + 0.5), + after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; +}; + +this.scrollIntoCenterView = function(element, scrollBox, notX, notY) +{ + if (!element) + return; + + if (!scrollBox) + scrollBox = this.getOverflowParent(element); + + if (!scrollBox) + return; + + var offset = this.getClientOffset(element); + + if (!notY) + { + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); + + if (topSpace < 0 || bottomSpace < 0) + { + var centerY = offset.y - (scrollBox.clientHeight/2); + scrollBox.scrollTop = centerY; + } + } + + if (!notX) + { + var leftSpace = offset.x - scrollBox.scrollLeft; + var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) + - (offset.x + element.clientWidth); + + if (leftSpace < 0 || rightSpace < 0) + { + var centerX = offset.x - (scrollBox.clientWidth/2); + scrollBox.scrollLeft = centerX; + } + } + if (FBTrace.DBG_SOURCEFILES) + FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); +}; + + +// ************************************************************************************************ +// CSS + +var cssKeywordMap = null; +var cssPropNames = null; +var cssColorNames = null; +var imageRules = null; + +this.getCSSKeywordsByProperty = function(propName) +{ + if (!cssKeywordMap) + { + cssKeywordMap = {}; + + for (var name in this.cssInfo) + { + var list = []; + + var types = this.cssInfo[name]; + for (var i = 0; i < types.length; ++i) + { + var keywords = this.cssKeywords[types[i]]; + if (keywords) + list.push.apply(list, keywords); + } + + cssKeywordMap[name] = list; + } + } + + return propName in cssKeywordMap ? cssKeywordMap[propName] : []; +}; + +this.getCSSPropertyNames = function() +{ + if (!cssPropNames) + { + cssPropNames = []; + + for (var name in this.cssInfo) + cssPropNames.push(name); + } + + return cssPropNames; +}; + +this.isColorKeyword = function(keyword) +{ + if (keyword == "transparent") + return false; + + if (!cssColorNames) + { + cssColorNames = []; + + var colors = this.cssKeywords["color"]; + for (var i = 0; i < colors.length; ++i) + cssColorNames.push(colors[i].toLowerCase()); + + var systemColors = this.cssKeywords["systemColor"]; + for (var i = 0; i < systemColors.length; ++i) + cssColorNames.push(systemColors[i].toLowerCase()); + } + + return cssColorNames.indexOf ? // Array.indexOf is not available in IE + cssColorNames.indexOf(keyword.toLowerCase()) != -1 : + (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; +}; + +this.isImageRule = function(rule) +{ + if (!imageRules) + { + imageRules = []; + + for (var i in this.cssInfo) + { + var r = i.toLowerCase(); + var suffix = "image"; + if (r.match(suffix + "$") == suffix || r == "background") + imageRules.push(r); + } + } + + return imageRules.indexOf ? // Array.indexOf is not available in IE + imageRules.indexOf(rule.toLowerCase()) != -1 : + (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; +}; + +this.copyTextStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.fontFamily = style.fontFamily; + + // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE + // returns wrong computed styles for inherited properties (like font-*) + // + // Also would be good to create a FBL.getStyle() + toNode.style.fontSize = style.fontSize; + toNode.style.fontWeight = style.fontWeight; + toNode.style.fontStyle = style.fontStyle; + + return style; + } +}; + +this.copyBoxStyles = function(fromNode, toNode, style) +{ + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) + { + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + + toNode.style.marginTop = style.marginTop; + toNode.style.marginRight = style.marginRight; + toNode.style.marginBottom = style.marginBottom; + toNode.style.marginLeft = style.marginLeft; + toNode.style.borderTopWidth = style.borderTopWidth; + toNode.style.borderRightWidth = style.borderRightWidth; + toNode.style.borderBottomWidth = style.borderBottomWidth; + toNode.style.borderLeftWidth = style.borderLeftWidth; + + return style; + } +}; + +this.readBoxStyles = function(style) +{ + var styleNames = { + "margin-top": "marginTop", "margin-right": "marginRight", + "margin-left": "marginLeft", "margin-bottom": "marginBottom", + "border-top-width": "borderTop", "border-right-width": "borderRight", + "border-left-width": "borderLeft", "border-bottom-width": "borderBottom", + "padding-top": "paddingTop", "padding-right": "paddingRight", + "padding-left": "paddingLeft", "padding-bottom": "paddingBottom", + "z-index": "zIndex" + }; + + var styles = {}; + for (var styleName in styleNames) + styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0; + if (FBTrace.DBG_INSPECT) + FBTrace.sysout("readBoxStyles ", styles); + return styles; +}; + +this.getBoxFromStyles = function(style, element) +{ + var args = this.readBoxStyles(style); + args.width = element.offsetWidth + - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight); + args.height = element.offsetHeight + - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom); + return args; +}; + +this.getElementCSSSelector = function(element) +{ + var label = element.localName.toLowerCase(); + if (element.id) + label += "#" + element.id; + if (element.hasAttribute("class")) + label += "." + element.getAttribute("class").split(" ")[0]; + + return label; +}; + +this.getURLForStyleSheet= function(styleSheet) +{ + //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null. + return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL); +}; + +this.getDocumentForStyleSheet = function(styleSheet) +{ + while (styleSheet.parentStyleSheet && !styleSheet.ownerNode) + { + styleSheet = styleSheet.parentStyleSheet; + } + if (styleSheet.ownerNode) + return styleSheet.ownerNode.ownerDocument; +}; + +/** + * Retrieves the instance number for a given style sheet. The instance number + * is sheet's index within the set of all other sheets whose URL is the same. + */ +this.getInstanceForStyleSheet = function(styleSheet, ownerDocument) +{ + // System URLs are always unique (or at least we are making this assumption) + if (FBL.isSystemStyleSheet(styleSheet)) + return 0; + + // ownerDocument is an optional hint for performance + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument); + ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet); + + var ret = 0, + styleSheets = ownerDocument.styleSheets, + href = styleSheet.href; + for (var i = 0; i < styleSheets.length; i++) + { + var curSheet = styleSheets[i]; + if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode))); + if (curSheet == styleSheet) + break; + if (curSheet.href == href) + ret++; + } + return ret; +}; + +// ************************************************************************************************ +// HTML and XML Serialization + + +var getElementType = this.getElementType = function(node) +{ + if (isElementXUL(node)) + return 'xul'; + else if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else if (isElementXHTML(node)) + return 'xhtml'; + else if (isElementHTML(node)) + return 'html'; +} + +var getElementSimpleType = this.getElementSimpleType = function(node) +{ + if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else + return 'html'; +} + +var isElementHTML = this.isElementHTML = function(node) +{ + return node.nodeName == node.nodeName.toUpperCase(); +} + +var isElementXHTML = this.isElementXHTML = function(node) +{ + return node.nodeName == node.nodeName.toLowerCase(); +} + +var isElementMathML = this.isElementMathML = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; +} + +var isElementSVG = this.isElementSVG = function(node) +{ + return node.namespaceURI == 'http://www.w3.org/2000/svg'; +} + +var isElementXUL = this.isElementXUL = function(node) +{ + return node instanceof XULElement; +} + +this.isSelfClosing = function(element) +{ + if (isElementSVG(element) || isElementMathML(element)) + return true; + var tag = element.localName.toLowerCase(); + return (this.selfClosingTags.hasOwnProperty(tag)); +}; + +this.getElementHTML = function(element) +{ + var self=this; + function toHTML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + html.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + html.push('>'); + + var pureText=true; + for (var child = element.firstChild; child; child = child.nextSibling) + pureText=pureText && (child.nodeType == Node.TEXT_NODE); + + if (pureText) + html.push(escapeForHtmlEditor(elt.textContent)); + else { + for (var child = elt.firstChild; child; child = child.nextSibling) + toHTML(child); + } + + html.push(''); + } + else if (isElementSVG(elt) || isElementMathML(elt)) + { + html.push('/>'); + } + else if (self.isSelfClosing(elt)) + { + html.push((isElementXHTML(elt))?'/>':'>'); + } + else + { + html.push('>'); + } + } + else if (elt.nodeType == Node.TEXT_NODE) + html.push(escapeForTextNode(elt.textContent)); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + html.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + html.push(''); + } + + var html = []; + toHTML(element); + return html.join(""); +}; + +this.getElementXML = function(element) +{ + function toXML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; + + xml.push('<', elt.nodeName.toLowerCase()); + + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; + + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + + xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } + + if (elt.firstChild) + { + xml.push('>'); + + for (var child = elt.firstChild; child; child = child.nextSibling) + toXML(child); + + xml.push(''); + } + else + xml.push('/>'); + } + else if (elt.nodeType == Node.TEXT_NODE) + xml.push(elt.nodeValue); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + xml.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + xml.push(''); + } + + var xml = []; + toXML(element); + return xml.join(""); +}; + + +// ************************************************************************************************ +// CSS classes + +this.hasClass = function(node, name) // className, className, ... +{ + // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments? + // this function can be optimized a lot if assumed 2 arguments only, + // which seems to be what happens 99% of the time + if (arguments.length == 2) + return (' '+node.className+' ').indexOf(' '+name+' ') != -1; + + if (!node || node.nodeType != 1) + return false; + else + { + for (var i=1; i= 0) + { + var size = name.length; + node.className = node.className.substr(0,index-1) + node.className.substr(index+size); + } + } +}; + +this.toggleClass = function(elt, name) +{ + if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1) + ///if (this.hasClass(elt, name)) + this.removeClass(elt, name); + else + this.setClass(elt, name); +}; + +this.setClassTimed = function(elt, name, context, timeout) +{ + if (!timeout) + timeout = 1300; + + if (elt.__setClassTimeout) + context.clearTimeout(elt.__setClassTimeout); + else + this.setClass(elt, name); + + elt.__setClassTimeout = context.setTimeout(function() + { + delete elt.__setClassTimeout; + + FBL.removeClass(elt, name); + }, timeout); +}; + +this.cancelClassTimed = function(elt, name, context) +{ + if (elt.__setClassTimeout) + { + FBL.removeClass(elt, name); + context.clearTimeout(elt.__setClassTimeout); + delete elt.__setClassTimeout; + } +}; + + +// ************************************************************************************************ +// DOM queries + +this.$ = function(id, doc) +{ + if (doc) + return doc.getElementById(id); + else + { + return FBL.Firebug.chrome.document.getElementById(id); + } +}; + +this.$$ = function(selector, doc) +{ + if (doc || !FBL.Firebug.chrome) + return FBL.Firebug.Selector(selector, doc); + else + { + return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document); + } +}; + +this.getChildByClass = function(node) // ,classname, classname, classname... +{ + for (var i = 1; i < arguments.length; ++i) + { + var className = arguments[i]; + var child = node.firstChild; + node = null; + for (; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + { + node = child; + break; + } + } + } + + return node; +}; + +this.getAncestorByClass = function(node, className) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (this.hasClass(parent, className)) + return parent; + } + + return null; +}; + + +this.getElementsByClass = function(node, className) +{ + var result = []; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + result.push(child); + } + + return result; +}; + +this.getElementByClass = function(node, className) // className, className, ... +{ + var args = cloneArray(arguments); args.splice(0, 1); + for (var child = node.firstChild; child; child = child.nextSibling) + { + var args1 = cloneArray(args); args1.unshift(child); + if (FBL.hasClass.apply(null, args1)) + return child; + else + { + var found = FBL.getElementByClass.apply(null, args1); + if (found) + return found; + } + } + + return null; +}; + +this.isAncestor = function(node, potentialAncestor) +{ + for (var parent = node; parent; parent = parent.parentNode) + { + if (parent == potentialAncestor) + return true; + } + + return false; +}; + +this.getNextElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.nextSibling; + + return node; +}; + +this.getPreviousElement = function(node) +{ + while (node && node.nodeType != 1) + node = node.previousSibling; + + return node; +}; + +this.getBody = function(doc) +{ + if (doc.body) + return doc.body; + + var body = doc.getElementsByTagName("body")[0]; + if (body) + return body; + + return doc.firstChild; // For non-HTML docs +}; + +this.findNextDown = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (criteria(child)) + return child; + + var next = this.findNextDown(child, criteria); + if (next) + return next; + } +}; + +this.findPreviousUp = function(node, criteria) +{ + if (!node) + return null; + + for (var child = node.lastChild; child; child = child.previousSibling) + { + var next = this.findPreviousUp(child, criteria); + if (next) + return next; + + if (criteria(child)) + return child; + } +}; + +this.findNext = function(node, criteria, upOnly, maxRoot) +{ + if (!node) + return null; + + if (!upOnly) + { + var next = this.findNextDown(node, criteria); + if (next) + return next; + } + + for (var sib = node.nextSibling; sib; sib = sib.nextSibling) + { + if (criteria(sib)) + return sib; + + var next = this.findNextDown(sib, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + return this.findNext(node.parentNode, criteria, true); +}; + +this.findPrevious = function(node, criteria, downOnly, maxRoot) +{ + if (!node) + return null; + + for (var sib = node.previousSibling; sib; sib = sib.previousSibling) + { + var prev = this.findPreviousUp(sib, criteria); + if (prev) + return prev; + + if (criteria(sib)) + return sib; + } + + if (!downOnly) + { + var next = this.findPreviousUp(node, criteria); + if (next) + return next; + } + + if (node.parentNode && node.parentNode != maxRoot) + { + if (criteria(node.parentNode)) + return node.parentNode; + + return this.findPrevious(node.parentNode, criteria, true); + } +}; + +this.getNextByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findNext(root, iter); +}; + +this.getPreviousByClass = function(root, state) +{ + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findPrevious(root, iter); +}; + +this.isElement = function(o) +{ + try { + return o && this.instanceOf(o, "Element"); + } + catch (ex) { + return false; + } +}; + + +// ************************************************************************************************ +// DOM Modification + +// TODO: xxxpedro use doc fragments in Context API +var appendFragment = null; + +this.appendInnerHTML = function(element, html, referenceElement) +{ + // if undefined, we must convert it to null otherwise it will throw an error in IE + // when executing element.insertBefore(firstChild, referenceElement) + referenceElement = referenceElement || null; + + var doc = element.ownerDocument; + + // doc.createRange not available in IE + if (doc.createRange) + { + var range = doc.createRange(); // a helper object + range.selectNodeContents(element); // the environment to interpret the html + + var fragment = range.createContextualFragment(html); // parse + var firstChild = fragment.firstChild; + element.insertBefore(fragment, referenceElement); + } + else + { + if (!appendFragment || appendFragment.ownerDocument != doc) + appendFragment = doc.createDocumentFragment(); + + var div = doc.createElement("div"); + div.innerHTML = html; + + var firstChild = div.firstChild; + while (div.firstChild) + appendFragment.appendChild(div.firstChild); + + element.insertBefore(appendFragment, referenceElement); + + div = null; + } + + return firstChild; +}; + + +// ************************************************************************************************ +// DOM creation + +this.createElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = properties.document || FBL.Firebug.chrome.document; + + var element = doc.createElement(tagName); + + for(var name in properties) + { + if (name != "document") + { + element[name] = properties[name]; + } + } + + return element; +}; + +this.createGlobalElement = function(tagName, properties) +{ + properties = properties || {}; + var doc = FBL.Env.browser.document; + + var element = this.NS && doc.createElementNS ? + doc.createElementNS(FBL.NS, tagName) : + doc.createElement(tagName); + + for(var name in properties) + { + var propname = name; + if (FBL.isIE && name == "class") propname = "className"; + + if (name != "document") + { + element.setAttribute(propname, properties[name]); + } + } + + return element; +}; + +//************************************************************************************************ + +this.safeGetWindowLocation = function(window) +{ + try + { + if (window) + { + if (window.closed) + return "(window.closed)"; + if ("location" in window) + return window.location+""; + else + return "(no window.location)"; + } + else + return "(no context.window)"; + } + catch(exc) + { + if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS) + FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc); + FBTrace.sysout("TabContext.getWindowLocation failed window:", window); + return "(getWindowLocation: "+exc+")"; + } +}; + +// ************************************************************************************************ +// Events + +this.isLeftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && // others + this.noKeyModifiers(event); +}; + +this.isMiddleClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 4 : // IE "click" and "dblclick" button model + event.button == 1) && + this.noKeyModifiers(event); +}; + +this.isRightClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 2 : // IE "click" and "dblclick" button model + event.button == 2) && + this.noKeyModifiers(event); +}; + +this.noKeyModifiers = function(event) +{ + return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey; +}; + +this.isControlClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isControl(event); +}; + +this.isShiftClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isShift(event); +}; + +this.isControl = function(event) +{ + return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; +}; + +this.isAlt = function(event) +{ + return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey; +}; + +this.isAltClick = function(event) +{ + return (this.isIE && event.type != "click" && event.type != "dblclick" ? + event.button == 1 : // IE "click" and "dblclick" button model + event.button == 0) && + this.isAlt(event); +}; + +this.isControlShift = function(event) +{ + return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey; +}; + +this.isShift = function(event) +{ + return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey; +}; + +this.addEvent = function(object, name, handler, useCapture) +{ + if (object.addEventListener) + object.addEventListener(name, handler, useCapture); + else + object.attachEvent("on"+name, handler); +}; + +this.removeEvent = function(object, name, handler, useCapture) +{ + try + { + if (object.removeEventListener) + object.removeEventListener(name, handler, useCapture); + else + object.detachEvent("on"+name, handler); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("FBL.removeEvent error: ", object, name); + } +}; + +this.cancelEvent = function(e, preventDefault) +{ + if (!e) return; + + if (preventDefault) + { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + } + + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.addGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.addEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.addEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.addEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +this.removeGlobalEvent = function(name, handler) +{ + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; + + this.removeEvent(doc, name, handler); + + if (this.Firebug.chrome.type == "popup") + this.removeEvent(this.Firebug.chrome.document, name, handler); + + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.removeEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.dispatch = function(listeners, name, args) +{ + if (!listeners) return; + + try + {/**/ + if (typeof listeners.length != "undefined") + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); + + for (var i = 0; i < listeners.length; ++i) + { + var listener = listeners[i]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + else + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object"); + + for (var prop in listeners) + { + var listener = listeners[prop]; + if ( listener[name] ) + listener[name].apply(listener, args); + } + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout(" Exception in lib.dispatch "+ name, exc); + //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener); + } + } + /**/ +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var disableTextSelectionHandler = function(event) +{ + FBL.cancelEvent(event, true); + + return false; +}; + +this.disableTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.addEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.addEvent(e, "mousedown", disableTextSelectionHandler); + } + + e.style.cursor = "default"; +}; + +this.restoreTextSelection = function(e) +{ + if (typeof e.onselectstart != "undefined") // IE + this.removeEvent(e, "selectstart", disableTextSelectionHandler); + + else // others + { + e.style.cssText = "cursor: default;"; + + // canceling the event in FF will prevent the menu popups to close when clicking over + // text-disabled elements + if (!this.isFirefox) + this.removeEvent(e, "mousedown", disableTextSelectionHandler); + } +}; + +// ************************************************************************************************ +// DOM Events + +var eventTypes = +{ + composition: [ + "composition", + "compositionstart", + "compositionend" ], + contextmenu: [ + "contextmenu" ], + drag: [ + "dragenter", + "dragover", + "dragexit", + "dragdrop", + "draggesture" ], + focus: [ + "focus", + "blur" ], + form: [ + "submit", + "reset", + "change", + "select", + "input" ], + key: [ + "keydown", + "keyup", + "keypress" ], + load: [ + "load", + "beforeunload", + "unload", + "abort", + "error" ], + mouse: [ + "mousedown", + "mouseup", + "click", + "dblclick", + "mouseover", + "mouseout", + "mousemove" ], + mutation: [ + "DOMSubtreeModified", + "DOMNodeInserted", + "DOMNodeRemoved", + "DOMNodeRemovedFromDocument", + "DOMNodeInsertedIntoDocument", + "DOMAttrModified", + "DOMCharacterDataModified" ], + paint: [ + "paint", + "resize", + "scroll" ], + scroll: [ + "overflow", + "underflow", + "overflowchanged" ], + text: [ + "text" ], + ui: [ + "DOMActivate", + "DOMFocusIn", + "DOMFocusOut" ], + xul: [ + "popupshowing", + "popupshown", + "popuphiding", + "popuphidden", + "close", + "command", + "broadcast", + "commandupdate" ] +}; + +this.getEventFamily = function(eventType) +{ + if (!this.families) + { + this.families = {}; + + for (var family in eventTypes) + { + var types = eventTypes[family]; + for (var i = 0; i < types.length; ++i) + this.families[types[i]] = family; + } + } + + return this.families[eventType]; +}; + + +// ************************************************************************************************ +// URLs + +this.getFileName = function(url) +{ + var split = this.splitURLBase(url); + return split.name; +}; + +this.splitURLBase = function(url) +{ + if (this.isDataURL(url)) + return this.splitDataURL(url); + return this.splitURLTrue(url); +}; + +this.splitDataURL = function(url) +{ + var mark = url.indexOf(':', 3); + if (mark != 4) + return false; // the first 5 chars must be 'data:' + + var point = url.indexOf(',', mark+1); + if (point < mark) + return false; // syntax error + + var props = { encodedContent: url.substr(point+1) }; + + var metadataBuffer = url.substr(mark+1, point); + var metadata = metadataBuffer.split(';'); + for (var i = 0; i < metadata.length; i++) + { + var nv = metadata[i].split('='); + if (nv.length == 2) + props[nv[0]] = nv[1]; + } + + // Additional Firebug-specific properties + if (props.hasOwnProperty('fileName')) + { + var caller_URL = decodeURIComponent(props['fileName']); + var caller_split = this.splitURLTrue(caller_URL); + + if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval() + { + props['path'] = caller_split.path; + props['line'] = props['baseLineNumber']; + var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + props['name'] = 'eval->'+hint; + } + else + { + props['name'] = caller_split.name; + props['path'] = caller_split.path; + } + } + else + { + if (!props.hasOwnProperty('path')) + props['path'] = "data:"; + if (!props.hasOwnProperty('name')) + props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); + } + + return props; +}; + +this.splitURLTrue = function(url) +{ + var m = reSplitFile.exec(url); + if (!m) + return {name: url, path: url}; + else if (!m[2]) + return {path: m[1], name: m[1]}; + else + return {path: m[1], name: m[2]+m[3]}; +}; + +this.getFileExtension = function(url) +{ + if (!url) + return null; + + // Remove query string from the URL if any. + var queryString = url.indexOf("?"); + if (queryString != -1) + url = url.substr(0, queryString); + + // Now get the file extension. + var lastDot = url.lastIndexOf("."); + return url.substr(lastDot+1); +}; + +this.isSystemURL = function(url) +{ + if (!url) return true; + if (url.length == 0) return true; + if (url[0] == 'h') return false; + if (url.substr(0, 9) == "resource:") + return true; + else if (url.substr(0, 16) == "chrome://firebug") + return true; + else if (url == "XPCSafeJSObjectWrapper.cpp") + return true; + else if (url.substr(0, 6) == "about:") + return true; + else if (url.indexOf("firebug-service.js") != -1) + return true; + else + return false; +}; + +this.isSystemPage = function(win) +{ + try + { + var doc = win.document; + if (!doc) + return false; + + // Detect pages for pretty printed XML + if ((doc.styleSheets.length && doc.styleSheets[0].href + == "chrome://global/content/xml/XMLPrettyPrint.css") + || (doc.styleSheets.length > 1 && doc.styleSheets[1].href + == "chrome://browser/skin/feeds/subscribe.css")) + return true; + + return FBL.isSystemURL(win.location.href); + } + catch (exc) + { + // Sometimes documents just aren't ready to be manipulated here, but don't let that + // gum up the works + ERROR("tabWatcher.isSystemPage document not ready:"+ exc); + return false; + } +}; + +this.isSystemStyleSheet = function(sheet) +{ + var href = sheet && sheet.href; + return href && FBL.isSystemURL(href); +}; + +this.getURIHost = function(uri) +{ + try + { + if (uri) + return uri.host; + else + return ""; + } + catch (exc) + { + return ""; + } +}; + +this.isLocalURL = function(url) +{ + if (url.substr(0, 5) == "file:") + return true; + else if (url.substr(0, 8) == "wyciwyg:") + return true; + else + return false; +}; + +this.isDataURL = function(url) +{ + return (url && url.substr(0,5) == "data:"); +}; + +this.getLocalPath = function(url) +{ + if (this.isLocalURL(url)) + { + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var file = fileHandler.getFileFromURLSpec(url); + return file.path; + } +}; + +this.getURLFromLocalFile = function(file) +{ + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var URL = fileHandler.getURLSpecFromFile(file); + return URL; +}; + +this.getDataURLForContent = function(content, url) +{ + // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10, + var uri = "data:text/html;"; + uri += "fileName="+encodeURIComponent(url)+ ","; + uri += encodeURIComponent(content); + return uri; +}, + +this.getDomain = function(url) +{ + var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url); + return m ? m[1] : ""; +}; + +this.getURLPath = function(url) +{ + var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); + return m ? m[1] : ""; +}; + +this.getPrettyDomain = function(url) +{ + var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); + return m ? m[2] : ""; +}; + +this.absoluteURL = function(url, baseURL) +{ + return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g"); +}; + +this.absoluteURLWithDots = function(url, baseURL) +{ + if (url[0] == "?") + return baseURL + url; + + var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/; + var m = reURL.exec(url); + if (m) + return url; + + var m = reURL.exec(baseURL); + if (!m) + return ""; + + var head = m[1]; + var tail = m[3]; + if (url.substr(0, 2) == "//") + return m[2] + url; + else if (url[0] == "/") + { + return head + url; + } + else if (tail[tail.length-1] == "/") + return baseURL + url; + else + { + var parts = tail.split("/"); + return head + parts.slice(0, parts.length-1).join("/") + "/" + url; + } +}; + +this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome +{ + if (!url) + return ""; + // Replace one or more characters that are not forward-slash followed by /.., by space. + if (url.length < 255) // guard against monsters. + { + // Replace one or more characters that are not forward-slash followed by /.., by space. + url = url.replace(/[^\/]+\/\.\.\//, "", "g"); + // Issue 1496, avoid # + url = url.replace(/#.*/,""); + // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they + // don't match up with the URLs we get back from the DOM + url = url.replace(/file:\/([^\/])/g, "file:///$1"); + if (url.indexOf('chrome:')==0) + { + var m = reChromeCase.exec(url); // 1 is package name, 2 is path + if (m) + { + url = "chrome://"+m[1].toLowerCase()+"/"+m[2]; + } + } + } + return url; +}; + +this.denormalizeURL = function(url) +{ + return url.replace(/file:\/\/\//g, "file:/"); +}; + +this.parseURLParams = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedText(search); +}; + +this.parseURLEncodedText = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: ""}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +// TODO: xxxpedro lib. why loops in domplate are requiring array in parameters +// as in response/request headers and get/post parameters in Net module? +this.parseURLParamsArray = function(url) +{ + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; + + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); + + if (!search) + return []; + + return this.parseURLEncodedTextArray(search); +}; + +this.parseURLEncodedTextArray = function(text) +{ + var maxValueLength = 25000; + + var params = []; + + // Unescape '+' characters that are used to encode a space. + // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + text = text.replace(/\+/g, " "); + + var args = text.split("&"); + for (var i = 0; i < args.length; ++i) + { + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); + + params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: [""]}); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } + } + } + + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); + + return params; +}; + +this.reEncodeURL = function(file, text) +{ + var lines = text.split("\n"); + var params = this.parseURLEncodedText(lines[lines.length-1]); + + var args = []; + for (var i = 0; i < params.length; ++i) + args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); + + var url = file.href; + url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); + + return url; +}; + +this.getResource = function(aURL) +{ + try + { + var channel=ioService.newChannel(aURL,null,null); + var input=channel.open(); + return FBL.readFromStream(input); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getResource FAILS for "+aURL, e); + } +}; + +this.parseJSONString = function(jsonString, originURL) +{ + // See if this is a Prototype style *-secure request. + var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/); + var matches = regex.exec(jsonString); + + if (matches) + { + jsonString = matches[1]; + + if (jsonString[0] == "\\" && jsonString[1] == "n") + jsonString = jsonString.substr(2); + + if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") + jsonString = jsonString.substr(0, jsonString.length-2); + } + + if (jsonString.indexOf("&&&START&&&")) + { + regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); + matches = regex.exec(jsonString); + if (matches) + jsonString = matches[1]; + } + + // throw on the extra parentheses + jsonString = "(" + jsonString + ")"; + + ///var s = Components.utils.Sandbox(originURL); + var jsonObject = null; + + try + { + ///jsonObject = Components.utils.evalInSandbox(jsonString, s); + + //jsonObject = Firebug.context.eval(jsonString); + jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;}); + } + catch(e) + { + /*** + if (e.message.indexOf("is not defined")) + { + var parts = e.message.split(" "); + s[parts[0]] = function(str){ return str; }; + try { + jsonObject = Components.utils.evalInSandbox(jsonString, s); + } catch(ex) { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + } + } + else + {/**/ + if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); + return null; + ///} + } + + return jsonObject; +}; + +// ************************************************************************************************ + +this.objectToString = function(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +// Input Caret Position + +this.setSelectionRange = function(input, start, length) +{ + if (input.createTextRange) + { + var range = input.createTextRange(); + range.moveStart("character", start); + range.moveEnd("character", length - input.value.length); + range.select(); + } + else if (input.setSelectionRange) + { + input.setSelectionRange(start, length); + input.focus(); + } +}; + +// ************************************************************************************************ +// Input Selection Start / Caret Position + +this.getInputSelectionStart = function(input) +{ + if (document.selection) + { + var range = input.ownerDocument.selection.createRange(); + var text = range.text; + + //console.log("range", range.text); + + // if there is a selection, find the start position + if (text) + { + return input.value.indexOf(text); + } + // if there is no selection, find the caret position + else + { + range.moveStart("character", -input.value.length); + + return range.text.length; + } + } + else if (typeof input.selectionStart != "undefined") + return input.selectionStart; + + return 0; +}; + +// ************************************************************************************************ +// Opera Tab Fix + +function onOperaTabBlur(e) +{ + if (this.lastKey == 9) + this.focus(); +}; + +function onOperaTabKeyDown(e) +{ + this.lastKey = e.keyCode; +}; + +function onOperaTabFocus(e) +{ + this.lastKey = null; +}; + +this.fixOperaTabKey = function(el) +{ + el.onfocus = onOperaTabFocus; + el.onblur = onOperaTabBlur; + el.onkeydown = onOperaTabKeyDown; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.Property = function(object, name) +{ + this.object = object; + this.name = name; + + this.getObject = function() + { + return object[name]; + }; +}; + +this.ErrorCopy = function(message) +{ + this.message = message; +}; + +function EventCopy(event) +{ + // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to + // represent them long term in the inspector. + for (var name in event) + { + try { + this[name] = event[name]; + } catch (exc) { } + } +} + +this.EventCopy = EventCopy; + + +// ************************************************************************************************ +// Type Checking + +var toString = Object.prototype.toString; +var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; + +this.isArray = function(object) { + return toString.call(object) === '[object Array]'; +}; + +this.isFunction = function(object) { + if (!object) return false; + + return toString.call(object) === "[object Function]" || + this.isIE && typeof object != "string" && reFunction.test(""+object); +}; + + +// ************************************************************************************************ +// Instance Checking + +this.instanceOf = function(object, className) +{ + if (!object || typeof object != "object") + return false; + + // Try to use the native instanceof operator. We can only use it when we know + // exactly the window where the object is located at + if (object.ownerDocument) + { + // find the correct window of the object + var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow; + + // if the class is accessible in the window, uses the native instanceof operator + // if the instanceof evaluates to "true" we can assume it is a instance, but if it + // evaluates to "false" we must continue with the duck type detection below because + // the native object may be extended, thus breaking the instanceof result + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (className in win && object instanceof win[className]) + return true; + } + // If the object doesn't have the ownerDocument property, we'll try to look at + // the current context's window + else + { + // TODO: xxxpedro context + // Since we're not using yet a Firebug.context, we'll just use the top window + // (browser) as a reference + var win = Firebug.browser.window; + if (className in win) + return object instanceof win[className]; + } + + // get the duck type model from the cache + var cache = instanceCheckMap[className]; + if (!cache) + return false; + + // starts the hacky duck type detection + for(var n in cache) + { + var obj = cache[n]; + var type = typeof obj; + obj = type == "object" ? obj : [obj]; + + for(var name in obj) + { + // avoid problems with extended native objects + // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended + if (!obj.hasOwnProperty(name)) + continue; + + var value = obj[name]; + + if( n == "property" && !(value in object) || + n == "method" && !this.isFunction(object[value]) || + n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) + return false; + } + } + + return true; +}; + +var instanceCheckMap = +{ + // DuckTypeCheck: + // { + // property: ["window", "document"], + // method: "setTimeout", + // value: {nodeType: 1} + // }, + + Window: + { + property: ["window", "document"], + method: "setTimeout" + }, + + Document: + { + property: ["body", "cookie"], + method: "getElementById" + }, + + Node: + { + property: "ownerDocument", + method: "appendChild" + }, + + Element: + { + property: "tagName", + value: {nodeType: 1} + }, + + Location: + { + property: ["hostname", "protocol"], + method: "assign" + }, + + HTMLImageElement: + { + property: "useMap", + value: + { + nodeType: 1, + tagName: "img" + } + }, + + HTMLAnchorElement: + { + property: "hreflang", + value: + { + nodeType: 1, + tagName: "a" + } + }, + + HTMLInputElement: + { + property: "form", + value: + { + nodeType: 1, + tagName: "input" + } + }, + + HTMLButtonElement: + { + // ? + }, + + HTMLFormElement: + { + method: "submit", + value: + { + nodeType: 1, + tagName: "form" + } + }, + + HTMLBodyElement: + { + + }, + + HTMLHtmlElement: + { + + }, + + CSSStyleRule: + { + property: ["selectorText", "style"] + } + +}; + + +// ************************************************************************************************ +// DOM Constants + +/* + +Problems: + + - IE does not have window.Node, window.Element, etc + - for (var name in Node.prototype) return nothing on FF + +*/ + + +var domMemberMap2 = {}; + +var domMemberMap2Sandbox = null; + +var getDomMemberMap2 = function(name) +{ + if (!domMemberMap2Sandbox) + { + var doc = Firebug.chrome.document; + var frame = doc.createElement("iframe"); + + frame.id = "FirebugSandbox"; + frame.style.display = "none"; + frame.src = "about:blank"; + + doc.body.appendChild(frame); + + domMemberMap2Sandbox = frame.window || frame.contentWindow; + } + + var props = []; + + //var object = domMemberMap2Sandbox[name]; + //object = object.prototype || object; + + var object = null; + + if (name == "Window") + object = domMemberMap2Sandbox.window; + + else if (name == "Document") + object = domMemberMap2Sandbox.document; + + else if (name == "HTMLScriptElement") + object = domMemberMap2Sandbox.document.createElement("script"); + + else if (name == "HTMLAnchorElement") + object = domMemberMap2Sandbox.document.createElement("a"); + + else if (name.indexOf("Element") != -1) + { + object = domMemberMap2Sandbox.document.createElement("div"); + } + + if (object) + { + //object = object.prototype || object; + + //props = 'addEventListener,document,location,navigator,window'.split(','); + + for (var n in object) + props.push(n); + } + /**/ + + return props; + return extendArray(props, domMemberMap[name]); +}; + +// xxxpedro experimental get DOM members +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + FBL.domMemberCache = domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = getDomMemberMap2(name); + var cache = domMemberCache[name] = {}; + + /* + if (name.indexOf("Element") != -1) + { + this.append(cache, this.getDOMMembers("Node")); + this.append(cache, this.getDOMMembers("Element")); + } + /**/ + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument")) + { return domMemberCache.Document; } + else if (this.instanceOf(object, "Location")) + { return domMemberCache.Location; } + else if (this.instanceOf(object, "HTMLImageElement")) + { return domMemberCache.HTMLImageElement; } + else if (this.instanceOf(object, "HTMLAnchorElement")) + { return domMemberCache.HTMLAnchorElement; } + else if (this.instanceOf(object, "HTMLInputElement")) + { return domMemberCache.HTMLInputElement; } + else if (this.instanceOf(object, "HTMLButtonElement")) + { return domMemberCache.HTMLButtonElement; } + else if (this.instanceOf(object, "HTMLFormElement")) + { return domMemberCache.HTMLFormElement; } + else if (this.instanceOf(object, "HTMLBodyElement")) + { return domMemberCache.HTMLBodyElement; } + else if (this.instanceOf(object, "HTMLHtmlElement")) + { return domMemberCache.HTMLHtmlElement; } + else if (this.instanceOf(object, "HTMLScriptElement")) + { return domMemberCache.HTMLScriptElement; } + else if (this.instanceOf(object, "HTMLTableElement")) + { return domMemberCache.HTMLTableElement; } + else if (this.instanceOf(object, "HTMLTableRowElement")) + { return domMemberCache.HTMLTableRowElement; } + else if (this.instanceOf(object, "HTMLTableCellElement")) + { return domMemberCache.HTMLTableCellElement; } + else if (this.instanceOf(object, "HTMLIFrameElement")) + { return domMemberCache.HTMLIFrameElement; } + else if (this.instanceOf(object, "SVGSVGElement")) + { return domMemberCache.SVGSVGElement; } + else if (this.instanceOf(object, "SVGElement")) + { return domMemberCache.SVGElement; } + else if (this.instanceOf(object, "Element")) + { return domMemberCache.Element; } + else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection")) + { return domMemberCache.Text; } + else if (this.instanceOf(object, "Attr")) + { return domMemberCache.Attr; } + else if (this.instanceOf(object, "Node")) + { return domMemberCache.Node; } + else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy")) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getDOMMembers FAILED ", E); + + return {}; + } +}; + + +/* +this.getDOMMembers = function(object) +{ + if (!domMemberCache) + { + domMemberCache = {}; + + for (var name in domMemberMap) + { + var builtins = domMemberMap[name]; + var cache = domMemberCache[name] = {}; + + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } + + try + { + if (this.instanceOf(object, "Window")) + { return domMemberCache.Window; } + else if (object instanceof Document || object instanceof XMLDocument) + { return domMemberCache.Document; } + else if (object instanceof Location) + { return domMemberCache.Location; } + else if (object instanceof HTMLImageElement) + { return domMemberCache.HTMLImageElement; } + else if (object instanceof HTMLAnchorElement) + { return domMemberCache.HTMLAnchorElement; } + else if (object instanceof HTMLInputElement) + { return domMemberCache.HTMLInputElement; } + else if (object instanceof HTMLButtonElement) + { return domMemberCache.HTMLButtonElement; } + else if (object instanceof HTMLFormElement) + { return domMemberCache.HTMLFormElement; } + else if (object instanceof HTMLBodyElement) + { return domMemberCache.HTMLBodyElement; } + else if (object instanceof HTMLHtmlElement) + { return domMemberCache.HTMLHtmlElement; } + else if (object instanceof HTMLScriptElement) + { return domMemberCache.HTMLScriptElement; } + else if (object instanceof HTMLTableElement) + { return domMemberCache.HTMLTableElement; } + else if (object instanceof HTMLTableRowElement) + { return domMemberCache.HTMLTableRowElement; } + else if (object instanceof HTMLTableCellElement) + { return domMemberCache.HTMLTableCellElement; } + else if (object instanceof HTMLIFrameElement) + { return domMemberCache.HTMLIFrameElement; } + else if (object instanceof SVGSVGElement) + { return domMemberCache.SVGSVGElement; } + else if (object instanceof SVGElement) + { return domMemberCache.SVGElement; } + else if (object instanceof Element) + { return domMemberCache.Element; } + else if (object instanceof Text || object instanceof CDATASection) + { return domMemberCache.Text; } + else if (object instanceof Attr) + { return domMemberCache.Attr; } + else if (object instanceof Node) + { return domMemberCache.Node; } + else if (object instanceof Event || object instanceof EventCopy) + { return domMemberCache.Event; } + else + return {}; + } + catch(E) + { + return {}; + } +}; +/**/ + +this.isDOMMember = function(object, propName) +{ + var members = this.getDOMMembers(object); + return members && propName in members; +}; + +var domMemberCache = null; +var domMemberMap = {}; + +domMemberMap.Window = +[ + "document", + "frameElement", + + "innerWidth", + "innerHeight", + "outerWidth", + "outerHeight", + "screenX", + "screenY", + "pageXOffset", + "pageYOffset", + "scrollX", + "scrollY", + "scrollMaxX", + "scrollMaxY", + + "status", + "defaultStatus", + + "parent", + "opener", + "top", + "window", + "content", + "self", + + "location", + "history", + "frames", + "navigator", + "screen", + "menubar", + "toolbar", + "locationbar", + "personalbar", + "statusbar", + "directories", + "scrollbars", + "fullScreen", + "netscape", + "java", + "console", + "Components", + "controllers", + "closed", + "crypto", + "pkcs11", + + "name", + "property", + "length", + + "sessionStorage", + "globalStorage", + + "setTimeout", + "setInterval", + "clearTimeout", + "clearInterval", + "addEventListener", + "removeEventListener", + "dispatchEvent", + "getComputedStyle", + "captureEvents", + "releaseEvents", + "routeEvent", + "enableExternalCapture", + "disableExternalCapture", + "moveTo", + "moveBy", + "resizeTo", + "resizeBy", + "scroll", + "scrollTo", + "scrollBy", + "scrollByLines", + "scrollByPages", + "sizeToContent", + "setResizable", + "getSelection", + "open", + "openDialog", + "close", + "alert", + "confirm", + "prompt", + "dump", + "focus", + "blur", + "find", + "back", + "forward", + "home", + "stop", + "print", + "atob", + "btoa", + "updateCommands", + "XPCNativeWrapper", + "GeckoActiveXObject", + "applicationCache" // FF3 +]; + +domMemberMap.Location = +[ + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + + "assign", + "reload", + "replace" +]; + +domMemberMap.Node = +[ + "id", + "className", + + "nodeType", + "tagName", + "nodeName", + "localName", + "prefix", + "namespaceURI", + "nodeValue", + + "ownerDocument", + "parentNode", + "offsetParent", + "nextSibling", + "previousSibling", + "firstChild", + "lastChild", + "childNodes", + "attributes", + + "dir", + "baseURI", + "textContent", + "innerHTML", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]; + +domMemberMap.Document = extendArray(domMemberMap.Node, +[ + "documentElement", + "body", + "title", + "location", + "referrer", + "cookie", + "contentType", + "lastModified", + "characterSet", + "inputEncoding", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "strictErrorChecking", + "documentURI", + "URL", + + "defaultView", + "doctype", + "implementation", + "styleSheets", + "images", + "links", + "forms", + "anchors", + "embeds", + "plugins", + "applets", + + "width", + "height", + + "designMode", + "compatMode", + "async", + "preferredStylesheetSet", + + "alinkColor", + "linkColor", + "vlinkColor", + "bgColor", + "fgColor", + "domain", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "captureEvents", + "releaseEvents", + "routeEvent", + "clear", + "open", + "close", + "execCommand", + "execCommandShowHelp", + "getElementsByName", + "getSelection", + "queryCommandEnabled", + "queryCommandIndeterm", + "queryCommandState", + "queryCommandSupported", + "queryCommandText", + "queryCommandValue", + "write", + "writeln", + "adoptNode", + "appendChild", + "removeChild", + "renameNode", + "cloneNode", + "compareDocumentPosition", + "createAttribute", + "createAttributeNS", + "createCDATASection", + "createComment", + "createDocumentFragment", + "createElement", + "createElementNS", + "createEntityReference", + "createEvent", + "createExpression", + "createNSResolver", + "createNodeIterator", + "createProcessingInstruction", + "createRange", + "createTextNode", + "createTreeWalker", + "domConfig", + "evaluate", + "evaluateFIXptr", + "evaluateXPointer", + "getAnonymousElementByAttribute", + "getAnonymousNodes", + "addBinding", + "removeBinding", + "getBindingParent", + "getBoxObjectFor", + "setBoxObjectFor", + "getElementById", + "getElementsByTagName", + "getElementsByTagNameNS", + "hasAttributes", + "hasChildNodes", + "importNode", + "insertBefore", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "load", + "loadBindingDocument", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "normalizeDocument", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.Element = extendArray(domMemberMap.Node, +[ + "clientWidth", + "clientHeight", + "offsetLeft", + "offsetTop", + "offsetWidth", + "offsetHeight", + "scrollLeft", + "scrollTop", + "scrollWidth", + "scrollHeight", + + "style", + + "tabIndex", + "title", + "lang", + "align", + "spellcheck", + + "addEventListener", + "removeEventListener", + "dispatchEvent", + "focus", + "blur", + "cloneNode", + "appendChild", + "insertBefore", + "replaceChild", + "removeChild", + "compareDocumentPosition", + "getElementsByTagName", + "getElementsByTagNameNS", + "getAttribute", + "getAttributeNS", + "getAttributeNode", + "getAttributeNodeNS", + "setAttribute", + "setAttributeNS", + "setAttributeNode", + "setAttributeNodeNS", + "removeAttribute", + "removeAttributeNS", + "removeAttributeNode", + "hasAttribute", + "hasAttributeNS", + "hasAttributes", + "hasChildNodes", + "lookupNamespaceURI", + "lookupPrefix", + "normalize", + "isDefaultNamespace", + "isEqualNode", + "isSameNode", + "isSupported", + "getFeature", + "getUserData", + "setUserData" +]); + +domMemberMap.SVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + "href", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getPresentationAttribute", + "preserveAspectRatio" +]); + +domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element, +[ + "x", + "y", + "width", + "height", + "rx", + "ry", + "transform", + + "viewBox", + "viewport", + "currentView", + "useCurrentView", + "pixelUnitToMillimeterX", + "pixelUnitToMillimeterY", + "screenPixelToMillimeterX", + "screenPixelToMillimeterY", + "currentScale", + "currentTranslate", + "zoomAndPan", + + "ownerSVGElement", + "viewportElement", + "farthestViewportElement", + "nearestViewportElement", + "contentScriptType", + "contentStyleType", + + "getBBox", + "getCTM", + "getScreenCTM", + "getTransformToElement", + "getEnclosureList", + "getIntersectionList", + "getViewboxToViewportTransform", + "getPresentationAttribute", + "getElementById", + "checkEnclosure", + "checkIntersection", + "createSVGAngle", + "createSVGLength", + "createSVGMatrix", + "createSVGNumber", + "createSVGPoint", + "createSVGRect", + "createSVGString", + "createSVGTransform", + "createSVGTransformFromMatrix", + "deSelectAll", + "preserveAspectRatio", + "forceRedraw", + "suspendRedraw", + "unsuspendRedraw", + "unsuspendRedrawAll", + "getCurrentTime", + "setCurrentTime", + "animationsPaused", + "pauseAnimations", + "unpauseAnimations" +]); + +domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element, +[ + "src", + "naturalWidth", + "naturalHeight", + "width", + "height", + "x", + "y", + "name", + "alt", + "longDesc", + "lowsrc", + "border", + "complete", + "hspace", + "vspace", + "isMap", + "useMap" +]); + +domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element, +[ + "name", + "target", + "accessKey", + "href", + "protocol", + "host", + "hostname", + "port", + "pathname", + "search", + "hash", + "hreflang", + "coords", + "shape", + "text", + "type", + "rel", + "rev", + "charset" +]); + +domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element, +[ + "contentDocument", + "contentWindow", + "frameBorder", + "height", + "longDesc", + "marginHeight", + "marginWidth", + "name", + "scrolling", + "src", + "width" +]); + +domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "border", + "caption", + "cellPadding", + "cellSpacing", + "frame", + "rows", + "rules", + "summary", + "tBodies", + "tFoot", + "tHead", + "width", + + "createCaption", + "createTFoot", + "createTHead", + "deleteCaption", + "deleteRow", + "deleteTFoot", + "deleteTHead", + "insertRow" +]); + +domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element, +[ + "bgColor", + "cells", + "ch", + "chOff", + "rowIndex", + "sectionRowIndex", + "vAlign", + + "deleteCell", + "insertCell" +]); + +domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element, +[ + "abbr", + "axis", + "bgColor", + "cellIndex", + "ch", + "chOff", + "colSpan", + "headers", + "height", + "noWrap", + "rowSpan", + "scope", + "vAlign", + "width" + +]); + +domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element, +[ + "src" +]); + +domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element, +[ + "accessKey", + "disabled", + "form", + "name", + "type", + "value", + + "click" +]); + +domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element, +[ + "type", + "value", + "checked", + "accept", + "accessKey", + "alt", + "controllers", + "defaultChecked", + "defaultValue", + "disabled", + "form", + "maxLength", + "name", + "readOnly", + "selectionEnd", + "selectionStart", + "size", + "src", + "textLength", + "useMap", + + "click", + "select", + "setSelectionRange" +]); + +domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element, +[ + "acceptCharset", + "action", + "author", + "elements", + "encoding", + "enctype", + "entry_id", + "length", + "method", + "name", + "post", + "target", + "text", + "url", + + "reset", + "submit" +]); + +domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element, +[ + "aLink", + "background", + "bgColor", + "link", + "text", + "vLink" +]); + +domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element, +[ + "version" +]); + +domMemberMap.Text = extendArray(domMemberMap.Node, +[ + "data", + "length", + + "appendData", + "deleteData", + "insertData", + "replaceData", + "splitText", + "substringData" +]); + +domMemberMap.Attr = extendArray(domMemberMap.Node, +[ + "name", + "value", + "specified", + "ownerElement" +]); + +domMemberMap.Event = +[ + "type", + "target", + "currentTarget", + "originalTarget", + "explicitOriginalTarget", + "relatedTarget", + "rangeParent", + "rangeOffset", + "view", + + "keyCode", + "charCode", + "screenX", + "screenY", + "clientX", + "clientY", + "layerX", + "layerY", + "pageX", + "pageY", + + "detail", + "button", + "which", + "ctrlKey", + "shiftKey", + "altKey", + "metaKey", + + "eventPhase", + "timeStamp", + "bubbles", + "cancelable", + "cancelBubble", + + "isTrusted", + "isChar", + + "getPreventDefault", + "initEvent", + "initMouseEvent", + "initKeyEvent", + "initUIEvent", + "preventBubble", + "preventCapture", + "preventDefault", + "stopPropagation" +]; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.domConstantMap = +{ + "ELEMENT_NODE": 1, + "ATTRIBUTE_NODE": 1, + "TEXT_NODE": 1, + "CDATA_SECTION_NODE": 1, + "ENTITY_REFERENCE_NODE": 1, + "ENTITY_NODE": 1, + "PROCESSING_INSTRUCTION_NODE": 1, + "COMMENT_NODE": 1, + "DOCUMENT_NODE": 1, + "DOCUMENT_TYPE_NODE": 1, + "DOCUMENT_FRAGMENT_NODE": 1, + "NOTATION_NODE": 1, + + "DOCUMENT_POSITION_DISCONNECTED": 1, + "DOCUMENT_POSITION_PRECEDING": 1, + "DOCUMENT_POSITION_FOLLOWING": 1, + "DOCUMENT_POSITION_CONTAINS": 1, + "DOCUMENT_POSITION_CONTAINED_BY": 1, + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1, + + "UNKNOWN_RULE": 1, + "STYLE_RULE": 1, + "CHARSET_RULE": 1, + "IMPORT_RULE": 1, + "MEDIA_RULE": 1, + "FONT_FACE_RULE": 1, + "PAGE_RULE": 1, + + "CAPTURING_PHASE": 1, + "AT_TARGET": 1, + "BUBBLING_PHASE": 1, + + "SCROLL_PAGE_UP": 1, + "SCROLL_PAGE_DOWN": 1, + + "MOUSEUP": 1, + "MOUSEDOWN": 1, + "MOUSEOVER": 1, + "MOUSEOUT": 1, + "MOUSEMOVE": 1, + "MOUSEDRAG": 1, + "CLICK": 1, + "DBLCLICK": 1, + "KEYDOWN": 1, + "KEYUP": 1, + "KEYPRESS": 1, + "DRAGDROP": 1, + "FOCUS": 1, + "BLUR": 1, + "SELECT": 1, + "CHANGE": 1, + "RESET": 1, + "SUBMIT": 1, + "SCROLL": 1, + "LOAD": 1, + "UNLOAD": 1, + "XFER_DONE": 1, + "ABORT": 1, + "ERROR": 1, + "LOCATE": 1, + "MOVE": 1, + "RESIZE": 1, + "FORWARD": 1, + "HELP": 1, + "BACK": 1, + "TEXT": 1, + + "ALT_MASK": 1, + "CONTROL_MASK": 1, + "SHIFT_MASK": 1, + "META_MASK": 1, + + "DOM_VK_TAB": 1, + "DOM_VK_PAGE_UP": 1, + "DOM_VK_PAGE_DOWN": 1, + "DOM_VK_UP": 1, + "DOM_VK_DOWN": 1, + "DOM_VK_LEFT": 1, + "DOM_VK_RIGHT": 1, + "DOM_VK_CANCEL": 1, + "DOM_VK_HELP": 1, + "DOM_VK_BACK_SPACE": 1, + "DOM_VK_CLEAR": 1, + "DOM_VK_RETURN": 1, + "DOM_VK_ENTER": 1, + "DOM_VK_SHIFT": 1, + "DOM_VK_CONTROL": 1, + "DOM_VK_ALT": 1, + "DOM_VK_PAUSE": 1, + "DOM_VK_CAPS_LOCK": 1, + "DOM_VK_ESCAPE": 1, + "DOM_VK_SPACE": 1, + "DOM_VK_END": 1, + "DOM_VK_HOME": 1, + "DOM_VK_PRINTSCREEN": 1, + "DOM_VK_INSERT": 1, + "DOM_VK_DELETE": 1, + "DOM_VK_0": 1, + "DOM_VK_1": 1, + "DOM_VK_2": 1, + "DOM_VK_3": 1, + "DOM_VK_4": 1, + "DOM_VK_5": 1, + "DOM_VK_6": 1, + "DOM_VK_7": 1, + "DOM_VK_8": 1, + "DOM_VK_9": 1, + "DOM_VK_SEMICOLON": 1, + "DOM_VK_EQUALS": 1, + "DOM_VK_A": 1, + "DOM_VK_B": 1, + "DOM_VK_C": 1, + "DOM_VK_D": 1, + "DOM_VK_E": 1, + "DOM_VK_F": 1, + "DOM_VK_G": 1, + "DOM_VK_H": 1, + "DOM_VK_I": 1, + "DOM_VK_J": 1, + "DOM_VK_K": 1, + "DOM_VK_L": 1, + "DOM_VK_M": 1, + "DOM_VK_N": 1, + "DOM_VK_O": 1, + "DOM_VK_P": 1, + "DOM_VK_Q": 1, + "DOM_VK_R": 1, + "DOM_VK_S": 1, + "DOM_VK_T": 1, + "DOM_VK_U": 1, + "DOM_VK_V": 1, + "DOM_VK_W": 1, + "DOM_VK_X": 1, + "DOM_VK_Y": 1, + "DOM_VK_Z": 1, + "DOM_VK_CONTEXT_MENU": 1, + "DOM_VK_NUMPAD0": 1, + "DOM_VK_NUMPAD1": 1, + "DOM_VK_NUMPAD2": 1, + "DOM_VK_NUMPAD3": 1, + "DOM_VK_NUMPAD4": 1, + "DOM_VK_NUMPAD5": 1, + "DOM_VK_NUMPAD6": 1, + "DOM_VK_NUMPAD7": 1, + "DOM_VK_NUMPAD8": 1, + "DOM_VK_NUMPAD9": 1, + "DOM_VK_MULTIPLY": 1, + "DOM_VK_ADD": 1, + "DOM_VK_SEPARATOR": 1, + "DOM_VK_SUBTRACT": 1, + "DOM_VK_DECIMAL": 1, + "DOM_VK_DIVIDE": 1, + "DOM_VK_F1": 1, + "DOM_VK_F2": 1, + "DOM_VK_F3": 1, + "DOM_VK_F4": 1, + "DOM_VK_F5": 1, + "DOM_VK_F6": 1, + "DOM_VK_F7": 1, + "DOM_VK_F8": 1, + "DOM_VK_F9": 1, + "DOM_VK_F10": 1, + "DOM_VK_F11": 1, + "DOM_VK_F12": 1, + "DOM_VK_F13": 1, + "DOM_VK_F14": 1, + "DOM_VK_F15": 1, + "DOM_VK_F16": 1, + "DOM_VK_F17": 1, + "DOM_VK_F18": 1, + "DOM_VK_F19": 1, + "DOM_VK_F20": 1, + "DOM_VK_F21": 1, + "DOM_VK_F22": 1, + "DOM_VK_F23": 1, + "DOM_VK_F24": 1, + "DOM_VK_NUM_LOCK": 1, + "DOM_VK_SCROLL_LOCK": 1, + "DOM_VK_COMMA": 1, + "DOM_VK_PERIOD": 1, + "DOM_VK_SLASH": 1, + "DOM_VK_BACK_QUOTE": 1, + "DOM_VK_OPEN_BRACKET": 1, + "DOM_VK_BACK_SLASH": 1, + "DOM_VK_CLOSE_BRACKET": 1, + "DOM_VK_QUOTE": 1, + "DOM_VK_META": 1, + + "SVG_ZOOMANDPAN_DISABLE": 1, + "SVG_ZOOMANDPAN_MAGNIFY": 1, + "SVG_ZOOMANDPAN_UNKNOWN": 1 +}; + +this.cssInfo = +{ + "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"], + "background-attachment": ["bgAttachment"], + "background-color": ["color", "systemColor"], + "background-image": ["none"], + "background-position": ["bgPosition"], + "background-repeat": ["bgRepeat"], + + "border": ["borderStyle", "thickness", "color", "systemColor", "none"], + "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], + "border-collapse": ["borderCollapse"], + "border-color": ["color", "systemColor"], + "border-top-color": ["color", "systemColor"], + "border-right-color": ["color", "systemColor"], + "border-bottom-color": ["color", "systemColor"], + "border-left-color": ["color", "systemColor"], + "border-spacing": [], + "border-style": ["borderStyle"], + "border-top-style": ["borderStyle"], + "border-right-style": ["borderStyle"], + "border-bottom-style": ["borderStyle"], + "border-left-style": ["borderStyle"], + "border-width": ["thickness"], + "border-top-width": ["thickness"], + "border-right-width": ["thickness"], + "border-bottom-width": ["thickness"], + "border-left-width": ["thickness"], + + "bottom": ["auto"], + "caption-side": ["captionSide"], + "clear": ["clear", "none"], + "clip": ["auto"], + "color": ["color", "systemColor"], + "content": ["content"], + "counter-increment": ["none"], + "counter-reset": ["none"], + "cursor": ["cursor", "none"], + "direction": ["direction"], + "display": ["display", "none"], + "empty-cells": [], + "float": ["float", "none"], + "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"], + + "font-family": ["fontFamily"], + "font-size": ["fontSize"], + "font-size-adjust": [], + "font-stretch": [], + "font-style": ["fontStyle"], + "font-variant": ["fontVariant"], + "font-weight": ["fontWeight"], + + "height": ["auto"], + "left": ["auto"], + "letter-spacing": [], + "line-height": [], + + "list-style": ["listStyleType", "listStylePosition", "none"], + "list-style-image": ["none"], + "list-style-position": ["listStylePosition"], + "list-style-type": ["listStyleType", "none"], + + "margin": [], + "margin-top": [], + "margin-right": [], + "margin-bottom": [], + "margin-left": [], + + "marker-offset": ["auto"], + "min-height": ["none"], + "max-height": ["none"], + "min-width": ["none"], + "max-width": ["none"], + + "outline": ["borderStyle", "color", "systemColor", "none"], + "outline-color": ["color", "systemColor"], + "outline-style": ["borderStyle"], + "outline-width": [], + + "overflow": ["overflow", "auto"], + "overflow-x": ["overflow", "auto"], + "overflow-y": ["overflow", "auto"], + + "padding": [], + "padding-top": [], + "padding-right": [], + "padding-bottom": [], + "padding-left": [], + + "position": ["position"], + "quotes": ["none"], + "right": ["auto"], + "table-layout": ["tableLayout", "auto"], + "text-align": ["textAlign"], + "text-decoration": ["textDecoration", "none"], + "text-indent": [], + "text-shadow": [], + "text-transform": ["textTransform", "none"], + "top": ["auto"], + "unicode-bidi": [], + "vertical-align": ["verticalAlign"], + "white-space": ["whiteSpace"], + "width": ["auto"], + "word-spacing": [], + "z-index": [], + + "-moz-appearance": ["mozAppearance"], + "-moz-border-radius": [], + "-moz-border-radius-bottomleft": [], + "-moz-border-radius-bottomright": [], + "-moz-border-radius-topleft": [], + "-moz-border-radius-topright": [], + "-moz-border-top-colors": ["color", "systemColor"], + "-moz-border-right-colors": ["color", "systemColor"], + "-moz-border-bottom-colors": ["color", "systemColor"], + "-moz-border-left-colors": ["color", "systemColor"], + "-moz-box-align": ["mozBoxAlign"], + "-moz-box-direction": ["mozBoxDirection"], + "-moz-box-flex": [], + "-moz-box-ordinal-group": [], + "-moz-box-orient": ["mozBoxOrient"], + "-moz-box-pack": ["mozBoxPack"], + "-moz-box-sizing": ["mozBoxSizing"], + "-moz-opacity": [], + "-moz-user-focus": ["userFocus", "none"], + "-moz-user-input": ["userInput"], + "-moz-user-modify": [], + "-moz-user-select": ["userSelect", "none"], + "-moz-background-clip": [], + "-moz-background-inline-policy": [], + "-moz-background-origin": [], + "-moz-binding": [], + "-moz-column-count": [], + "-moz-column-gap": [], + "-moz-column-width": [], + "-moz-image-region": [] +}; + +this.inheritedStyleNames = +{ + "border-collapse": 1, + "border-spacing": 1, + "border-style": 1, + "caption-side": 1, + "color": 1, + "cursor": 1, + "direction": 1, + "empty-cells": 1, + "font": 1, + "font-family": 1, + "font-size-adjust": 1, + "font-size": 1, + "font-style": 1, + "font-variant": 1, + "font-weight": 1, + "letter-spacing": 1, + "line-height": 1, + "list-style": 1, + "list-style-image": 1, + "list-style-position": 1, + "list-style-type": 1, + "quotes": 1, + "text-align": 1, + "text-decoration": 1, + "text-indent": 1, + "text-shadow": 1, + "text-transform": 1, + "white-space": 1, + "word-spacing": 1 +}; + +this.cssKeywords = +{ + "appearance": + [ + "button", + "button-small", + "checkbox", + "checkbox-container", + "checkbox-small", + "dialog", + "listbox", + "menuitem", + "menulist", + "menulist-button", + "menulist-textfield", + "menupopup", + "progressbar", + "radio", + "radio-container", + "radio-small", + "resizer", + "scrollbar", + "scrollbarbutton-down", + "scrollbarbutton-left", + "scrollbarbutton-right", + "scrollbarbutton-up", + "scrollbartrack-horizontal", + "scrollbartrack-vertical", + "separator", + "statusbar", + "tab", + "tab-left-edge", + "tabpanels", + "textfield", + "toolbar", + "toolbarbutton", + "toolbox", + "tooltip", + "treeheadercell", + "treeheadersortarrow", + "treeitem", + "treetwisty", + "treetwistyopen", + "treeview", + "window" + ], + + "systemColor": + [ + "ActiveBorder", + "ActiveCaption", + "AppWorkspace", + "Background", + "ButtonFace", + "ButtonHighlight", + "ButtonShadow", + "ButtonText", + "CaptionText", + "GrayText", + "Highlight", + "HighlightText", + "InactiveBorder", + "InactiveCaption", + "InactiveCaptionText", + "InfoBackground", + "InfoText", + "Menu", + "MenuText", + "Scrollbar", + "ThreeDDarkShadow", + "ThreeDFace", + "ThreeDHighlight", + "ThreeDLightShadow", + "ThreeDShadow", + "Window", + "WindowFrame", + "WindowText", + "-moz-field", + "-moz-fieldtext", + "-moz-workspace", + "-moz-visitedhyperlinktext", + "-moz-use-text-color" + ], + + "color": + [ + "AliceBlue", + "AntiqueWhite", + "Aqua", + "Aquamarine", + "Azure", + "Beige", + "Bisque", + "Black", + "BlanchedAlmond", + "Blue", + "BlueViolet", + "Brown", + "BurlyWood", + "CadetBlue", + "Chartreuse", + "Chocolate", + "Coral", + "CornflowerBlue", + "Cornsilk", + "Crimson", + "Cyan", + "DarkBlue", + "DarkCyan", + "DarkGoldenRod", + "DarkGray", + "DarkGreen", + "DarkKhaki", + "DarkMagenta", + "DarkOliveGreen", + "DarkOrange", + "DarkOrchid", + "DarkRed", + "DarkSalmon", + "DarkSeaGreen", + "DarkSlateBlue", + "DarkSlateGray", + "DarkTurquoise", + "DarkViolet", + "DeepPink", + "DarkSkyBlue", + "DimGray", + "DodgerBlue", + "Feldspar", + "FireBrick", + "FloralWhite", + "ForestGreen", + "Fuchsia", + "Gainsboro", + "GhostWhite", + "Gold", + "GoldenRod", + "Gray", + "Green", + "GreenYellow", + "HoneyDew", + "HotPink", + "IndianRed", + "Indigo", + "Ivory", + "Khaki", + "Lavender", + "LavenderBlush", + "LawnGreen", + "LemonChiffon", + "LightBlue", + "LightCoral", + "LightCyan", + "LightGoldenRodYellow", + "LightGrey", + "LightGreen", + "LightPink", + "LightSalmon", + "LightSeaGreen", + "LightSkyBlue", + "LightSlateBlue", + "LightSlateGray", + "LightSteelBlue", + "LightYellow", + "Lime", + "LimeGreen", + "Linen", + "Magenta", + "Maroon", + "MediumAquaMarine", + "MediumBlue", + "MediumOrchid", + "MediumPurple", + "MediumSeaGreen", + "MediumSlateBlue", + "MediumSpringGreen", + "MediumTurquoise", + "MediumVioletRed", + "MidnightBlue", + "MintCream", + "MistyRose", + "Moccasin", + "NavajoWhite", + "Navy", + "OldLace", + "Olive", + "OliveDrab", + "Orange", + "OrangeRed", + "Orchid", + "PaleGoldenRod", + "PaleGreen", + "PaleTurquoise", + "PaleVioletRed", + "PapayaWhip", + "PeachPuff", + "Peru", + "Pink", + "Plum", + "PowderBlue", + "Purple", + "Red", + "RosyBrown", + "RoyalBlue", + "SaddleBrown", + "Salmon", + "SandyBrown", + "SeaGreen", + "SeaShell", + "Sienna", + "Silver", + "SkyBlue", + "SlateBlue", + "SlateGray", + "Snow", + "SpringGreen", + "SteelBlue", + "Tan", + "Teal", + "Thistle", + "Tomato", + "Turquoise", + "Violet", + "VioletRed", + "Wheat", + "White", + "WhiteSmoke", + "Yellow", + "YellowGreen", + "transparent", + "invert" + ], + + "auto": + [ + "auto" + ], + + "none": + [ + "none" + ], + + "captionSide": + [ + "top", + "bottom", + "left", + "right" + ], + + "clear": + [ + "left", + "right", + "both" + ], + + "cursor": + [ + "auto", + "cell", + "context-menu", + "crosshair", + "default", + "help", + "pointer", + "progress", + "move", + "e-resize", + "all-scroll", + "ne-resize", + "nw-resize", + "n-resize", + "se-resize", + "sw-resize", + "s-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "text", + "vertical-text", + "wait", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "-moz-alias", + "-moz-cell", + "-moz-copy", + "-moz-grab", + "-moz-grabbing", + "-moz-contextmenu", + "-moz-zoom-in", + "-moz-zoom-out", + "-moz-spinning" + ], + + "direction": + [ + "ltr", + "rtl" + ], + + "bgAttachment": + [ + "scroll", + "fixed" + ], + + "bgPosition": + [ + "top", + "center", + "bottom", + "left", + "right" + ], + + "bgRepeat": + [ + "repeat", + "repeat-x", + "repeat-y", + "no-repeat" + ], + + "borderStyle": + [ + "hidden", + "dotted", + "dashed", + "solid", + "double", + "groove", + "ridge", + "inset", + "outset", + "-moz-bg-inset", + "-moz-bg-outset", + "-moz-bg-solid" + ], + + "borderCollapse": + [ + "collapse", + "separate" + ], + + "overflow": + [ + "visible", + "hidden", + "scroll", + "-moz-scrollbars-horizontal", + "-moz-scrollbars-none", + "-moz-scrollbars-vertical" + ], + + "listStyleType": + [ + "disc", + "circle", + "square", + "decimal", + "decimal-leading-zero", + "lower-roman", + "upper-roman", + "lower-greek", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "hebrew", + "armenian", + "georgian", + "cjk-ideographic", + "hiragana", + "katakana", + "hiragana-iroha", + "katakana-iroha", + "inherit" + ], + + "listStylePosition": + [ + "inside", + "outside" + ], + + "content": + [ + "open-quote", + "close-quote", + "no-open-quote", + "no-close-quote", + "inherit" + ], + + "fontStyle": + [ + "normal", + "italic", + "oblique", + "inherit" + ], + + "fontVariant": + [ + "normal", + "small-caps", + "inherit" + ], + + "fontWeight": + [ + "normal", + "bold", + "bolder", + "lighter", + "inherit" + ], + + "fontSize": + [ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger" + ], + + "fontFamily": + [ + "Arial", + "Comic Sans MS", + "Georgia", + "Tahoma", + "Verdana", + "Times New Roman", + "Trebuchet MS", + "Lucida Grande", + "Helvetica", + "serif", + "sans-serif", + "cursive", + "fantasy", + "monospace", + "caption", + "icon", + "menu", + "message-box", + "small-caption", + "status-bar", + "inherit" + ], + + "display": + [ + "block", + "inline", + "inline-block", + "list-item", + "marker", + "run-in", + "compact", + "table", + "inline-table", + "table-row-group", + "table-column", + "table-column-group", + "table-header-group", + "table-footer-group", + "table-row", + "table-cell", + "table-caption", + "-moz-box", + "-moz-compact", + "-moz-deck", + "-moz-grid", + "-moz-grid-group", + "-moz-grid-line", + "-moz-groupbox", + "-moz-inline-block", + "-moz-inline-box", + "-moz-inline-grid", + "-moz-inline-stack", + "-moz-inline-table", + "-moz-marker", + "-moz-popup", + "-moz-runin", + "-moz-stack" + ], + + "position": + [ + "static", + "relative", + "absolute", + "fixed", + "inherit" + ], + + "float": + [ + "left", + "right" + ], + + "textAlign": + [ + "left", + "right", + "center", + "justify" + ], + + "tableLayout": + [ + "fixed" + ], + + "textDecoration": + [ + "underline", + "overline", + "line-through", + "blink" + ], + + "textTransform": + [ + "capitalize", + "lowercase", + "uppercase", + "inherit" + ], + + "unicodeBidi": + [ + "normal", + "embed", + "bidi-override" + ], + + "whiteSpace": + [ + "normal", + "pre", + "nowrap" + ], + + "verticalAlign": + [ + "baseline", + "sub", + "super", + "top", + "text-top", + "middle", + "bottom", + "text-bottom", + "inherit" + ], + + "thickness": + [ + "thin", + "medium", + "thick" + ], + + "userFocus": + [ + "ignore", + "normal" + ], + + "userInput": + [ + "disabled", + "enabled" + ], + + "userSelect": + [ + "normal" + ], + + "mozBoxSizing": + [ + "content-box", + "padding-box", + "border-box" + ], + + "mozBoxAlign": + [ + "start", + "center", + "end", + "baseline", + "stretch" + ], + + "mozBoxDirection": + [ + "normal", + "reverse" + ], + + "mozBoxOrient": + [ + "horizontal", + "vertical" + ], + + "mozBoxPack": + [ + "start", + "center", + "end" + ] +}; + +this.nonEditableTags = +{ + "HTML": 1, + "HEAD": 1, + "html": 1, + "head": 1 +}; + +this.innerEditableTags = +{ + "BODY": 1, + "body": 1 +}; + +this.selfClosingTags = +{ // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML + "meta": 1, + "link": 1, + "area": 1, + "base": 1, + "col": 1, + "input": 1, + "img": 1, + "br": 1, + "hr": 1, + "param":1, + "embed":1 +}; + +var invisibleTags = this.invisibleTags = +{ + "HTML": 1, + "HEAD": 1, + "TITLE": 1, + "META": 1, + "LINK": 1, + "STYLE": 1, + "SCRIPT": 1, + "NOSCRIPT": 1, + "BR": 1, + "PARAM": 1, + "COL": 1, + + "html": 1, + "head": 1, + "title": 1, + "meta": 1, + "link": 1, + "style": 1, + "script": 1, + "noscript": 1, + "br": 1, + "param": 1, + "col": 1 + /* + "window": 1, + "browser": 1, + "frame": 1, + "tabbrowser": 1, + "WINDOW": 1, + "BROWSER": 1, + "FRAME": 1, + "TABBROWSER": 1, + */ +}; + + +if (typeof KeyEvent == "undefined") { + this.KeyEvent = { + DOM_VK_CANCEL: 3, + DOM_VK_HELP: 6, + DOM_VK_BACK_SPACE: 8, + DOM_VK_TAB: 9, + DOM_VK_CLEAR: 12, + DOM_VK_RETURN: 13, + DOM_VK_ENTER: 14, + DOM_VK_SHIFT: 16, + DOM_VK_CONTROL: 17, + DOM_VK_ALT: 18, + DOM_VK_PAUSE: 19, + DOM_VK_CAPS_LOCK: 20, + DOM_VK_ESCAPE: 27, + DOM_VK_SPACE: 32, + DOM_VK_PAGE_UP: 33, + DOM_VK_PAGE_DOWN: 34, + DOM_VK_END: 35, + DOM_VK_HOME: 36, + DOM_VK_LEFT: 37, + DOM_VK_UP: 38, + DOM_VK_RIGHT: 39, + DOM_VK_DOWN: 40, + DOM_VK_PRINTSCREEN: 44, + DOM_VK_INSERT: 45, + DOM_VK_DELETE: 46, + DOM_VK_0: 48, + DOM_VK_1: 49, + DOM_VK_2: 50, + DOM_VK_3: 51, + DOM_VK_4: 52, + DOM_VK_5: 53, + DOM_VK_6: 54, + DOM_VK_7: 55, + DOM_VK_8: 56, + DOM_VK_9: 57, + DOM_VK_SEMICOLON: 59, + DOM_VK_EQUALS: 61, + DOM_VK_A: 65, + DOM_VK_B: 66, + DOM_VK_C: 67, + DOM_VK_D: 68, + DOM_VK_E: 69, + DOM_VK_F: 70, + DOM_VK_G: 71, + DOM_VK_H: 72, + DOM_VK_I: 73, + DOM_VK_J: 74, + DOM_VK_K: 75, + DOM_VK_L: 76, + DOM_VK_M: 77, + DOM_VK_N: 78, + DOM_VK_O: 79, + DOM_VK_P: 80, + DOM_VK_Q: 81, + DOM_VK_R: 82, + DOM_VK_S: 83, + DOM_VK_T: 84, + DOM_VK_U: 85, + DOM_VK_V: 86, + DOM_VK_W: 87, + DOM_VK_X: 88, + DOM_VK_Y: 89, + DOM_VK_Z: 90, + DOM_VK_CONTEXT_MENU: 93, + DOM_VK_NUMPAD0: 96, + DOM_VK_NUMPAD1: 97, + DOM_VK_NUMPAD2: 98, + DOM_VK_NUMPAD3: 99, + DOM_VK_NUMPAD4: 100, + DOM_VK_NUMPAD5: 101, + DOM_VK_NUMPAD6: 102, + DOM_VK_NUMPAD7: 103, + DOM_VK_NUMPAD8: 104, + DOM_VK_NUMPAD9: 105, + DOM_VK_MULTIPLY: 106, + DOM_VK_ADD: 107, + DOM_VK_SEPARATOR: 108, + DOM_VK_SUBTRACT: 109, + DOM_VK_DECIMAL: 110, + DOM_VK_DIVIDE: 111, + DOM_VK_F1: 112, + DOM_VK_F2: 113, + DOM_VK_F3: 114, + DOM_VK_F4: 115, + DOM_VK_F5: 116, + DOM_VK_F6: 117, + DOM_VK_F7: 118, + DOM_VK_F8: 119, + DOM_VK_F9: 120, + DOM_VK_F10: 121, + DOM_VK_F11: 122, + DOM_VK_F12: 123, + DOM_VK_F13: 124, + DOM_VK_F14: 125, + DOM_VK_F15: 126, + DOM_VK_F16: 127, + DOM_VK_F17: 128, + DOM_VK_F18: 129, + DOM_VK_F19: 130, + DOM_VK_F20: 131, + DOM_VK_F21: 132, + DOM_VK_F22: 133, + DOM_VK_F23: 134, + DOM_VK_F24: 135, + DOM_VK_NUM_LOCK: 144, + DOM_VK_SCROLL_LOCK: 145, + DOM_VK_COMMA: 188, + DOM_VK_PERIOD: 190, + DOM_VK_SLASH: 191, + DOM_VK_BACK_QUOTE: 192, + DOM_VK_OPEN_BRACKET: 219, + DOM_VK_BACK_SLASH: 220, + DOM_VK_CLOSE_BRACKET: 221, + DOM_VK_QUOTE: 222, + DOM_VK_META: 224 + }; +} + + +// ************************************************************************************************ +// Ajax + +/** + * @namespace + */ +this.Ajax = +{ + + requests: [], + transport: null, + states: ["Uninitialized","Loading","Loaded","Interactive","Complete"], + + initialize: function() + { + this.transport = this.getXHRObject(); + }, + + getXHRObject: function() + { + var xhrObj = false; + try + { + xhrObj = new XMLHttpRequest(); + } + catch(e) + { + var progid = [ + "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" + ]; + + for ( var i=0; i < progid.length; ++i ) { + try + { + xhrObj = new ActiveXObject(progid[i]); + } + catch(e) + { + continue; + } + break; + } + } + finally + { + return xhrObj; + } + }, + + + /** + * Create a AJAX request. + * + * @name request + * @param {Object} options request options + * @param {String} options.url URL to be requested + * @param {String} options.type Request type ("get" ou "post"). Default is "get". + * @param {Boolean} options.async Asynchronous flag. Default is "true". + * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text". + * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded". + * @param {Function} options.onLoading onLoading callback + * @param {Function} options.onLoaded onLoaded callback + * @param {Function} options.onInteractive onInteractive callback + * @param {Function} options.onComplete onComplete callback + * @param {Function} options.onUpdate onUpdate callback + * @param {Function} options.onSuccess onSuccess callback + * @param {Function} options.onFailure onFailure callback + */ + request: function(options) + { + // process options + var o = FBL.extend( + { + // default values + type: "get", + async: true, + dataType: "text", + contentType: "application/x-www-form-urlencoded" + }, + options || {} + ); + + this.requests.push(o); + + var s = this.getState(); + if (s == "Uninitialized" || s == "Complete" || s == "Loaded") + this.sendRequest(); + }, + + serialize: function(data) + { + var r = [""], rl = 0; + if (data) { + if (typeof data == "string") r[rl++] = data; + + else if (data.innerHTML && data.elements) { + for (var i=0,el,l=(el=data.elements).length; i < l; i++) + if (el[i].name) { + r[rl++] = encodeURIComponent(el[i].name); + r[rl++] = "="; + r[rl++] = encodeURIComponent(el[i].value); + r[rl++] = "&"; + } + + } else + for(var param in data) { + r[rl++] = encodeURIComponent(param); + r[rl++] = "="; + r[rl++] = encodeURIComponent(data[param]); + r[rl++] = "&"; + } + } + return r.join("").replace(/&$/, ""); + }, + + sendRequest: function() + { + var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; + + // open XHR object + t.open(r.type, r.url, r.async); + + //setRequestHeaders(); + + // indicates that it is a XHR request to the server + t.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // if data is being sent, sets the appropriate content-type + if (data = FBL.Ajax.serialize(r.data)) + t.setRequestHeader("Content-Type", r.contentType); + + /** @ignore */ + // onreadystatechange handler + t.onreadystatechange = function() + { + FBL.Ajax.onStateChange(r); + }; + + // send the request + t.send(data); + }, + + /** + * Handles the state change + */ + onStateChange: function(options) + { + var fn, o = options, t = this.transport; + var state = this.getState(t); + + if (fn = o["on" + state]) fn(this.getResponse(o), o); + + if (state == "Complete") + { + var success = t.status == 200, response = this.getResponse(o); + + if (fn = o["onUpdate"]) + fn(response, o); + + if (fn = o["on" + (success ? "Success" : "Failure")]) + fn(response, o); + + t.onreadystatechange = FBL.emptyFn; + + if (this.requests.length > 0) + setTimeout(this.sendRequest, 10); + } + }, + + /** + * gets the appropriate response value according the type + */ + getResponse: function(options) + { + var t = this.transport, type = options.dataType; + + if (t.status != 200) return t.statusText; + else if (type == "text") return t.responseText; + else if (type == "html") return t.responseText; + else if (type == "xml") return t.responseXML; + else if (type == "json") return eval("(" + t.responseText + ")"); + }, + + /** + * returns the current state of the XHR object + */ + getState: function() + { + return this.states[this.transport.readyState]; + } + +}; + + +// ************************************************************************************************ +// Cookie, from http://www.quirksmode.org/js/cookies.html + +this.createCookie = function(name,value,days) +{ + if ('cookie' in document) + { + if (days) + { + var date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + var expires = "; expires="+date.toGMTString(); + } + else + var expires = ""; + + document.cookie = name+"="+value+expires+"; path=/"; + } +}; + +this.readCookie = function (name) +{ + if ('cookie' in document) + { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + + for(var i=0; i < ca.length; i++) + { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + } + + return null; +}; + +this.removeCookie = function(name) +{ + this.createCookie(name, "", -1); +}; + + +// ************************************************************************************************ +// http://www.mister-pixel.com/#Content__state=is_that_simple +var fixIE6BackgroundImageCache = function(doc) +{ + doc = doc || document; + try + { + doc.execCommand("BackgroundImageCache", false, true); + } + catch(E) + { + + } +}; + +// ************************************************************************************************ +// calculatePixelsPerInch + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; + +var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body) +{ + var inch = FBL.createGlobalElement("div"); + inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;"; + body.appendChild(inch); + + FBL.pixelsPerInch = { + x: inch.offsetWidth, + y: inch.offsetHeight + }; + + body.removeChild(inch); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceLink = function(url, line, type, object, instance) +{ + this.href = url; + this.instance = instance; + this.line = line; + this.type = type; + this.object = object; +}; + +this.SourceLink.prototype = +{ + toString: function() + { + return this.href; + }, + toJSON: function() // until 3.1... + { + return "{\"href\":\""+this.href+"\", "+ + (this.line?("\"line\":"+this.line+","):"")+ + (this.type?(" \"type\":\""+this.type+"\","):"")+ + "}"; + } + +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +this.SourceText = function(lines, owner) +{ + this.lines = lines; + this.owner = owner; +}; + +this.SourceText.getLineAsHTML = function(lineNo) +{ + return escapeForSourceLine(this.lines[lineNo-1]); +}; + + +// ************************************************************************************************ +}).apply(FBL); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-i18n */ function() { with (FBL) { +// ************************************************************************************************ + +// TODO: xxxpedro localization +var oSTR = +{ + "NoMembersWarning": "There are no properties to show for this object.", + + "EmptyStyleSheet": "There are no rules in this stylesheet.", + "EmptyElementCSS": "This element has no style rules.", + "AccessRestricted": "Access to restricted URI denied.", + + "net.label.Parameters": "Parameters", + "net.label.Source": "Source", + "URLParameters": "Params", + + "EditStyle": "Edit Element Style...", + "NewRule": "New Rule...", + + "NewProp": "New Property...", + "EditProp": 'Edit "%s"', + "DeleteProp": 'Delete "%s"', + "DisableProp": 'Disable "%s"' +}; + +// ************************************************************************************************ + +FBL.$STR = function(name) +{ + return oSTR.hasOwnProperty(name) ? oSTR[name] : name; +}; + +FBL.$STRF = function(name, args) +{ + if (!oSTR.hasOwnProperty(name)) return name; + + var format = oSTR[name]; + var objIndex = 0; + + var parts = parseFormat(format); + var trialIndex = objIndex; + var objects = args; + + for (var i= 0; i < parts.length; i++) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + + var result = []; + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + result.push(""+args.shift()); + } + else + result.push(part); + } + + return result.join(""); +}; + +// ************************************************************************************************ + +var parseFormat = function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-firebug */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; +var reps = []; + +var parentPanelMap = {}; + + +// ************************************************************************************************ +// Firebug + +/** + * @namespace describe Firebug + * @exports window.Firebug as Firebug + */ +window.Firebug = FBL.Firebug = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + version: "Firebug Lite 1.3.2", + revision: "$Revision: 9760 $", + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + modules: modules, + panelTypes: panelTypes, + panelTypeMap: panelTypeMap, + reps: reps, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Initialization + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); + + Firebug.browser = new Context(Env.browser); + Firebug.context = Firebug.browser; + + // Document must be cached before chrome initialization + cacheDocument(); + + if (Firebug.Inspector) + Firebug.Inspector.create(); + + if (FBL.processAllStyleSheets) + processAllStyleSheets(Firebug.browser.document); + + FirebugChrome.initialize(); + + dispatch(modules, "initialize", []); + + if (Env.onLoad) + { + var onLoad = Env.onLoad; + delete Env.onLoad; + + setTimeout(onLoad, 200); + } + }, + + shutdown: function() + { + if (Firebug.Inspector) + Firebug.Inspector.destroy(); + + dispatch(modules, "shutdown", []); + + var chromeMap = FirebugChrome.chromeMap; + + for (var name in chromeMap) + { + if (chromeMap.hasOwnProperty(name)) + { + chromeMap[name].destroy(); + } + } + + Firebug.Lite.Cache.Element.clear(); + Firebug.Lite.Cache.StyleSheet.clear(); + + Firebug.browser = null; + Firebug.context = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + modules.push.apply(modules, arguments); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + panelTypeMap[panelType.prototype.name] = arguments[i]; + + if (panelType.prototype.parentPanel) + parentPanelMap[panelType.prototype.parentPanel] = 1; + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + }, + + registerRep: function() + { + reps.push.apply(reps, arguments); + }, + + unregisterRep: function() + { + for (var i = 0; i < arguments.length; ++i) + remove(reps, arguments[i]); + }, + + setDefaultReps: function(funcRep, rep) + { + FBL.defaultRep = rep; + FBL.defaultFuncRep = funcRep; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Reps + + getRep: function(object) + { + var type = typeof object; + if (isIE && isFunction(object)) + type = "function"; + + for (var i = 0; i < reps.length; ++i) + { + var rep = reps[i]; + try + { + if (rep.supportsObject(object, type)) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("getRep type: "+type+" object: "+object, rep); + return rep; + } + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc); + FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className); + // TODO: xxxpedro add trace to FBTrace logs like in Firebug + //firebug.trace(); + } + } + } + + return (type == 'function') ? defaultFuncRep : defaultRep; + }, + + getRepObject: function(node) + { + var target = null; + for (var child = node; child; child = child.parentNode) + { + if (hasClass(child, "repTarget")) + target = child; + + if (child.repObject) + { + if (!target && hasClass(child, "repIgnore")) + break; + else + return child.repObject; + } + } + }, + + getRepNode: function(node) + { + for (var child = node; child; child = child.parentNode) + { + if (child.repObject) + return child; + } + }, + + getElementByRepObject: function(element, object) + { + for (var child = element.firstChild; child; child = child.nextSibling) + { + if (child.repObject == object) + return child; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Preferences + + getPref: function(name) + { + return Firebug[name]; + }, + + setPref: function(name, value) + { + Firebug[name] = value; + + this.savePrefs(); + }, + + setPrefs: function(prefs) + { + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + + this.savePrefs(); + }, + + restorePrefs: function() + { + var Options = Env.Options; + + for (var name in Options) + { + Firebug[name] = Options[name]; + } + }, + + loadPrefs: function(prefs) + { + this.restorePrefs(); + + prefs = prefs || eval("(" + readCookie("FirebugLite") + ")"); + + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + }, + + savePrefs: function() + { + var json = ['{'], jl = 0; + var Options = Env.Options; + + for (var name in Options) + { + if (Options.hasOwnProperty(name)) + { + var value = Firebug[name]; + + json[++jl] = '"'; + json[++jl] = name; + + var type = typeof value; + if (type == "boolean" || type == "number") + { + json[++jl] = '":'; + json[++jl] = value; + json[++jl] = ','; + } + else + { + json[++jl] = '":"'; + json[++jl] = value; + json[++jl] = '",'; + } + } + } + + json.length = jl--; + json[++jl] = '}'; + + createCookie("FirebugLite", json.join("")); + }, + + erasePrefs: function() + { + removeCookie("FirebugLite"); + } +}; + +Firebug.restorePrefs(); + +if (!Env.Options.enablePersistent || + Env.Options.enablePersistent && Env.isChromeContext || + Env.isDebugMode) + Env.browser.window.Firebug = FBL.Firebug; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Other methods + +FBL.cacheDocument = function cacheDocument() +{ + var ElementCache = Firebug.Lite.Cache.Element; + var els = Firebug.browser.document.getElementsByTagName("*"); + for (var i=0, l=els.length, el; iFirebug.registerModule method. There is always one instance of a module object + * per browser window. + * @extends Firebug.Listener + */ +Firebug.Module = extend(new Firebug.Listener(), +/** @extend Firebug.Module */ +{ + /** + * Called when the window is opened. + */ + initialize: function() + { + }, + + /** + * Called when the window is closed. + */ + shutdown: function() + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Called when a new context is created but before the page is loaded. + */ + initContext: function(context) + { + }, + + /** + * Called after a context is detached to a separate window; + */ + reattachContext: function(browser, context) + { + }, + + /** + * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. + */ + destroyContext: function(context, persistedState) + { + }, + + // Called when a FF tab is create or activated (user changes FF tab) + // Called after context is created or with context == null (to abort?) + showContext: function(browser, context) + { + }, + + /** + * Called after a context's page gets DOMContentLoaded + */ + loadedContext: function(context) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + showPanel: function(browser, panel) + { + }, + + showSidePanel: function(browser, panel) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateOption: function(name, value) + { + }, + + getObjectByURL: function(context, url) + { + } +}); + +// ************************************************************************************************ +// Panel + +/** + * @panel Base class for all panels. Every derived panel must define a constructor and + * register with "Firebug.registerPanel" method. An instance of the panel + * object is created by the framework for each browser tab where Firebug is activated. + */ +Firebug.Panel = +{ + name: "HelloWorld", + title: "Hello World!", + + parentPanel: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + options: { + hasCommandLine: false, + hasStatusBar: false, + hasToolButtons: false, + + // Pre-rendered panels are those included in the skin file (firebug.html) + isPreRendered: false, + innerHTMLSync: false + + /* + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // To be used by external extensions + panelHTML: "", + panelCSS: "", + + toolButtonsHTML: "" + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + tabNode: null, + panelNode: null, + sidePanelNode: null, + statusBarNode: null, + toolButtonsNode: null, + + panelBarNode: null, + + sidePanelBarBoxNode: null, + sidePanelBarNode: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + sidePanelBar: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + searchable: false, + editable: true, + order: 2147483647, + statusSeparator: "<", + + create: function(context, doc) + { + this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name); + + this.panelBarNode = $("fbPanelBar1"); + this.sidePanelBarBoxNode = $("fbPanelBar2"); + + if (this.hasSidePanel) + { + this.sidePanelBar = extend({}, PanelBar); + this.sidePanelBar.create(this); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + if (options.isPreRendered) + { + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + } + else + { + var containerSufix = this.parentPanel ? "2" : "1"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel + var panelNode = this.panelNode = createElement("div", { + id: panelId, + className: "fbPanel" + }); + + $("fbPanel" + containerSufix).appendChild(panelNode); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Create Panel Tab + var tabHTML = '' + + this.title + ''; + + var tabNode = this.tabNode = createElement("a", { + id: panelId + "Tab", + className: "fbTab fbHover", + innerHTML: tabHTML + }); + + if (isIE6) + { + tabNode.href = "javascript:void(0)"; + } + + var panelBarNode = this.parentPanel ? + Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode : + this.panelBarNode; + + panelBarNode.appendChild(tabNode); + tabNode.style.display = "block"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create ToolButtons + if (options.hasToolButtons) + { + this.toolButtonsNode = createElement("span", { + id: panelId + "Buttons", + className: "fbToolbarButtons" + }); + + $("fbToolbarButtons").appendChild(this.toolButtonsNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create StatusBar + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + + this.statusBarNode = createElement("span", { + id: panelId + "StatusBar", + className: "fbToolbarButtons fbStatusBar" + }); + + this.statusBarBox.appendChild(this.statusBarNode); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create SidePanel + } + + this.containerNode = this.panelNode.parentNode; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name); + + // xxxpedro contextMenu + this.onContextMenu = bind(this.onContextMenu, this); + + /* + this.context = context; + this.document = doc; + + this.panelNode = doc.createElement("div"); + this.panelNode.ownerPanel = this; + + setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); + doc.body.appendChild(this.panelNode); + + if (FBTrace.DBG_INITIALIZE) + FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); + + this.initializeNode(this.panelNode); + /**/ + }, + + destroy: function(state) // Panel may store info on state + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name); + + if (this.hasSidePanel) + { + this.sidePanelBar.destroy(); + this.sidePanelBar = null; + } + + this.options = null; + this.name = null; + this.parentPanel = null; + + this.tabNode = null; + this.panelNode = null; + this.containerNode = null; + + this.toolButtonsNode = null; + this.statusBarBox = null; + this.statusBarNode = null; + + //if (this.panelNode) + // delete this.panelNode.ownerPanel; + + //this.destroyNode(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + this.sidePanelBar.initialize(); + } + + var options = this.options = extend(Firebug.Panel.options, this.options); + var panelId = "fb" + this.name; + + this.panelNode = $(panelId); + + this.tabNode = $(panelId + "Tab"); + this.tabNode.style.display = "block"; + + if (options.hasStatusBar) + { + this.statusBarBox = $("fbStatusBarBox"); + this.statusBarNode = $(panelId + "StatusBar"); + } + + if (options.hasToolButtons) + { + this.toolButtonsNode = $(panelId + "Buttons"); + } + + this.containerNode = this.panelNode.parentNode; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // restore persistent state + this.containerNode.scrollTop = this.lastScrollTop; + + // xxxpedro contextMenu + addEvent(this.containerNode, "contextmenu", this.onContextMenu); + + + /// TODO: xxxpedro infoTip Hack + Firebug.chrome.currentPanel = + Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ? + Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel : + Firebug.chrome.selectedPanel; + + Firebug.showInfoTips = true; + Firebug.InfoTip.initializeBrowser(Firebug.chrome); + }, + + shutdown: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); + + /// TODO: xxxpedro infoTip Hack + Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); + + if (Firebug.chrome.largeCommandLineVisible) + Firebug.chrome.hideLargeCommandLine(); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (this.hasSidePanel) + { + // TODO: xxxpedro firebug1.3a6 + // new PanelBar mechanism will need to call shutdown to hide the panels (so it + // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement + // a "remember selected panel" feature in the sidePanelBar + //this.sidePanelBar.shutdown(); + } + + // store persistent state + this.lastScrollTop = this.containerNode.scrollTop; + + // xxxpedro contextMenu + removeEvent(this.containerNode, "contextmenu", this.onContextMenu); + }, + + detach: function(oldChrome, newChrome) + { + if (oldChrome.selectedPanel.name == this.name) + this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop; + }, + + reattach: function(doc) + { + if (this.options.innerHTMLSync) + this.synchronizeUI(); + }, + + synchronizeUI: function() + { + this.containerNode.scrollTop = this.lastScrollTop || 0; + }, + + show: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "inline"; + this.statusBarNode.style.display = "inline"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "inline"; + } + + this.panelNode.style.display = "block"; + + this.visible = true; + + if (!this.parentPanel) + Firebug.chrome.layout(this); + }, + + hide: function(state) + { + var options = this.options; + + if (options.hasStatusBar) + { + this.statusBarBox.style.display = "none"; + this.statusBarNode.style.display = "none"; + } + + if (options.hasToolButtons) + { + this.toolButtonsNode.style.display = "none"; + } + + this.panelNode.style.display = "none"; + + this.visible = false; + }, + + watchWindow: function(win) + { + }, + + unwatchWindow: function(win) + { + }, + + updateOption: function(name, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Toolbar helpers + */ + showToolbarButtons: function(buttonsId, show) + { + try + { + if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext. + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this); + + return; + } + var buttons = this.context.browser.chrome.$(buttonsId); + if (buttons) + collapse(buttons, show ? "false" : "true"); + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc); + if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser"); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * Returns a number indicating the view's ability to inspect the object. + * + * Zero means not supported, and higher numbers indicate specificity. + */ + supportsObject: function(object) + { + return 0; + }, + + hasObject: function(object) // beyond type testing, is this object selectable? + { + return false; + }, + + select: function(object, forceUpdate) + { + if (!object) + object = this.getDefaultSelection(this.context); + + if(FBTrace.DBG_PANELS) + FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); + + if (forceUpdate || object != this.selection) + { + this.selection = object; + this.updateSelection(object); + + // TODO: xxxpedro + // XXXjoe This is kind of cheating, but, feh. + //Firebug.chrome.onPanelSelect(object, this); + //if (uiListeners.length > 0) + // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener + } + }, + + updateSelection: function(object) + { + }, + + markChange: function(skipSelf) + { + if (this.dependents) + { + if (skipSelf) + { + for (var i = 0; i < this.dependents.length; ++i) + { + var panelName = this.dependents[i]; + if (panelName != this.name) + this.context.invalidatePanels(panelName); + } + } + else + this.context.invalidatePanels.apply(this.context, this.dependents); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + startInspecting: function() + { + }, + + stopInspecting: function(object, cancelled) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + search: function(text, reverse) + { + }, + + /** + * Retrieves the search options that this modules supports. + * This is used by the search UI to present the proper options. + */ + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive") + ]; + }, + + /** + * Navigates to the next document whose match parameter returns true. + */ + navigateToNextDocument: function(match, reverse) + { + // This is an approximation of the UI that is displayed by the location + // selector. This should be close enough, although it may be better + // to simply generate the sorted list within the module, rather than + // sorting within the UI. + var self = this; + function compare(a, b) { + var locA = self.getObjectDescription(a); + var locB = self.getObjectDescription(b); + if(locA.path > locB.path) + return 1; + if(locA.path < locB.path) + return -1; + if(locA.name > locB.name) + return 1; + if(locA.name < locB.name) + return -1; + return 0; + } + var allLocs = this.getLocationList().sort(compare); + for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++); + + function transformIndex(index) { + if (reverse) { + // For the reverse case we need to implement wrap around. + var intermediate = curPos - index - 1; + return (intermediate < 0 ? allLocs.length : 0) + intermediate; + } else { + return (curPos + index + 1) % allLocs.length; + } + }; + + for (var next = 0; next < allLocs.length - 1; next++) + { + var object = allLocs[transformIndex(next)]; + + if (match(object)) + { + this.navigate(object); + return object; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // Called when "Options" clicked. Return array of + // {label: 'name', nol10n: true, type: "checkbox", checked: , command:function to set } + getOptionsMenuItems: function() + { + return null; + }, + + /* + * Called by chrome.onContextMenu to build the context menu when this panel has focus. + * See also FirebugRep for a similar function also called by onContextMenu + * Extensions may monkey patch and chain off this call + * @param object: the 'realObject', a model value, eg a DOM property + * @param target: the HTML element clicked on. + * @return an array of menu items. + */ + getContextMenuItems: function(object, target) + { + return []; + }, + + getBreakOnMenuItems: function() + { + return []; + }, + + getEditor: function(target, value) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getDefaultSelection: function() + { + return null; + }, + + browseObject: function(object) + { + }, + + getPopupObject: function(target) + { + return Firebug.getRepObject(target); + }, + + getTooltipObject: function(target) + { + return Firebug.getRepObject(target); + }, + + showInfoTip: function(infoTip, x, y) + { + + }, + + getObjectPath: function(object) + { + return null; + }, + + // An array of objects that can be passed to getObjectLocation. + // The list of things a panel can show, eg sourceFiles. + // Only shown if panel.location defined and supportsObject true + getLocationList: function() + { + return null; + }, + + getDefaultLocation: function() + { + return null; + }, + + getObjectLocation: function(object) + { + return ""; + }, + + // Text for the location list menu eg script panel source file list + // return.path: group/category label, return.name: item label + getObjectDescription: function(object) + { + var url = this.getObjectLocation(object); + return FBL.splitURLBase(url); + }, + + /* + * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint + * @param: show boolean, true turns on. + */ + highlight: function(show) + { + var tab = this.getTab(); + if (!tab) + return; + + if (show) + tab.setAttribute("highlight", "true"); + else + tab.removeAttribute("highlight"); + }, + + getTab: function() + { + var chrome = Firebug.chrome; + + var tab = chrome.$("fbPanelBar2").getTab(this.name); + if (!tab) + tab = chrome.$("fbPanelBar1").getTab(this.name); + return tab; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for Break On Next + + /** + * Called by the framework when the user clicks on the Break On Next button. + * @param {Boolean} armed Set to true if the Break On Next feature is + * to be armed for action and set to false if the Break On Next should be disarmed. + * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|. + */ + breakOnNext: function(armed) + { + }, + + /** + * Called when a panel is selected/displayed. The method should return true + * if the Break On Next feature is currently armed for this panel. + */ + shouldBreakOnNext: function() + { + return false; + }, + + /** + * Returns labels for Break On Next tooltip (one for enabled and one for disabled state). + * @param {Boolean} enabled Set to true if the Break On Next feature is + * currently activated for this panel. + */ + getBreakOnNextTooltip: function(enabled) + { + return null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // xxxpedro contextMenu + onContextMenu: function(event) + { + if (!this.getContextMenuItems) + return; + + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + var menu = this.getContextMenuItems(this.selection, target); + if (!menu) + return; + + var contextMenu = new Menu( + { + id: "fbPanelContextMenu", + + items: menu + }); + + contextMenu.show(event.clientX, event.clientY); + + return true; + + /* + // TODO: xxxpedro move code to somewhere. code to get cross-browser + // window to screen coordinates + var box = Firebug.browser.getElementPosition(Firebug.chrome.node); + + var screenY = 0; + + // Firefox + if (typeof window.mozInnerScreenY != "undefined") + { + screenY = window.mozInnerScreenY; + } + // Chrome + else if (typeof window.innerHeight != "undefined") + { + screenY = window.outerHeight - window.innerHeight; + } + // IE + else if (typeof window.screenTop != "undefined") + { + screenY = window.screenTop; + } + + contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top); + /**/ + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * MeasureBox + * To get pixels size.width and size.height: + *
      • this.startMeasuring(view);
      • + *
      • var size = this.measureText(lineNoCharsSpacer);
      • + *
      • this.stopMeasuring();
      • + *
      + * + * @namespace + */ +Firebug.MeasureBox = +{ + startMeasuring: function(target) + { + if (!this.measureBox) + { + this.measureBox = target.ownerDocument.createElement("span"); + this.measureBox.className = "measureBox"; + } + + copyTextStyles(target, this.measureBox); + target.ownerDocument.body.appendChild(this.measureBox); + }, + + getMeasuringElement: function() + { + return this.measureBox; + }, + + measureText: function(value) + { + this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m"; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + measureInputText: function(value) + { + value = value ? escapeForTextNode(value) : "m"; + if (!Firebug.showTextNodesWithWhitespace) + value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m'); + this.measureBox.innerHTML = value; + return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; + }, + + getBox: function(target) + { + var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, ""); + var box = getBoxFromStyles(style, this.measureBox); + return box; + }, + + stopMeasuring: function() + { + this.measureBox.parentNode.removeChild(this.measureBox); + } +}; + + +// ************************************************************************************************ +if (FBL.domplate) Firebug.Rep = domplate( +{ + className: "", + inspectable: true, + + supportsObject: function(object, type) + { + return false; + }, + + inspectObject: function(object, context) + { + Firebug.chrome.select(object); + }, + + browseObject: function(object, context) + { + }, + + persistObject: function(object, context) + { + }, + + getRealObject: function(object, context) + { + return object; + }, + + getTitle: function(object) + { + var label = safeToString(object); + + var re = /\[object (.*?)\]/; + var m = re.exec(label); + + ///return m ? m[1] : label; + + // if the label is in the "[object TYPE]" format return its type + if (m) + { + return m[1]; + } + // if it is IE we need to handle some special cases + else if ( + // safeToString() fails to recognize some objects in IE + isIE && + // safeToString() returns "[object]" for some objects like window.Image + (label == "[object]" || + // safeToString() returns undefined for some objects like window.clientInformation + typeof object == "object" && typeof label == "undefined") + ) + { + return "Object"; + } + else + { + return label; + } + }, + + getTooltip: function(object) + { + return null; + }, + + getContextMenuItems: function(object, target, context) + { + return []; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Convenience for domplates + + STR: function(name) + { + return $STR(name); + }, + + cropString: function(text) + { + return cropString(text); + }, + + cropMultipleLines: function(text, limit) + { + return cropMultipleLines(text, limit); + }, + + toLowerCase: function(text) + { + return text ? text.toLowerCase() : text; + }, + + plural: function(n) + { + return n == 1 ? "" : "s"; + } +}); + +// ************************************************************************************************ + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /** @scope ns-gui */ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Controller + +/**@namespace*/ +FBL.Controller = { + + controllers: null, + controllerContext: null, + + initialize: function(context) + { + this.controllers = []; + this.controllerContext = context || Firebug.chrome; + }, + + shutdown: function() + { + this.removeControllers(); + + //this.controllers = null; + //this.controllerContext = null; + }, + + addController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + // If the first argument is a string, make a selector query + // within the controller node context + if (typeof arg[0] == "string") + { + arg[0] = $$(arg[0], this.controllerContext); + } + + // bind the handler to the proper context + var handler = arg[2]; + arg[2] = bind(handler, this); + // save the original handler as an extra-argument, so we can + // look for it later, when removing a particular controller + arg[3] = handler; + + this.controllers.push(arg); + addEvent.apply(this, arg); + } + }, + + removeController: function() + { + for (var i=0, arg; arg=arguments[i]; i++) + { + for (var j=0, c; c=this.controllers[j]; j++) + { + if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3]) + removeEvent.apply(this, c); + } + } + }, + + removeControllers: function() + { + for (var i=0, c; c=this.controllers[i]; i++) + { + removeEvent.apply(this, c); + } + } +}; + + +// ************************************************************************************************ +// PanelBar + +/**@namespace*/ +FBL.PanelBar = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + panelMap: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + selectedPanel: null, + parentPanelName: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function(ownerPanel) + { + this.panelMap = {}; + this.ownerPanel = ownerPanel; + + if (ownerPanel) + { + ownerPanel.sidePanelBarNode = createElement("span"); + ownerPanel.sidePanelBarNode.style.display = "none"; + ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode); + } + + var panels = Firebug.panelTypes; + for (var i=0, p; p=panels[i]; i++) + { + if ( // normal Panel of the Chrome's PanelBar + !ownerPanel && !p.prototype.parentPanel || + // Child Panel of the current Panel's SidePanelBar + ownerPanel && p.prototype.parentPanel && + ownerPanel.name == p.prototype.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + }, + + destroy: function() + { + PanelBar.shutdown.call(this); + + for (var name in this.panelMap) + { + this.removePanel(name); + + var panel = this.panelMap[name]; + panel.destroy(); + + this.panelMap[name] = null; + delete this.panelMap[name]; + } + + this.panelMap = null; + this.ownerPanel = null; + }, + + initialize: function() + { + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "inline"; + + for(var name in this.panelMap) + { + (function(self, name){ + + // tab click handler + var onTabClick = function onTabClick() + { + self.selectPanel(name); + return false; + }; + + Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]); + + })(this, name); + } + }, + + shutdown: function() + { + var selectedPanel = this.selectedPanel; + + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.hide(); + selectedPanel.shutdown(); + } + + if (this.ownerPanel) + this.ownerPanel.sidePanelBarNode.style.display = "none"; + + this.selectedPanel = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + addPanel: function(panelName, parentPanel) + { + var PanelType = Firebug.panelTypeMap[panelName]; + var panel = this.panelMap[panelName] = new PanelType(); + + panel.create(); + }, + + removePanel: function(panelName) + { + var panel = this.panelMap[panelName]; + if (panel.hasOwnProperty(panelName)) + panel.destroy(); + }, + + selectPanel: function(panelName) + { + var selectedPanel = this.selectedPanel; + var panel = this.panelMap[panelName]; + + if (panel && selectedPanel != panel) + { + if (selectedPanel) + { + removeClass(selectedPanel.tabNode, "fbSelectedTab"); + selectedPanel.shutdown(); + selectedPanel.hide(); + } + + if (!panel.parentPanel) + FirebugChrome.selectedPanelName = panelName; + + this.selectedPanel = panel; + + setClass(panel.tabNode, "fbSelectedTab"); + panel.show(); + panel.initialize(); + } + }, + + getPanel: function(panelName) + { + var panel = this.panelMap[panelName]; + + return panel; + } + +}; + +//************************************************************************************************ +// Button + +/** + * options.element + * options.caption + * options.title + * + * options.owner + * options.className + * options.pressedClassName + * + * options.onPress + * options.onUnpress + * options.onClick + * + * @class + * @extends FBL.Controller + * + */ + +FBL.Button = function(options) +{ + options = options || {}; + + append(this, options); + + this.state = "unpressed"; + this.display = "unpressed"; + + if (this.element) + { + this.container = this.element.parentNode; + } + else + { + this.shouldDestroy = true; + + this.container = this.owner.getPanel().toolButtonsNode; + + this.element = createElement("a", { + className: this.baseClassName + " " + this.className + " fbHover", + innerHTML: this.caption + }); + + if (this.title) + this.element.title = this.title; + + this.container.appendChild(this.element); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +Button.prototype = extend(Controller, +/**@extend FBL.Button.prototype*/ +{ + type: "normal", + caption: "caption", + title: null, + + className: "", // custom class + baseClassName: "fbButton", // control class + pressedClassName: "fbBtnPressed", // control pressed class + + element: null, + container: null, + owner: null, + + state: null, + display: null, + + destroy: function() + { + this.shutdown(); + + // only remove if it is a dynamically generated button (not pre-rendered) + if (this.shouldDestroy) + this.container.removeChild(this.element); + + this.element = null; + this.container = null; + this.owner = null; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var element = this.element; + + this.addController([element, "mousedown", this.handlePress]); + + if (this.type == "normal") + this.addController( + [element, "mouseup", this.handleUnpress], + [element, "mouseout", this.handleUnpress], + [element, "click", this.handleClick] + ); + }, + + shutdown: function() + { + Controller.shutdown.apply(this); + }, + + restore: function() + { + this.changeState("unpressed"); + }, + + changeState: function(state) + { + this.state = state; + this.changeDisplay(state); + }, + + changeDisplay: function(display) + { + if (display != this.display) + { + if (display == "pressed") + { + setClass(this.element, this.pressedClassName); + } + else if (display == "unpressed") + { + removeClass(this.element, this.pressedClassName); + } + this.display = display; + } + }, + + handlePress: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + this.changeDisplay("pressed"); + this.beforeClick = true; + } + else if (this.type == "toggle") + { + if (this.state == "pressed") + { + this.changeState("unpressed"); + + if (this.onUnpress) + this.onUnpress.apply(this.owner, arguments); + } + else + { + this.changeState("pressed"); + + if (this.onPress) + this.onPress.apply(this.owner, arguments); + } + + if (this.onClick) + this.onClick.apply(this.owner, arguments); + } + + return false; + }, + + handleUnpress: function(event) + { + cancelEvent(event, true); + + if (this.beforeClick) + this.changeDisplay("unpressed"); + + return false; + }, + + handleClick: function(event) + { + cancelEvent(event, true); + + if (this.type == "normal") + { + if (this.onClick) + this.onClick.apply(this.owner); + + this.changeState("unpressed"); + } + + this.beforeClick = false; + + return false; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +/** + * @class + * @extends FBL.Button + */ +FBL.IconButton = function() +{ + Button.apply(this, arguments); +}; + +IconButton.prototype = extend(Button.prototype, +/**@extend FBL.IconButton.prototype*/ +{ + baseClassName: "fbIconButton", + pressedClassName: "fbIconPressed" +}); + + +//************************************************************************************************ +// Menu + +var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value", + _command: "$item.command"}; + +if (isIE6) + menuItemProps.href = "javascript:void(0)"; + +// Allow GUI to be loaded even when Domplate module is not installed. +if (FBL.domplate) +var MenuPlate = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "fbMenu fbShadow"}, + DIV({"class": "fbMenuContent fbShadowContent"}, + FOR("item", "$object.items|memberIterator", + TAG("$item.tag", {item: "$item"}) + ) + ) + ), + + itemTag: + A(menuItemProps, + "$item.label" + ), + + checkBoxTag: + A(extend(menuItemProps, {checked : "$item.checked"}), + + "$item.label" + ), + + radioButtonTag: + A(extend(menuItemProps, {selected : "$item.selected"}), + + "$item.label" + ), + + groupTag: + A(extend(menuItemProps, {child: "$item.child"}), + "$item.label" + ), + + shortcutTag: + A(menuItemProps, + "$item.label", + SPAN({"class": "fbMenuShortcutKey"}, + "$item.key" + ) + ), + + separatorTag: + SPAN({"class": "fbMenuSeparator"}), + + memberIterator: function(items) + { + var result = []; + + for (var i=0, length=items.length; i width || el.scrollHeight > height)) + { + width = el.scrollWidth; + height = el.scrollHeight; + } + + return {width: width, height: height}; + }, + + getWindowScrollPosition: function() + { + var top=0, left=0, el; + + if(typeof this.window.pageYOffset == "number") + { + top = this.window.pageYOffset; + left = this.window.pageXOffset; + } + else if((el=this.document.body) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft)) + { + top = el.scrollTop; + left = el.scrollLeft; + } + + return {top:top, left:left}; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Element Methods + + getElementFromPoint: function(x, y) + { + if (shouldFixElementFromPoint) + { + var scroll = this.getWindowScrollPosition(); + return this.document.elementFromPoint(x + scroll.left, y + scroll.top); + } + else + return this.document.elementFromPoint(x, y); + }, + + getElementPosition: function(el) + { + var left = 0 + var top = 0; + + do + { + left += el.offsetLeft; + top += el.offsetTop; + } + while (el = el.offsetParent); + + return {left:left, top:top}; + }, + + getElementBox: function(el) + { + var result = {}; + + if (el.getBoundingClientRect) + { + var rect = el.getBoundingClientRect(); + + // fix IE problem with offset when not in fullscreen mode + var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; + + var scroll = this.getWindowScrollPosition(); + + result.top = Math.round(rect.top - offset + scroll.top); + result.left = Math.round(rect.left - offset + scroll.left); + result.height = Math.round(rect.bottom - rect.top); + result.width = Math.round(rect.right - rect.left); + } + else + { + var position = this.getElementPosition(el); + + result.top = position.top; + result.left = position.left; + result.height = el.offsetHeight; + result.width = el.offsetWidth; + } + + return result; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Measurement Methods + + getMeasurement: function(el, name) + { + var result = {value: 0, unit: "px"}; + + var cssValue = this.getStyle(el, name); + + if (!cssValue) return result; + if (cssValue.toLowerCase() == "auto") return result; + + var reMeasure = /(\d+\.?\d*)(.*)/; + var m = cssValue.match(reMeasure); + + if (m) + { + result.value = m[1]-0; + result.unit = m[2].toLowerCase(); + } + + return result; + }, + + getMeasurementInPixels: function(el, name) + { + if (!el) return null; + + var m = this.getMeasurement(el, name); + var value = m.value; + var unit = m.unit; + + if (unit == "px") + return value; + + else if (unit == "pt") + return this.pointsToPixels(name, value); + + if (unit == "em") + return this.emToPixels(el, value); + + else if (unit == "%") + return this.percentToPixels(el, value); + }, + + getMeasurementBox1: function(el, name) + { + var sufixes = ["Top", "Left", "Bottom", "Right"]; + var result = []; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getMeasurementBox: function(el, name) + { + var result = []; + var sufixes = name == "border" ? + ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : + ["Top", "Left", "Bottom", "Right"]; + + if (isIE) + { + var propName, cssValue; + var autoMargin = null; + + for(var i=0, sufix; sufix=sufixes[i]; i++) + { + propName = name + sufix; + + cssValue = el.currentStyle[propName] || el.style[propName]; + + if (cssValue == "auto") + { + if (!autoMargin) + autoMargin = this.getCSSAutoMarginBox(el); + + result[i] = autoMargin[sufix.toLowerCase()]; + } + else + result[i] = this.getMeasurementInPixels(el, propName); + + } + + } + else + { + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = this.getMeasurementInPixels(el, name + sufix); + } + + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getCSSAutoMarginBox: function(el) + { + if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1) + return {top:0, left:0, bottom:0, right:0}; + /**/ + + var offsetTop = 0; + if (false && isIEStantandMode) + { + var scrollSize = Firebug.browser.getWindowScrollSize(); + offsetTop = scrollSize.height; + } + + var box = this.document.createElement("div"); + //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;"; + box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;"; + + var clone = el.cloneNode(false); + var text = this.document.createTextNode(" "); + clone.appendChild(text); + + box.appendChild(clone); + + this.document.body.appendChild(box); + + var marginTop = clone.offsetTop - box.offsetTop - 1; + var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; + + var marginLeft = clone.offsetLeft - box.offsetLeft - 1; + var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; + + this.document.body.removeChild(box); + + return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight}; + }, + + getFontSizeInPixels: function(el) + { + var size = this.getMeasurement(el, "fontSize"); + + if (size.unit == "px") return size.value; + + // get font size, the dirty way + var computeDirtyFontSize = function(el, calibration) + { + var div = this.document.createElement("div"); + var divStyle = offscreenStyle; + + if (calibration) + divStyle += " font-size:"+calibration+"px;"; + + div.style.cssText = divStyle; + div.innerHTML = "A"; + el.appendChild(div); + + var value = div.offsetHeight; + el.removeChild(div); + return value; + } + + /* + var calibrationBase = 200; + var calibrationValue = computeDirtyFontSize(el, calibrationBase); + var rate = calibrationBase / calibrationValue; + /**/ + + // the "dirty technique" fails in some environments, so we're using a static value + // based in some tests. + var rate = 200 / 225; + + var value = computeDirtyFontSize(el); + + return value * rate; + }, + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Unit Funtions + + pointsToPixels: function(name, value, returnFloat) + { + var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; + + var result = value * pixelsPerInch[axis] / 72; + + return returnFloat ? result : Math.round(result); + }, + + emToPixels: function(el, value) + { + if (!el) return null; + + var fontSize = this.getFontSizeInPixels(el); + + return Math.round(value * fontSize); + }, + + exToPixels: function(el, value) + { + if (!el) return null; + + // get ex value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "ex;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + percentToPixels: function(el, value) + { + if (!el) return null; + + // get % value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "%;"; + + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); + + return value; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getStyle: isIE ? function(el, name) + { + return el.currentStyle[name] || el.style[name] || undefined; + } + : function(el, name) + { + return this.document.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + } + +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Window Options + +var WindowDefaultOptions = + { + type: "frame", + id: "FirebugUI", + height: 250 + }, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Instantiated objects + + commandLine, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Interface Elements Cache + + fbTop, + fbContent, + fbContentStyle, + fbBottom, + fbBtnInspect, + + fbToolbar, + + fbPanelBox1, + fbPanelBox1Style, + fbPanelBox2, + fbPanelBox2Style, + fbPanelBar2Box, + fbPanelBar2BoxStyle, + + fbHSplitter, + fbVSplitter, + fbVSplitterStyle, + + fbPanel1, + fbPanel1Style, + fbPanel2, + fbPanel2Style, + + fbConsole, + fbConsoleStyle, + fbHTML, + + fbCommandLine, + fbLargeCommandLine, + fbLargeCommandButtons, + +//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Cached size values + + topHeight, + topPartialHeight, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastSelectedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLineState = 0, + lastFocusedPanelName, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastHSplitterMouseMove = 0, + onHSplitterMouseMoveBuffer = null, + onHSplitterMouseMoveTimer = null, + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + lastVSplitterMouseMove = 0; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// FirebugChrome + +/**@namespace*/ +FBL.FirebugChrome = +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + isOpen: false, + height: 250, + sidePanelWidth: 350, + + selectedPanelName: "Console", + selectedHTMLElementId: null, + + chromeMap: {}, + + htmlSelectionStack: [], + consoleMessageQueue: [], + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); + + createChromeWindow(); + }, + + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); + + if (Env.chrome.type == "frame" || Env.chrome.type == "div") + ChromeMini.create(Env.chrome); + + var chrome = Firebug.chrome = new Chrome(Env.chrome); + FirebugChrome.chromeMap[chrome.type] = chrome; + + addGlobalEvent("keydown", onGlobalKeyDown); + + if (Env.Options.enablePersistent && chrome.type == "popup") + { + // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode + var frame = FirebugChrome.chromeMap.frame; + if (frame) + frame.close(); + + //chrome.reattach(frame, chrome); + //TODO: xxxpedro persist synchronize? + chrome.initialize(); + } + }, + + clone: function(FBChrome) + { + for (var name in FBChrome) + { + var prop = FBChrome[name]; + if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) + { + this[name] = prop; + } + } + } +}; + + + +// ************************************************************************************************ +// Chrome Window Creation + +var createChromeWindow = function(options) +{ + options = extend(WindowDefaultOptions, options || {}); + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Locals + + var chrome = {}, + + context = options.context || Env.browser, + + type = chrome.type = Env.Options.enablePersistent ? + "popup" : + options.type, + + isChromeFrame = type == "frame", + + useLocalSkin = Env.useLocalSkin, + + url = useLocalSkin ? + Env.Location.skin : + "about:blank", + + // document.body not available in XML+XSL documents in Firefox + body = context.document.getElementsByTagName("body")[0], + + formatNode = function(node) + { + if (!Env.isDebugMode) + { + node.firebugIgnore = true; + } + + node.style.border = "0"; + node.style.visibility = "hidden"; + node.style.zIndex = "2147483647"; // MAX z-index = 2147483647 + node.style.position = noFixedPosition ? "absolute" : "fixed"; + node.style.width = "100%"; // "102%"; IE auto margin bug + node.style.left = "0"; + node.style.bottom = noFixedPosition ? "-1px" : "0"; + node.style.height = options.height + "px"; + + // avoid flickering during chrome rendering + if (isFirefox) + node.style.display = "none"; + }, + + createChromeDiv = function() + { + //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed."); + + var node = chrome.node = createGlobalElement("div"), + style = createGlobalElement("style"), + + css = FirebugChrome.Skin.CSS + /* + .replace(/;/g, " !important;") + .replace(/!important\s!important/g, "!important") + .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/, + + // reset some styles to minimize interference from the main page's style + rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" + + // load the chrome styles + css + + // adjust some remaining styles + ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}"; + /* + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + rules += ".fbBody table.fbChrome{position: static !important;}"; + }/**/ + + style.type = "text/css"; + + if (style.styleSheet) + style.styleSheet.cssText = rules; + else + style.appendChild(context.document.createTextNode(rules)); + + document.getElementsByTagName("head")[0].appendChild(style); + + node.className = "fbBody"; + node.style.overflow = "hidden"; + node.innerHTML = getChromeDivTemplate(); + + if (isIE) + { + // IE7 CSS bug (FbChrome table bigger than its parent div) + setTimeout(function(){ + node.firstChild.style.height = "1px"; + node.firstChild.style.position = "static"; + },0); + /**/ + } + + formatNode(node); + + body.appendChild(node); + + chrome.window = window; + chrome.document = document; + onChromeLoad(chrome); + }; + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + try + { + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "div" (windowless mode) + if (type == "div") + { + createChromeDiv(); + return; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // cretate the Chrome as an "iframe" + else if (isChromeFrame) + { + // Create the Chrome Frame + var node = chrome.node = createGlobalElement("iframe"); + node.setAttribute("src", url); + node.setAttribute("frameBorder", "0"); + + formatNode(node); + + body.appendChild(node); + + // must set the id after appending to the document, otherwise will cause an + // strange error in IE, making the iframe load the page in which the bookmarklet + // was created (like getfirebug.com), before loading the injected UI HTML, + // generating an "Access Denied" error. + node.id = options.id; + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "popup" + else + { + var height = FirebugChrome.height || options.height, + + options = [ + "true,top=", + Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0), + ",left=0,height=", + height, + ",width=", + screen.availWidth-10, // Opera opens popup in a new tab if it's too big! + ",resizable" + ].join(""), + + node = chrome.node = context.window.open( + url, + "popup", + options + ); + + if (node) + { + try + { + node.focus(); + } + catch(E) + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + else + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inject the interface HTML if it is not using the local skin + + if (!useLocalSkin) + { + var tpl = getChromeTemplate(!isChromeFrame), + doc = isChromeFrame ? node.contentWindow.document : node.document; + + doc.write(tpl); + doc.close(); + } + + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Wait the Window to be loaded + + var win, + + waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100, + + waitForWindow = function() + { + if ( // Frame loaded... OR + isChromeFrame && (win=node.contentWindow) && + node.contentWindow.document.getElementById("fbCommandLine") || + + // Popup loaded + !isChromeFrame && (win=node.window) && node.document && + node.document.getElementById("fbCommandLine") ) + { + chrome.window = win.window; + chrome.document = win.document; + + // Prevent getting the wrong chrome height in FF when opening a popup + setTimeout(function(){ + onChromeLoad(chrome); + },0); + } + else + setTimeout(waitForWindow, waitDelay); + }; + + waitForWindow(); + } + catch(e) + { + var msg = e.message || e; + + if (/access/i.test(msg)) + { + // Firebug Lite could not create a window for its Graphical User Interface due to + // a access restriction. This happens in some pages, when loading via bookmarklet. + // In such cases, the only way is to load the GUI in a "windowless mode". + + if (isChromeFrame) + body.removeChild(node); + else if(type == "popup") + node.close(); + + // Load the GUI in a "windowless mode" + createChromeDiv(); + } + else + { + alert("Firebug Error: Firebug GUI could not be created."); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var onChromeLoad = function onChromeLoad(chrome) +{ + Env.chrome = chrome; + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded"); + + if (Env.Options.enablePersistent) + { + // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode + Env.FirebugChrome = FirebugChrome; + + chrome.window.Firebug = chrome.window.Firebug || {}; + chrome.window.Firebug.SharedEnv = Env; + + if (Env.isDevelopmentMode) + { + Env.browser.window.FBDev.loadChromeApplication(chrome); + } + else + { + var doc = chrome.document; + var script = doc.createElement("script"); + script.src = Env.Location.app + "#remote,persist"; + doc.getElementsByTagName("head")[0].appendChild(script); + } + } + else + { + if (chrome.type == "frame" || chrome.type == "div") + { + // initialize the chrome application + setTimeout(function(){ + FBL.Firebug.initialize(); + },0); + } + else if (chrome.type == "popup") + { + var oldChrome = FirebugChrome.chromeMap.frame; + + var newChrome = new Chrome(chrome); + + // TODO: xxxpedro sync detach reattach attach + dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); + + if (oldChrome) + oldChrome.close(); + + newChrome.reattach(oldChrome, newChrome); + } + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var getChromeDivTemplate = function() +{ + return FirebugChrome.Skin.HTML; +}; + +var getChromeTemplate = function(isPopup) +{ + var tpl = FirebugChrome.Skin; + var r = [], i = -1; + + r[++i] = ''; + r[++i] = ''; + r[++i] = Firebug.version; + + /* + r[++i] = ''; + /**/ + + r[++i] = ''; + /**/ + + r[++i] = ''; + r[++i] = tpl.HTML; + r[++i] = ''; + + return r.join(""); +}; + + +// ************************************************************************************************ +// Chrome Class + +/**@class*/ +var Chrome = function Chrome(chrome) +{ + var type = chrome.type; + var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; + + append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase) + append(this, chrome); // inherit chrome window properties + append(this, new Context(chrome.window)); // inherit from Context class + + FirebugChrome.chromeMap[type] = this; + Firebug.chrome = this; + Env.chrome = chrome.window; + + this.commandLineVisible = false; + this.sidePanelVisible = false; + + this.create(); + + return this; +}; + +// ************************************************************************************************ +// ChromeBase + +/** + * @namespace + * @extends FBL.Controller + * @extends FBL.PanelBar + **/ +var ChromeBase = {}; +append(ChromeBase, Controller); +append(ChromeBase, PanelBar); +append(ChromeBase, +/**@extend ns-chrome-ChromeBase*/ +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited properties + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from createChrome function + + node: null, + type: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from Context.prototype + + document: null, + window: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // value properties + + sidePanelVisible: false, + commandLineVisible: false, + largeCommandLineVisible: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // object properties + + inspectButton: null, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + create: function() + { + PanelBar.create.call(this); + + if (Firebug.Inspector) + this.inspectButton = new Button({ + type: "toggle", + element: $("fbChrome_btInspect"), + owner: Firebug.Inspector, + + onPress: Firebug.Inspector.startInspecting, + onUnpress: Firebug.Inspector.stopInspecting + }); + }, + + destroy: function() + { + if(Firebug.Inspector) + this.inspectButton.destroy(); + + PanelBar.destroy.call(this); + + this.shutdown(); + }, + + testMenu: function() + { + var firebugMenu = new Menu( + { + id: "fbFirebugMenu", + + items: + [ + { + label: "Open Firebug", + type: "shortcut", + key: isFirefox ? "Shift+F12" : "F12", + checked: true, + command: "toggleChrome" + }, + { + label: "Open Firebug in New Window", + type: "shortcut", + key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12", + command: "openPopup" + }, + { + label: "Inspect Element", + type: "shortcut", + key: "Ctrl+Shift+C", + command: "toggleInspect" + }, + { + label: "Command Line", + type: "shortcut", + key: "Ctrl+Shift+L", + command: "focusCommandLine" + }, + "-", + { + label: "Options", + type: "group", + child: "fbFirebugOptionsMenu" + }, + "-", + { + label: "Firebug Lite Website...", + command: "visitWebsite" + }, + { + label: "Discussion Group...", + command: "visitDiscussionGroup" + }, + { + label: "Issue Tracker...", + command: "visitIssueTracker" + } + ], + + onHide: function() + { + iconButton.restore(); + }, + + toggleChrome: function() + { + Firebug.chrome.toggle(); + }, + + openPopup: function() + { + Firebug.chrome.toggle(true, true); + }, + + toggleInspect: function() + { + Firebug.Inspector.toggleInspect(); + }, + + focusCommandLine: function() + { + Firebug.chrome.focusCommandLine(); + }, + + visitWebsite: function() + { + this.visit("http://getfirebug.com/lite.html"); + }, + + visitDiscussionGroup: function() + { + this.visit("http://groups.google.com/group/firebug"); + }, + + visitIssueTracker: function() + { + this.visit("http://code.google.com/p/fbug/issues/list"); + }, + + visit: function(url) + { + window.open(url); + } + + }); + + /**@private*/ + var firebugOptionsMenu = + { + id: "fbFirebugOptionsMenu", + + getItems: function() + { + var cookiesDisabled = !Firebug.saveCookies; + + return [ + { + label: "Save Options in Cookies", + type: "checkbox", + value: "saveCookies", + checked: Firebug.saveCookies, + command: "saveOptions" + }, + "-", + { + label: "Start Opened", + type: "checkbox", + value: "startOpened", + checked: Firebug.startOpened, + disabled: cookiesDisabled + }, + { + label: "Start in New Window", + type: "checkbox", + value: "startInNewWindow", + checked: Firebug.startInNewWindow, + disabled: cookiesDisabled + }, + { + label: "Show Icon When Hidden", + type: "checkbox", + value: "showIconWhenHidden", + checked: Firebug.showIconWhenHidden, + disabled: cookiesDisabled + }, + { + label: "Override Console Object", + type: "checkbox", + value: "overrideConsole", + checked: Firebug.overrideConsole, + disabled: cookiesDisabled + }, + { + label: "Ignore Firebug Elements", + type: "checkbox", + value: "ignoreFirebugElements", + checked: Firebug.ignoreFirebugElements, + disabled: cookiesDisabled + }, + { + label: "Disable When Firebug Active", + type: "checkbox", + value: "disableWhenFirebugActive", + checked: Firebug.disableWhenFirebugActive, + disabled: cookiesDisabled + }, + { + label: "Disable XHR Listener", + type: "checkbox", + value: "disableXHRListener", + checked: Firebug.disableXHRListener, + disabled: cookiesDisabled + }, + { + label: "Enable Trace Mode", + type: "checkbox", + value: "enableTrace", + checked: Firebug.enableTrace, + disabled: cookiesDisabled + }, + { + label: "Enable Persistent Mode (experimental)", + type: "checkbox", + value: "enablePersistent", + checked: Firebug.enablePersistent, + disabled: cookiesDisabled + }, + "-", + { + label: "Reset All Firebug Options", + command: "restorePrefs", + disabled: cookiesDisabled + } + ]; + }, + + onCheck: function(target, value, checked) + { + Firebug.setPref(value, checked); + }, + + saveOptions: function(target) + { + var saveEnabled = target.getAttribute("checked"); + + if (!saveEnabled) this.restorePrefs(); + + this.updateMenu(target); + + return false; + }, + + restorePrefs: function(target) + { + Firebug.restorePrefs(); + + if(Firebug.saveCookies) + Firebug.savePrefs(); + else + Firebug.erasePrefs(); + + if (target) + this.updateMenu(target); + + return false; + }, + + updateMenu: function(target) + { + var options = getElementsByClass(target.parentNode, "fbMenuOption"); + + var firstOption = options[0]; + var enabled = Firebug.saveCookies; + if (enabled) + Menu.check(firstOption); + else + Menu.uncheck(firstOption); + + if (enabled) + Menu.check(options[0]); + else + Menu.uncheck(options[0]); + + for (var i = 1, length = options.length; i < length; i++) + { + var option = options[i]; + + var value = option.getAttribute("value"); + var pref = Firebug[value]; + + if (pref) + Menu.check(option); + else + Menu.uncheck(option); + + if (enabled) + Menu.enable(option); + else + Menu.disable(option); + } + } + }; + + Menu.register(firebugOptionsMenu); + + var menu = firebugMenu; + + var testMenuClick = function(event) + { + //console.log("testMenuClick"); + cancelEvent(event, true); + + var target = event.target || event.srcElement; + + if (menu.isVisible) + menu.hide(); + else + { + var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position + + chrome = Firebug.chrome, + + box = chrome.getElementBox(target), + + offset = chrome.type == "div" ? + chrome.getElementPosition(chrome.node) : + {top: 0, left: 0}; + + menu.show( + box.left + offsetLeft - offset.left, + box.top + box.height -5 - offset.top + ); + } + + return false; + }; + + var iconButton = new IconButton({ + type: "toggle", + element: $("fbFirebugButton"), + + onClick: testMenuClick + }); + + iconButton.initialize(); + + //addEvent($("fbToolbarIcon"), "click", testMenuClick); + }, + + initialize: function() + { + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Env.bookmarkletOutdated) + Firebug.Console.logFormatted([ + "A new bookmarklet version is available. " + + "Please visit http://getfirebug.com/firebuglite#Install and update it." + ], Firebug.context, "warn"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Firebug.Console) + Firebug.Console.flush(); + + if (Firebug.Trace) + FBTrace.flush(Firebug.Trace); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize inherited classes + Controller.initialize.call(this); + PanelBar.initialize.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the interface elements cache + + fbTop = $("fbTop"); + fbContent = $("fbContent"); + fbContentStyle = fbContent.style; + fbBottom = $("fbBottom"); + fbBtnInspect = $("fbBtnInspect"); + + fbToolbar = $("fbToolbar"); + + fbPanelBox1 = $("fbPanelBox1"); + fbPanelBox1Style = fbPanelBox1.style; + fbPanelBox2 = $("fbPanelBox2"); + fbPanelBox2Style = fbPanelBox2.style; + fbPanelBar2Box = $("fbPanelBar2Box"); + fbPanelBar2BoxStyle = fbPanelBar2Box.style; + + fbHSplitter = $("fbHSplitter"); + fbVSplitter = $("fbVSplitter"); + fbVSplitterStyle = fbVSplitter.style; + + fbPanel1 = $("fbPanel1"); + fbPanel1Style = fbPanel1.style; + fbPanel2 = $("fbPanel2"); + fbPanel2Style = fbPanel2.style; + + fbConsole = $("fbConsole"); + fbConsoleStyle = fbConsole.style; + fbHTML = $("fbHTML"); + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + topHeight = fbTop.offsetHeight; + topPartialHeight = fbToolbar.offsetHeight; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + disableTextSelection($("fbToolbar")); + disableTextSelection($("fbPanelBarBox")); + disableTextSelection($("fbPanelBar1")); + disableTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6 + if (isIE6 && Firebug.Selector) + { + // TODO: xxxpedro change to getElementsByClass + var as = $$(".fbHover"); + for (var i=0, a; a=as[i]; i++) + { + a.setAttribute("href", "javascript:void(0)"); + } + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize all panels + /* + var panelMap = Firebug.panelTypes; + for (var i=0, p; p=panelMap[i]; i++) + { + if (!p.parentPanel) + { + this.addPanel(p.prototype.name); + } + } + /**/ + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.initialize(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + this.addController( + [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine] + ); + + // ************************************************************************************************ + + // Select the first registered panel + // TODO: BUG IE7 + var self = this; + setTimeout(function(){ + self.selectPanel(FirebugChrome.selectedPanelName); + + if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine) + Firebug.chrome.focusCommandLine(); + },0); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + //this.draw(); + + + + + + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + var onPanelMouseDown = function onPanelMouseDown(event) + { + //console.log("onPanelMouseDown", event.target || event.srcElement, event); + + var target = event.target || event.srcElement; + + if (FBL.isLeftClick(event)) + { + var editable = FBL.getAncestorByClass(target, "editable"); + + // if an editable element has been clicked then start editing + if (editable) + { + Firebug.Editor.startEditing(editable); + FBL.cancelEvent(event); + } + // if any other element has been clicked then stop editing + else + { + if (!hasClass(target, "textEditorInner")) + Firebug.Editor.stopEditing(); + } + } + else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target)) + { + // Prevent auto-scroll when middle-clicking a rep object + FBL.cancelEvent(event); + } + }; + + Firebug.getElementPanel = function(element) + { + var panelNode = getAncestorByClass(element, "fbPanel"); + var id = panelNode.id.substr(2); + + var panel = Firebug.chrome.panelMap[id]; + + if (!panel) + { + if (Firebug.chrome.selectedPanel.sidePanelBar) + panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; + } + + return panel; + }; + + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // TODO: xxxpedro port to Firebug + + // Improved window key code event listener. Only one "keydown" event will be attached + // to the window, and the onKeyCodeListen() function will delegate which listeners + // should be called according to the event.keyCode fired. + var onKeyCodeListenersMap = []; + var onKeyCodeListen = function(event) + { + for (var keyCode in onKeyCodeListenersMap) + { + var listeners = onKeyCodeListenersMap[keyCode]; + + for (var i = 0, listener; listener = listeners[i]; i++) + { + var filter = listener.filter || FBL.noKeyModifiers; + + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener.listener(); + FBL.cancelEvent(event, true); + return false; + } + } + } + }; + + addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); + + /** + * @name keyCodeListen + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + var keyCode = KeyEvent["DOM_VK_"+key]; + + if (!onKeyCodeListenersMap[keyCode]) + onKeyCodeListenersMap[keyCode] = []; + + onKeyCodeListenersMap[keyCode].push({ + filter: filter, + listener: listener + }); + + return keyCode; + }; + + /** + * @name keyIgnore + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyIgnore = function(keyCode) + { + onKeyCodeListenersMap[keyCode] = null; + delete onKeyCodeListenersMap[keyCode]; + }; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + /**/ + // move to shutdown + //removeEvent(Firebug.chrome.document, "keydown", listener[0]); + + + /* + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + if (!filter) + filter = FBL.noKeyModifiers; + + var keyCode = KeyEvent["DOM_VK_"+key]; + + var fn = function fn(event) + { + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener(); + FBL.cancelEvent(event, true); + return false; + } + } + + addEvent(Firebug.chrome.document, "keydown", fn); + + return [fn, capture]; + }; + + Firebug.chrome.keyIgnore = function(listener) + { + removeEvent(Firebug.chrome.document, "keydown", listener[0]); + }; + /**/ + + + this.addController( + [fbPanel1, "mousedown", onPanelMouseDown], + [fbPanel2, "mousedown", onPanelMouseDown] + ); +/**/ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + + // menus can be used without domplate + if (FBL.domplate) + this.testMenu(); + /**/ + + //test XHR + /* + setTimeout(function(){ + + FBL.Ajax.request({url: "../content/firebug/boot.js"}); + FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); + + },1000); + /**/ + }, + + shutdown: function() + { + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + if(Firebug.Inspector) + this.inspectButton.shutdown(); + + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // remove disableTextSelection event handlers + restoreTextSelection($("fbToolbar")); + restoreTextSelection($("fbPanelBarBox")); + restoreTextSelection($("fbPanelBar1")); + restoreTextSelection($("fbPanelBar2")); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // shutdown inherited classes + Controller.shutdown.call(this); + PanelBar.shutdown.call(this); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Remove the interface elements cache (this must happen after calling + // the shutdown method of all dependent components to avoid errors) + + fbTop = null; + fbContent = null; + fbContentStyle = null; + fbBottom = null; + fbBtnInspect = null; + + fbToolbar = null; + + fbPanelBox1 = null; + fbPanelBox1Style = null; + fbPanelBox2 = null; + fbPanelBox2Style = null; + fbPanelBar2Box = null; + fbPanelBar2BoxStyle = null; + + fbHSplitter = null; + fbVSplitter = null; + fbVSplitterStyle = null; + + fbPanel1 = null; + fbPanel1Style = null; + fbPanel2 = null; + + fbConsole = null; + fbConsoleStyle = null; + fbHTML = null; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + + topHeight = null; + topPartialHeight = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + toggle: function(forceOpen, popup) + { + if(popup) + { + this.detach(); + } + else + { + if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) + { + var frame = FirebugChrome.chromeMap.frame; + frame.reattach(); + + FirebugChrome.chromeMap.popup = null; + + frame.open(); + + return; + } + + // If the context is a popup, ignores the toggle process + if (Firebug.chrome.type == "popup") return; + + var shouldOpen = forceOpen || !FirebugChrome.isOpen; + + if(shouldOpen) + this.open(); + else + this.close(); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + detach: function() + { + if(!FirebugChrome.chromeMap.popup) + { + createChromeWindow({type: "popup"}); + } + }, + + reattach: function(oldChrome, newChrome) + { + Firebug.browser.window.Firebug = Firebug; + + // chrome synchronization + var newPanelMap = newChrome.panelMap; + var oldPanelMap = oldChrome.panelMap; + + var panel; + for(var name in newPanelMap) + { + // TODO: xxxpedro innerHTML + panel = newPanelMap[name]; + if (panel.options.innerHTMLSync) + panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; + } + + Firebug.chrome = newChrome; + + // TODO: xxxpedro sync detach reattach attach + //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); + + if (newChrome.type == "popup") + { + newChrome.initialize(); + //dispatch(Firebug.modules, "initialize", []); + } + else + { + // TODO: xxxpedro only needed in persistent + // should use FirebugChrome.clone, but popup FBChrome + // isn't acessible + FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name; + } + + dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + draw: function() + { + var size = this.getSize(); + + // Height related values + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, + + y = Math.max(size.height /* chrome height */, topHeight), + + heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), + + height = heightValue + "px", + + // Width related values + sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0, + + width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Height related rendering + fbPanelBox1Style.height = height; + fbPanel1Style.height = height; + + if (isIE || isOpera) + { + // Fix IE and Opera problems with auto resizing the verticall splitter + fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px"; + } + //xxxpedro FF2 only? + /* + else if (isFirefox) + { + // Fix Firefox problem with table rows with 100% height (fit height) + fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px"; + }/**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Width related rendering + fbPanelBox1Style.width = width; + fbPanel1Style.width = width; + + // SidePanel rendering + if (Firebug.chrome.sidePanelVisible) + { + sideWidthValue = Math.max(sideWidthValue - 6, 0); + + var sideWidth = sideWidthValue + "px"; + + fbPanelBox2Style.width = sideWidth; + + fbVSplitterStyle.right = sideWidth; + + if (Firebug.chrome.largeCommandLineVisible) + { + fbLargeCommandLine = $("fbLargeCommandLine"); + + fbLargeCommandLine.style.height = heightValue - 4 + "px"; + fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; + + fbLargeCommandButtons = $("fbLargeCommandButtons"); + fbLargeCommandButtons.style.width = sideWidth; + } + else + { + fbPanel2Style.height = height; + fbPanel2Style.width = sideWidth; + + fbPanelBar2BoxStyle.width = sideWidth; + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getSize: function() + { + return this.type == "div" ? + { + height: this.node.offsetHeight, + width: this.node.offsetWidth + } + : + this.getWindowSize(); + }, + + resize: function() + { + var self = this; + + // avoid partial resize when maximizing window + setTimeout(function(){ + self.draw(); + + if (noFixedPosition && (self.type == "frame" || self.type == "div")) + self.fixIEPosition(); + }, 0); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + layout: function(panel) + { + if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); + + var options = panel.options; + + changeCommandLineVisibility(options.hasCommandLine); + changeSidePanelVisibility(panel.hasSidePanel); + + Firebug.chrome.draw(); + }, + + showLargeCommandLine: function(hideToggleIcon) + { + var chrome = Firebug.chrome; + + if (!chrome.largeCommandLineVisible) + { + chrome.largeCommandLineVisible = true; + + if (chrome.selectedPanel.options.hasCommandLine) + { + if (Firebug.CommandLine) + Firebug.CommandLine.blur(); + + changeCommandLineVisibility(false); + } + + changeSidePanelVisibility(true); + + fbLargeCommandLine.style.display = "block"; + fbLargeCommandButtons.style.display = "block"; + + fbPanel2Style.display = "none"; + fbPanelBar2BoxStyle.display = "none"; + + chrome.draw(); + + fbLargeCommandLine.focus(); + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(true); + } + }, + + hideLargeCommandLine: function() + { + if (Firebug.chrome.largeCommandLineVisible) + { + Firebug.chrome.largeCommandLineVisible = false; + + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(false); + + fbLargeCommandLine.blur(); + + fbPanel2Style.display = "block"; + fbPanelBar2BoxStyle.display = "block"; + + fbLargeCommandLine.style.display = "none"; + fbLargeCommandButtons.style.display = "none"; + + changeSidePanelVisibility(false); + + if (Firebug.chrome.selectedPanel.options.hasCommandLine) + changeCommandLineVisibility(true); + + Firebug.chrome.draw(); + + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focusCommandLine: function() + { + var selectedPanelName = this.selectedPanel.name, panelToSelect; + + if (focusCommandLineState == 0 || selectedPanelName != "Console") + { + focusCommandLineState = 0; + lastFocusedPanelName = selectedPanelName; + + panelToSelect = "Console"; + } + if (focusCommandLineState == 1) + { + panelToSelect = lastFocusedPanelName; + } + + this.selectPanel(panelToSelect); + + try + { + if (Firebug.CommandLine) + { + if (panelToSelect == "Console") + Firebug.CommandLine.focus(); + else + Firebug.CommandLine.blur(); + } + } + catch(e) + { + //TODO: xxxpedro trace error + } + + focusCommandLineState = ++focusCommandLineState % 2; + } + +}); + +// ************************************************************************************************ +// ChromeFrameBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromeFrameBase = extend(ChromeBase, +/**@extend ns-chrome-ChromeFrameBase*/ +{ + create: function() + { + ChromeBase.create.call(this); + + // restore display for the anti-flicker trick + if (isFirefox) + this.node.style.display = "block"; + + if (Env.Options.startInNewWindow) + { + this.close(); + this.toggle(true, true); + return; + } + + if (Env.Options.startOpened) + this.open(); + else + this.close(); + }, + + destroy: function() + { + removeGlobalEvent("keydown", onGlobalKeyDown); + + ChromeBase.destroy.call(this); + + this.document = null; + delete this.document; + + this.window = null; + delete this.window; + + this.node.parentNode.removeChild(this.node); + this.node = null; + delete this.node; + }, + + initialize: function() + { + //FBTrace.sysout("Frame", "initialize();") + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.browser.window, "resize", this.resize], + [$("fbWindow_btClose"), "click", this.close], + [$("fbWindow_btDetach"), "click", this.detach], + [$("fbWindow_btDeactivate"), "click", this.deactivate] + ); + + if (!Env.Options.enablePersistent) + this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + fbVSplitter.onmousedown = onVSplitterMouseDown; + fbHSplitter.onmousedown = onHSplitterMouseDown; + + this.isInitialized = true; + }, + + shutdown: function() + { + fbVSplitter.onmousedown = null; + fbHSplitter.onmousedown = null; + + ChromeBase.shutdown.apply(this); + + this.isInitialized = false; + }, + + reattach: function() + { + var frame = FirebugChrome.chromeMap.frame; + + ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); + }, + + open: function() + { + if (!FirebugChrome.isOpen) + { + FirebugChrome.isOpen = true; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,1"); + + var node = this.node; + + node.style.visibility = "hidden"; // Avoid flickering + + if (Firebug.showIconWhenHidden) + { + if (ChromeMini.isInitialized) + { + ChromeMini.shutdown(); + } + + } + else + node.style.display = "block"; + + var main = $("fbChrome"); + + // IE6 throws an error when setting this property! why? + //main.style.display = "table"; + main.style.display = ""; + + var self = this; + setTimeout(function(){ + node.style.visibility = "visible"; + + //dispatch(Firebug.modules, "initialize", []); + self.initialize(); + + if (noFixedPosition) + self.fixIEPosition(); + + self.draw(); + + }, 10); + } + }, + + close: function() + { + if (FirebugChrome.isOpen || !this.isInitialized) + { + if (this.isInitialized) + { + //dispatch(Firebug.modules, "shutdown", []); + this.shutdown(); + } + + FirebugChrome.isOpen = false; + + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,0"); + + var node = this.node; + + if (Firebug.showIconWhenHidden) + { + node.style.visibility = "hidden"; // Avoid flickering + + // TODO: xxxpedro - persist IE fixed? + var main = $("fbChrome", FirebugChrome.chromeMap.frame.document); + main.style.display = "none"; + + ChromeMini.initialize(); + + node.style.visibility = "visible"; + } + else + node.style.display = "none"; + } + }, + + deactivate: function() + { + // if it is running as a Chrome extension, dispatch a message to the extension signaling + // that Firebug should be deactivated for the current tab + if (Env.isChromeExtension) + { + localStorage.removeItem("Firebug"); + Firebug.GoogleChrome.dispatch("FB_deactivate"); + + // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole + // app, otherwise it won't be able to be reactivated without reloading the page. + // but we need to stop listening global keys, otherwise the key activation won't work. + Firebug.chrome.close(); + } + else + { + Firebug.shutdown(); + } + }, + + fixIEPosition: function() + { + // fix IE problem with offset when not in fullscreen mode + var doc = this.document; + var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0; + + var size = Firebug.browser.getWindowSize(); + var scroll = Firebug.browser.getWindowScrollPosition(); + var maxHeight = size.height; + var height = this.node.offsetHeight; + + var bodyStyle = doc.body.currentStyle; + + this.node.style.top = maxHeight - height + scroll.top + "px"; + + if ((this.type == "frame" || this.type == "div") && + (bodyStyle.marginLeft || bodyStyle.marginRight)) + { + this.node.style.width = size.width + "px"; + } + + if (fbVSplitterStyle) + fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px"; + + this.draw(); + } + +}); + + +// ************************************************************************************************ +// ChromeMini + +/** + * @namespace + * @extends FBL.Controller + */ +var ChromeMini = extend(Controller, +/**@extend ns-chrome-ChromeMini*/ +{ + create: function(chrome) + { + append(this, chrome); + this.type = "mini"; + }, + + initialize: function() + { + Controller.initialize.apply(this); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "block"; + + var miniIcon = $("fbMiniIcon", doc); + var width = miniIcon.offsetWidth + 10; + miniIcon.title = "Open " + Firebug.version; + + var errors = $("fbMiniErrors", doc); + if (errors.offsetWidth) + width += errors.offsetWidth + 10; + + var node = this.node; + node.style.height = "27px"; + node.style.width = width + "px"; + node.style.left = ""; + node.style.right = 0; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "true"); + this.document.body.style.backgroundColor = "transparent"; + } + else + node.style.background = "transparent"; + + if (noFixedPosition) + this.fixIEPosition(); + + this.addController( + [$("fbMiniIcon", doc), "click", onMiniIconClick] + ); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } + + this.isInitialized = true; + }, + + shutdown: function() + { + var node = this.node; + node.style.height = FirebugChrome.height + "px"; + node.style.width = "100%"; + node.style.left = 0; + node.style.right = ""; + + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "false"); + this.document.body.style.backgroundColor = "#fff"; + } + else + node.style.background = "#fff"; + + if (noFixedPosition) + this.fixIEPosition(); + + var doc = FirebugChrome.chromeMap.frame.document; + + var mini = $("fbMiniChrome", doc); + mini.style.display = "none"; + + Controller.shutdown.apply(this); + + this.isInitialized = false; + }, + + draw: function() + { + + }, + + fixIEPosition: ChromeFrameBase.fixIEPosition + +}); + + +// ************************************************************************************************ +// ChromePopupBase + +/** + * @namespace + * @extends ns-chrome-ChromeBase + */ +var ChromePopupBase = extend(ChromeBase, +/**@extend ns-chrome-ChromePopupBase*/ +{ + + initialize: function() + { + setClass(this.document.body, "FirebugPopup"); + + ChromeBase.initialize.call(this); + + this.addController( + [Firebug.chrome.window, "resize", this.resize], + [Firebug.chrome.window, "unload", this.destroy] + ); + + if (Env.Options.enablePersistent) + { + this.persist = bind(this.persist, this); + addEvent(Firebug.browser.window, "unload", this.persist); + } + else + this.addController( + [Firebug.browser.window, "unload", this.close] + ); + + fbVSplitter.onmousedown = onVSplitterMouseDown; + }, + + destroy: function() + { + // TODO: xxxpedro sync detach reattach attach + var frame = FirebugChrome.chromeMap.frame; + + if(frame) + { + dispatch(frame.panelMap, "detach", [this, frame]); + + frame.reattach(this, frame); + } + + if (Env.Options.enablePersistent) + { + removeEvent(Firebug.browser.window, "unload", this.persist); + } + + ChromeBase.destroy.apply(this); + + FirebugChrome.chromeMap.popup = null; + + this.node.close(); + }, + + persist: function() + { + persistTimeStart = new Date().getTime(); + + removeEvent(Firebug.browser.window, "unload", this.persist); + + Firebug.Inspector.destroy(); + Firebug.browser.window.FirebugOldBrowser = true; + + var persistTimeStart = new Date().getTime(); + + var waitMainWindow = function() + { + var doc, head; + + try + { + if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && + doc.documentElement && (head = doc.documentElement.firstChild)*/) + { + + try + { + // exposes the FBL to the global namespace when in debug mode + if (Env.isDebugMode) + { + window.FBL = FBL; + } + + window.Firebug = Firebug; + window.opener.Firebug = Firebug; + + Env.browser = window.opener; + Firebug.browser = Firebug.context = new Context(Env.browser); + + registerConsole(); + + // the delay time should be calculated right after registering the + // console, once right after the console registration, call log messages + // will be properly handled + var persistDelay = new Date().getTime() - persistTimeStart; + + var chrome = Firebug.chrome; + addEvent(Firebug.browser.window, "unload", chrome.persist); + + FBL.cacheDocument(); + Firebug.Inspector.create(); + + var htmlPanel = chrome.getPanel("HTML"); + htmlPanel.createUI(); + + Firebug.Console.logFormatted( + ["Firebug could not capture console calls during " + + persistDelay + "ms"], + Firebug.context, + "info" + ); + } + catch(pE) + { + alert("persist error: " + (pE.message || pE)); + } + + } + else + { + window.setTimeout(waitMainWindow, 0); + } + + } catch (E) { + window.close(); + } + }; + + waitMainWindow(); + }, + + close: function() + { + this.destroy(); + } + +}); + + +//************************************************************************************************ +// UI helpers + +var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) +{ + var last = Firebug.chrome.commandLineVisible; + var visible = Firebug.chrome.commandLineVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; + + if (visible != last) + { + if (visible) + { + fbBottom.className = ""; + + if (Firebug.CommandLine) + Firebug.CommandLine.activate(); + } + else + { + if (Firebug.CommandLine) + Firebug.CommandLine.deactivate(); + + fbBottom.className = "hide"; + } + } +}; + +var changeSidePanelVisibility = function changeSidePanelVisibility(visibility) +{ + var last = Firebug.chrome.sidePanelVisible; + Firebug.chrome.sidePanelVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible; + + if (Firebug.chrome.sidePanelVisible != last) + { + fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + } +}; + + +// ************************************************************************************************ +// F12 Handler + +var onGlobalKeyDown = function onGlobalKeyDown(event) +{ + var keyCode = event.keyCode; + var shiftKey = event.shiftKey; + var ctrlKey = event.ctrlKey; + + if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox)) + { + Firebug.chrome.toggle(false, ctrlKey); + cancelEvent(event, true); + + // TODO: xxxpedro replace with a better solution. we're doing this + // to allow reactivating with the F12 key after being deactivated + if (Env.isChromeExtension) + { + Firebug.GoogleChrome.dispatch("FB_enableIcon"); + } + } + else if (keyCode == 67 /* C */ && ctrlKey && shiftKey) + { + Firebug.Inspector.toggleInspect(); + cancelEvent(event, true); + } + else if (keyCode == 76 /* L */ && ctrlKey && shiftKey) + { + Firebug.chrome.focusCommandLine(); + cancelEvent(event, true); + } +}; + +var onMiniIconClick = function onMiniIconClick(event) +{ + Firebug.chrome.toggle(false, event.ctrlKey); + cancelEvent(event, true); +}; + + +// ************************************************************************************************ +// Horizontal Splitter Handling + +var onHSplitterMouseDown = function onHSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onHSplitterMouseMove); + addGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = "fbOnMovingHSplitter"; + + return false; +}; + +var onHSplitterMouseMove = function onHSplitterMouseMove(event) +{ + cancelEvent(event, true); + + var clientY = event.clientY; + var win = isIE + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument && event.target.ownerDocument.defaultView; + + if (!win) + return; + + if (win != win.parent) + { + var frameElement = win.frameElement; + if (frameElement) + { + var framePos = Firebug.browser.getElementPosition(frameElement).top; + clientY += framePos; + + if (frameElement.style.position != "fixed") + clientY -= Firebug.browser.getWindowScrollPosition().top; + } + } + + if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI") + { + clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY; + } + /* + console.log( + typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome", + //win.frameElement.id, + event.target, + clientY + );/**/ + + onHSplitterMouseMoveBuffer = clientY; // buffer + + if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + lastHSplitterMouseMove = new Date().getTime(); + handleHSplitterMouseMove(); + } + else + if (!onHSplitterMouseMoveTimer) + onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate); + + // improving the resizing performance by canceling the mouse event. + // canceling events will prevent the page to receive such events, which would imply + // in more processing being expended. + cancelEvent(event, true); + return false; +}; + +var handleHSplitterMouseMove = function() +{ + if (onHSplitterMouseMoveTimer) + { + clearTimeout(onHSplitterMouseMoveTimer); + onHSplitterMouseMoveTimer = null; + } + + var clientY = onHSplitterMouseMoveBuffer; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + + // compute chrome fixed size (top bar and command line) + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0; + var fixedHeight = topHeight + commandLineHeight; + var chromeNode = Firebug.chrome.node; + + var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; + + //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; + var height = windowSize.height; + + // compute the min and max size of the chrome + var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight); + chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize); + + FirebugChrome.height = chromeHeight; + chromeNode.style.height = chromeHeight + "px"; + + if (noFixedPosition) + Firebug.chrome.fixIEPosition(); + + Firebug.chrome.draw(); +}; + +var onHSplitterMouseUp = function onHSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onHSplitterMouseMove); + removeGlobalEvent("mouseup", onHSplitterMouseUp); + + if (isIE) + removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + + fbHSplitter.className = ""; + + Firebug.chrome.draw(); + + // avoid text selection in IE when returning to the document + // after the mouse leaves the document during the resizing + return false; +}; + + +// ************************************************************************************************ +// Vertical Splitter Handling + +var onVSplitterMouseDown = function onVSplitterMouseDown(event) +{ + addGlobalEvent("mousemove", onVSplitterMouseMove); + addGlobalEvent("mouseup", onVSplitterMouseUp); + + return false; +}; + +var onVSplitterMouseMove = function onVSplitterMouseMove(event) +{ + if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + { + var target = event.target || event.srcElement; + if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome + { + var clientX = event.clientX; + var win = document.all + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument.defaultView; + + if (win != win.parent) + clientX += win.frameElement ? win.frameElement.offsetLeft : 0; + + var size = Firebug.chrome.getSize(); + var x = Math.max(size.width - clientX + 3, 6); + + FirebugChrome.sidePanelWidth = x; + Firebug.chrome.draw(); + } + + lastVSplitterMouseMove = new Date().getTime(); + } + + cancelEvent(event, true); + return false; +}; + +var onVSplitterMouseUp = function onVSplitterMouseUp(event) +{ + removeGlobalEvent("mousemove", onVSplitterMouseMove); + removeGlobalEvent("mouseup", onVSplitterMouseUp); + + Firebug.chrome.draw(); +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Browser = function(window) +{ + this.contentWindow = window; + this.contentDocument = window.document; + this.currentURI = + { + spec: window.location.href + }; +}; + +Firebug.Lite.Browser.prototype = +{ + toString: function() + { + return "Firebug.Lite.Browser"; + } +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Cache = +{ + ID: "firebug" + new Date().getTime() +}; + +// ************************************************************************************************ + +/** + * TODO: if a cached element is cloned, the expando property will be cloned too in IE + * which will result in a bug. Firebug Lite will think the new cloned node is the old + * one. + * + * TODO: Investigate a possibility of cache validation, to be customized by each + * kind of cache. For ElementCache it should validate if the element still is + * inserted at the DOM. + */ +var cacheUID = 0; +var createCache = function() +{ + var map = {}; + var CID = Firebug.Lite.Cache.ID; + + // better detection + var supportsDeleteExpando = !document.all; + + var cacheFunction = function(element) + { + return cacheAPI.set(element); + }; + + var cacheAPI = + { + get: function(key) + { + return map.hasOwnProperty(key) ? + map[key] : + null; + }, + + set: function(element) + { + var id = element[CID]; + + if (!id) + { + id = ++cacheUID; + element[CID] = id; + } + + if (!map.hasOwnProperty(id)) + { + map[id] = element; + } + + return id; + }, + + unset: function(element) + { + var id = element[CID]; + + if (supportsDeleteExpando) + { + delete element[CID]; + } + else if (element.removeAttribute) + { + element.removeAttribute(CID); + } + + delete map[id]; + + }, + + key: function(element) + { + return element[CID]; + }, + + has: function(element) + { + return map.hasOwnProperty(element[CID]); + }, + + clear: function() + { + for (var id in map) + { + var element = map[id]; + cacheAPI.unset(element); + } + } + }; + + FBL.append(cacheFunction, cacheAPI); + + return cacheFunction; +}; + +// ************************************************************************************************ + +// TODO: xxxpedro : check if we need really this on FBL scope +Firebug.Lite.Cache.StyleSheet = createCache(); +Firebug.Lite.Cache.Element = createCache(); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +Firebug.Lite.Proxy = +{ + // jsonp callbacks + _callbacks: {}, + + /** + * Load a resource, either locally (directly) or externally (via proxy) using + * synchronous XHR calls. Loading external resources requires the proxy plugin to + * be installed and configured (see /plugin/proxy/proxy.php). + */ + load: function(url) + { + var resourceDomain = getDomain(url); + var isLocalResource = + // empty domain means local URL + !resourceDomain || + // same domain means local too + resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context + + return isLocalResource ? fetchResource(url) : fetchProxyResource(url); + }, + + /** + * Load a resource using JSONP technique. + */ + loadJSONP: function(url, callback) + { + var script = createGlobalElement("script"), + doc = Firebug.context.document, + + uid = "" + new Date().getTime(), + callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, + + jsonpURL = url.indexOf("?") != -1 ? + url + "&" + callbackName : + url + "?" + callbackName; + + Firebug.Lite.Proxy._callbacks[uid] = function(data) + { + if (callback) + callback(data); + + script.parentNode.removeChild(script); + delete Firebug.Lite.Proxy._callbacks[uid]; + }; + + script.src = jsonpURL; + + if (doc.documentElement) + doc.documentElement.appendChild(script); + }, + + /** + * Load a resource using YQL (not reliable). + */ + YQL: function(url, callback) + { + var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + + encodeURIComponent(url) + "%22&format=xml"; + + this.loadJSONP(yql, function(data) + { + var source = data.results[0]; + + // clean up YQL bogus elements + var match = /\s+

      ([\s\S]+)<\/p>\s+<\/body>$/.exec(source); + if (match) + source = match[1]; + + console.log(source); + }); + } +}; + +// ************************************************************************************************ + +var fetchResource = function(url) +{ + var xhr = FBL.Ajax.getXHRObject(); + xhr.open("get", url, false); + xhr.send(); + + return xhr.responseText; +}; + +var fetchProxyResource = function(url) +{ + var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); + var response = fetchResource(proxyURL); + + try + { + var data = eval("(" + response + ")"); + } + catch(E) + { + return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; + } + + return data ? data.contents : ""; +}; + + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Script = function(window) +{ + this.fileName = null; + this.isValid = null; + this.baseLineNumber = null; + this.lineExtent = null; + this.tag = null; + + this.functionName = null; + this.functionSource = null; +}; + +Firebug.Lite.Script.prototype = +{ + isLineExecutable: function(){}, + pcToLine: function(){}, + lineToPc: function(){}, + + toString: function() + { + return "Firebug.Lite.Script"; + } +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +Firebug.Lite.Style = +{ +}; + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns( /**@scope ns-selector*/ function() { with (FBL) { +// ************************************************************************************************ + +/* + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +/** + * @name Firebug.Selector + * @namespace + */ + +/** + * @exports Sizzle as Firebug.Selector + */ +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +/**#@+ @ignore */ +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + if ( div.getElementsByClassName("e").length === 0 ) + return; + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE + +Firebug.Selector = Sizzle; + +/**#@-*/ + +// ************************************************************************************************ +}}); + +// Problems in IE +// FIXED - eval return +// FIXED - addEventListener problem in IE +// FIXED doc.createRange? +// +// class reserved word +// test all honza examples in IE6 and IE7 + + +/* See license.txt for terms of usage */ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function DomplateTag(tagName) +{ + this.tagName = tagName; +} + +function DomplateEmbed() +{ +} + +function DomplateLoop() +{ +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +( /** @scope ns-domplate */ function() { + +var womb = null; + +var domplate = FBL.domplate = function() +{ + var lastSubject; + for (var i = 0; i < arguments.length; ++i) + lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i]; + + for (var name in lastSubject) + { + var val = lastSubject[name]; + if (isTag(val)) + val.tag.subject = lastSubject; + } + + return lastSubject; +}; + +domplate.context = function(context, fn) +{ + var lastContext = domplate.lastContext; + domplate.topContext = context; + fn.apply(context); + domplate.topContext = lastContext; +}; + +FBL.TAG = function() +{ + var embed = new DomplateEmbed(); + return embed.merge(arguments); +}; + +FBL.FOR = function() +{ + var loop = new DomplateLoop(); + return loop.merge(arguments); +}; + +DomplateTag.prototype = +{ + merge: function(args, oldTag) + { + if (oldTag) + this.tagName = oldTag.tagName; + + this.context = oldTag ? oldTag.context : null; + this.subject = oldTag ? oldTag.subject : null; + this.attrs = oldTag ? copyObject(oldTag.attrs) : {}; + this.classes = oldTag ? copyObject(oldTag.classes) : {}; + this.props = oldTag ? copyObject(oldTag.props) : null; + this.listeners = oldTag ? copyArray(oldTag.listeners) : null; + this.children = oldTag ? copyArray(oldTag.children) : []; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args.length ? args[0] : null; + var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); + + this.children = []; + + if (domplate.topContext) + this.context = domplate.topContext; + + if (args.length) + parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); + + if (hasAttrs) + this.parseAttrs(attrs); + + return creator(this, DomplateTag); + }, + + parseAttrs: function(args) + { + for (var name in args) + { + var val = parseValue(args[name]); + readPartNames(val, this.vars); + + if (name.indexOf("on") == 0) + { + var eventName = name.substr(2); + if (!this.listeners) + this.listeners = []; + this.listeners.push(eventName, val); + } + else if (name.indexOf("_") == 0) + { + var propName = name.substr(1); + if (!this.props) + this.props = {}; + this.props[propName] = val; + } + else if (name.indexOf("$") == 0) + { + var className = name.substr(1); + if (!this.classes) + this.classes = {}; + this.classes[className] = val; + } + else + { + if (name == "class" && this.attrs.hasOwnProperty(name) ) + this.attrs[name] += " " + val; + else + this.attrs[name] = val; + } + } + }, + + compile: function() + { + if (this.renderMarkup) + return; + + this.compileMarkup(); + this.compileDOM(); + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs); + }, + + compileMarkup: function() + { + this.markupArgs = []; + var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; + + this.generateMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + + var fnBlock = ['r=(function (__code__, __context__, __in__, __out__']; + for (var i = 0; i < info.argIndex; ++i) + fnBlock.push(', s', i); + fnBlock.push(') {'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (__context__) {'); + fnBlock.push('with (__in__) {'); + + fnBlock.push.apply(fnBlock, blocks); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('}})'); + + function __link__(tag, code, outputs, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var tagOutputs = []; + var markupArgs = [code, tag.tag.context, args, tagOutputs]; + markupArgs.push.apply(markupArgs, tag.tag.markupArgs); + tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs); + + outputs.push(tag); + outputs.push(tagOutputs); + } + + function __escape__(value) + { + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); + } + + function __loop__(iter, outputs, fn) + { + var iterOuts = []; + outputs.push(iterOuts); + + if (iter instanceof Array) + iter = new ArrayIterator(iter); + + try + { + while (1) + { + var value = iter.next(); + var itemOuts = [0,0]; + iterOuts.push(itemOuts); + fn.apply(this, [value, itemOuts]); + } + } + catch (exc) + { + if (exc != StopIteration) + throw exc; + } + } + + var js = fnBlock.join(""); + var r = null; + eval(js); + this.renderMarkup = r; + }, + + getVarNames: function(args) + { + if (this.vars) + args.push.apply(args, this.vars); + + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.getVarNames(args); + else if (child instanceof Parts) + { + for (var i = 0; i < child.parts.length; ++i) + { + if (child.parts[i] instanceof Variable) + { + var name = child.parts[i].name; + var names = name.split("."); + args.push(names[0]); + } + } + } + } + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + topBlock.push(',"<', this.tagName, '"'); + + for (var name in this.attrs) + { + if (name != "class") + { + var val = this.attrs[name]; + topBlock.push(', " ', name, '=\\""'); + addParts(val, ',', topBlock, info, true); + topBlock.push(', "\\""'); + } + } + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + readPartNames(this.listeners[i+1], topOuts); + } + + if (this.props) + { + for (var name in this.props) + readPartNames(this.props[name], topOuts); + } + + if ( this.attrs.hasOwnProperty("class") || this.classes) + { + topBlock.push(', " class=\\""'); + if (this.attrs.hasOwnProperty("class")) + addParts(this.attrs["class"], ',', topBlock, info, true); + topBlock.push(', " "'); + for (var name in this.classes) + { + topBlock.push(', ('); + addParts(this.classes[name], '', topBlock, info); + topBlock.push(' ? "', name, '" + " " : "")'); + } + topBlock.push(', "\\""'); + } + topBlock.push(',">"'); + + this.generateChildMarkup(topBlock, topOuts, blocks, info); + topBlock.push(',""'); + }, + + generateChildMarkup: function(topBlock, topOuts, blocks, info) + { + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + child.tag.generateMarkup(topBlock, topOuts, blocks, info); + else + addParts(child, ',', topBlock, info, true); + } + }, + + addCode: function(topBlock, topOuts, blocks) + { + if (topBlock.length) + blocks.push('__code__.push(""', topBlock.join(""), ');'); + if (topOuts.length) + blocks.push('__out__.push(', topOuts.join(","), ');'); + topBlock.splice(0, topBlock.length); + topOuts.splice(0, topOuts.length); + }, + + addLocals: function(blocks) + { + var varNames = []; + this.getVarNames(varNames); + + var map = {}; + for (var i = 0; i < varNames.length; ++i) + { + var name = varNames[i]; + if ( map.hasOwnProperty(name) ) + continue; + + map[name] = 1; + var names = name.split("."); + blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); + } + }, + + compileDOM: function() + { + var path = []; + var blocks = []; + this.domArgs = []; + path.embedIndex = 0; + path.loopIndex = 0; + path.staticIndex = 0; + path.renderIndex = 0; + var nodeCount = this.generateDOM(path, blocks, this.domArgs); + + var fnBlock = ['r=(function (root, context, o']; + + for (var i = 0; i < path.staticIndex; ++i) + fnBlock.push(', ', 's'+i); + + for (var i = 0; i < path.renderIndex; ++i) + fnBlock.push(', ', 'd'+i); + + fnBlock.push(') {'); + for (var i = 0; i < path.loopIndex; ++i) + fnBlock.push('var l', i, ' = 0;'); + for (var i = 0; i < path.embedIndex; ++i) + fnBlock.push('var e', i, ' = 0;'); + + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (context) {'); + + fnBlock.push(blocks.join("")); + + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); + + fnBlock.push('return ', nodeCount, ';'); + fnBlock.push('})'); + + function __bind__(object, fn) + { + return function(event) { return fn.apply(object, [event]); }; + } + + function __link__(node, tag, args) + { + if (!tag || !tag.tag) + return; + + tag.tag.compile(); + + var domArgs = [node, tag.tag.context, 0]; + domArgs.push.apply(domArgs, tag.tag.domArgs); + domArgs.push.apply(domArgs, args); + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs); + return tag.tag.renderDOM.apply(tag.tag.subject, domArgs); + } + + var self = this; + function __loop__(iter, fn) + { + var nodeCount = 0; + for (var i = 0; i < iter.length; ++i) + { + iter[i][0] = i; + iter[i][1] = nodeCount; + nodeCount += fn.apply(this, iter[i]); + //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount); + } + return nodeCount; + } + + function __path__(parent, offset) + { + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); + var root = parent; + + for (var i = 2; i < arguments.length; ++i) + { + var index = arguments[i]; + if (i == 3) + index += offset; + + if (index == -1) + parent = parent.parentNode; + else + parent = parent.childNodes[index]; + } + + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); + return parent; + } + + var js = fnBlock.join(""); + //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); + var r = null; + eval(js); + this.renderDOM = r; + }, + + generateDOM: function(path, blocks, args) + { + if (this.listeners || this.props) + this.generateNodePath(path, blocks); + + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + { + var val = this.listeners[i+1]; + var arg = generateArg(val, path, args); + //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);'); + } + } + + if (this.props) + { + for (var name in this.props) + { + var val = this.props[name]; + var arg = generateArg(val, path, args); + blocks.push('node.', name, ' = ', arg, ';'); + } + } + + this.generateChildDOM(path, blocks, args); + return 1; + }, + + generateNodePath: function(path, blocks) + { + blocks.push("var node = __path__(root, o"); + for (var i = 0; i < path.length; ++i) + blocks.push(",", path[i]); + blocks.push(");"); + }, + + generateChildDOM: function(path, blocks, args) + { + path.push(0); + for (var i = 0; i < this.children.length; ++i) + { + var child = this.children[i]; + if (isTag(child)) + path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args); + else + path[path.length-1] += '+1'; + } + path.pop(); + } +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateEmbed.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.value = oldTag ? oldTag.value : parseValue(args[0]); + this.attrs = oldTag ? oldTag.attrs : {}; + this.vars = oldTag ? copyArray(oldTag.vars) : []; + + var attrs = args[1]; + for (var name in attrs) + { + var val = parseValue(attrs[name]); + this.attrs[name] = val; + readPartNames(val, this.vars); + } + + return creator(this, DomplateEmbed); + }, + + getVarNames: function(names) + { + if (this.value instanceof Parts) + names.push(this.value.parts[0].name); + + if (this.vars) + names.push.apply(names, this.vars); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + blocks.push('__link__('); + addParts(this.value, '', blocks, info); + blocks.push(', __code__, __out__, {'); + + var lastName = null; + for (var name in this.attrs) + { + if (lastName) + blocks.push(','); + lastName = name; + + var val = this.attrs[name]; + blocks.push('"', name, '":'); + addParts(val, '', blocks, info); + } + + blocks.push('});'); + //this.generateChildMarkup(topBlock, topOuts, blocks, info); + }, + + generateDOM: function(path, blocks, args) + { + var embedName = 'e'+path.embedIndex++; + + this.generateNodePath(path, blocks); + + var valueName = 'd' + path.renderIndex++; + var argsName = 'd' + path.renderIndex++; + blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); + + return embedName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +DomplateLoop.prototype = copyObject(DomplateTag.prototype, +{ + merge: function(args, oldTag) + { + this.varName = oldTag ? oldTag.varName : args[0]; + this.iter = oldTag ? oldTag.iter : parseValue(args[1]); + this.vars = []; + + this.children = oldTag ? copyArray(oldTag.children) : []; + + var offset = Math.min(args.length, 2); + parseChildren(args, offset, this.vars, this.children); + + return creator(this, DomplateLoop); + }, + + getVarNames: function(names) + { + if (this.iter instanceof Parts) + names.push(this.iter.parts[0].name); + + DomplateTag.prototype.getVarNames.apply(this, [names]); + }, + + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); + + var iterName; + if (this.iter instanceof Parts) + { + var part = this.iter.parts[0]; + iterName = part.name; + + if (part.format) + { + for (var i = 0; i < part.format.length; ++i) + iterName = part.format[i] + "(" + iterName + ")"; + } + } + else + iterName = this.iter; + + blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {'); + this.generateChildMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + blocks.push('}]);'); + }, + + generateDOM: function(path, blocks, args) + { + var iterName = 'd'+path.renderIndex++; + var counterName = 'i'+path.loopIndex; + var loopName = 'l'+path.loopIndex++; + + if (!path.length) + path.push(-1, 0); + + var preIndex = path.renderIndex; + path.renderIndex = 0; + + var nodeCount = 0; + + var subBlocks = []; + var basePath = path[path.length-1]; + for (var i = 0; i < this.children.length; ++i) + { + path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount; + + var child = this.children[i]; + if (isTag(child)) + nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args); + else + nodeCount += '+1'; + } + + path[path.length-1] = basePath+'+'+loopName; + + blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName); + for (var i = 0; i < path.renderIndex; ++i) + blocks.push(',d'+i); + blocks.push(') {'); + blocks.push(subBlocks.join("")); + blocks.push('return ', nodeCount, ';'); + blocks.push('}]);'); + + path.renderIndex = preIndex; + + return loopName; + } +}); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function Variable(name, format) +{ + this.name = name; + this.format = format; +} + +function Parts(parts) +{ + this.parts = parts; +} + +// ************************************************************************************************ + +function parseParts(str) +{ + var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g; + var index = 0; + var parts = []; + + var m; + while (m = re.exec(str)) + { + var pre = str.substr(index, (re.lastIndex-m[0].length)-index); + if (pre) + parts.push(pre); + + var expr = m[1].split("|"); + parts.push(new Variable(expr[0], expr.slice(1))); + index = re.lastIndex; + } + + if (!index) + return str; + + var post = str.substr(index); + if (post) + parts.push(post); + + return new Parts(parts); +} + +function parseValue(val) +{ + return typeof(val) == 'string' ? parseParts(val) : val; +} + +function parseChildren(args, offset, vars, children) +{ + for (var i = offset; i < args.length; ++i) + { + var val = parseValue(args[i]); + children.push(val); + readPartNames(val, vars); + } +} + +function readPartNames(val, vars) +{ + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + vars.push(part.name); + } + } +} + +function generateArg(val, path, args) +{ + if (val instanceof Parts) + { + var vals = []; + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var varName = 'd'+path.renderIndex++; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + varName = part.format[j] + '(' + varName + ')'; + } + + vals.push(varName); + } + else + vals.push('"'+part.replace(/"/g, '\\"')+'"'); + } + + return vals.join('+'); + } + else + { + args.push(val); + return 's' + path.staticIndex++; + } +} + +function addParts(val, delim, block, info, escapeIt) +{ + var vals = []; + if (val instanceof Parts) + { + for (var i = 0; i < val.parts.length; ++i) + { + var part = val.parts[i]; + if (part instanceof Variable) + { + var partName = part.name; + if (part.format) + { + for (var j = 0; j < part.format.length; ++j) + partName = part.format[j] + "(" + partName + ")"; + } + + if (escapeIt) + vals.push("__escape__(" + partName + ")"); + else + vals.push(partName); + } + else + vals.push('"'+ part + '"'); + } + } + else if (isTag(val)) + { + info.args.push(val); + vals.push('s'+info.argIndex++); + } + else + vals.push('"'+ val + '"'); + + var parts = vals.join(delim); + if (parts) + block.push(delim, parts); +} + +function isTag(obj) +{ + return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag; +} + +function creator(tag, cons) +{ + var fn = new Function( + "var tag = arguments.callee.tag;" + + "var cons = arguments.callee.cons;" + + "var newTag = new cons();" + + "return newTag.merge(arguments, tag);"); + + fn.tag = tag; + fn.cons = cons; + extend(fn, Renderer); + + return fn; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function copyArray(oldArray) +{ + var ary = []; + if (oldArray) + for (var i = 0; i < oldArray.length; ++i) + ary.push(oldArray[i]); + return ary; +} + +function copyObject(l, r) +{ + var m = {}; + extend(m, l); + extend(m, r); + return m; +} + +function extend(l, r) +{ + for (var n in r) + l[n] = r[n]; +} + +function addEvent(object, name, handler) +{ + if (document.all) + object.attachEvent("on"+name, handler); + else + object.addEventListener(name, handler, false); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +function ArrayIterator(array) +{ + var index = -1; + + this.next = function() + { + if (++index >= array.length) + throw StopIteration; + + return array[index]; + }; +} + +function StopIteration() {} + +FBL.$break = function() +{ + throw StopIteration; +}; + +// ************************************************************************************************ + +var Renderer = +{ + renderHTML: function(args, outputs, self) + { + var code = []; + var markupArgs = [code, this.tag.context, args, outputs]; + markupArgs.push.apply(markupArgs, this.tag.markupArgs); + this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs); + return code.join(""); + }, + + insertRows: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + var div = doc.createElement("div"); + div.innerHTML = ""+html+"
      "; + + var tbody = div.firstChild.firstChild; + var parent = before.tagName == "TR" ? before.parentNode : before; + var after = before.tagName == "TR" ? before.nextSibling : null; + + var firstRow = tbody.firstChild, lastRow; + while (tbody.firstChild) + { + lastRow = tbody.firstChild; + if (after) + parent.insertBefore(lastRow, after); + else + parent.appendChild(lastRow); + } + + var offset = 0; + if (before.tagName == "TR") + { + var node = firstRow.parentNode.firstChild; + for (; node && node != firstRow; node = node.nextSibling) + ++offset; + } + + var domArgs = [firstRow, this.tag.context, offset]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + return [firstRow, lastRow]; + }, + + insertBefore: function(args, before, self) + { + return this.insertNode(args, before.ownerDocument, before, false, self); + }, + + insertAfter: function(args, after, self) + { + return this.insertNode(args, after.ownerDocument, after, true, self); + }, + + insertNode: function(args, doc, element, isAfter, self) + { + if (!args) + args = {}; + + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode html: "+html+"\n"); + + var doc = element.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + if (isAfter) + { + while (womb.firstChild) + if (element.nextSibling) + element.parentNode.insertBefore(womb.firstChild, element.nextSibling); + else + element.parentNode.appendChild(womb.firstChild); + } + else + { + while (womb.lastChild) + element.parentNode.insertBefore(womb.lastChild, element); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) + // FBTrace.sysout("domplate.insertNode domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + /**/ + + /* + insertAfter: function(args, before, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var doc = before.ownerDocument; + if (!womb || womb.ownerDocument != doc) + womb = doc.createElement("div"); + + womb.innerHTML = html; + + var root = womb.firstChild; + while (womb.firstChild) + if (before.nextSibling) + before.parentNode.insertBefore(womb.firstChild, before.nextSibling); + else + before.parentNode.appendChild(womb.firstChild); + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), + domArgs); + + return root; + }, + /**/ + + replace: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var root; + if (parent.nodeType == 1) + { + parent.innerHTML = html; + root = parent.firstChild; + } + else + { + if (!parent || parent.nodeType != 9) + parent = document; + + if (!womb || womb.ownerDocument != parent) + womb = parent.createElement("div"); + womb.innerHTML = html; + + root = womb.firstChild; + //womb.removeChild(root); + } + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + }, + + append: function(args, parent, self) + { + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n"); + + if (!womb || womb.ownerDocument != parent.ownerDocument) + womb = parent.ownerDocument.createElement("div"); + womb.innerHTML = html; + + // TODO: xxxpedro domplate port to Firebug + var root = womb.firstChild; + while (womb.firstChild) + parent.appendChild(womb.firstChild); + + // clearing element reference to avoid reference error in IE8 when switching contexts + womb = null; + + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); + + //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + + return root; + } +}; + +// ************************************************************************************************ + +function defineTags() +{ + for (var i = 0; i < arguments.length; ++i) + { + var tagName = arguments[i]; + var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);"); + fn.DomplateTag = DomplateTag; + + var fnName = tagName.toUpperCase(); + FBL[fnName] = fn; + } +} + +defineTags( + "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr", + "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select", + "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe" +); + +})(); + + +/* See license.txt for terms of usage */ + +var FirebugReps = FBL.ns(function() { with (FBL) { + + +// ************************************************************************************************ +// Common Tags + +var OBJECTBOX = this.OBJECTBOX = + SPAN({"class": "objectBox objectBox-$className"}); + +var OBJECTBLOCK = this.OBJECTBLOCK = + DIV({"class": "objectBox objectBox-$className"}); + +var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation + A({ + "class": "objectLink objectLink-$className a11yFocus", + href: "javascript:void(0)", + _repObject: "$object" + }) + : // Other browsers + A({ + "class": "objectLink objectLink-$className a11yFocus", + _repObject: "$object" + }); + + +// ************************************************************************************************ + +this.Undefined = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("undefined"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "undefined", + + supportsObject: function(object, type) + { + return type == "undefined"; + } +}); + +// ************************************************************************************************ + +this.Null = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("null"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "null", + + supportsObject: function(object, type) + { + return object == null; + } +}); + +// ************************************************************************************************ + +this.Nada = domplate(Firebug.Rep, +{ + tag: SPAN(""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "nada" +}); + +// ************************************************************************************************ + +this.Number = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "number", + + supportsObject: function(object, type) + { + return type == "boolean" || type == "number"; + } +}); + +// ************************************************************************************************ + +this.String = domplate(Firebug.Rep, +{ + tag: OBJECTBOX(""$object""), + + shortTag: OBJECTBOX(""$object|cropString""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "string", + + supportsObject: function(object, type) + { + return type == "string"; + } +}); + +// ************************************************************************************************ + +this.Text = domplate(Firebug.Rep, +{ + tag: OBJECTBOX("$object"), + + shortTag: OBJECTBOX("$object|cropString"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "text" +}); + +// ************************************************************************************************ + +this.Caption = domplate(Firebug.Rep, +{ + tag: SPAN({"class": "caption"}, "$object") +}); + +// ************************************************************************************************ + +this.Warning = domplate(Firebug.Rep, +{ + tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR") +}); + +// ************************************************************************************************ + +this.Func = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("$object|summarizeFunction"), + + summarizeFunction: function(fn) + { + var fnRegex = /function ([^(]+\([^)]*\)) \{/; + var fnText = safeToString(fn); + + var m = fnRegex.exec(fnText); + return m ? m[1] : "function()"; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copySource: function(fn) + { + copyToClipboard(safeToString(fn)); + }, + + monitor: function(fn, script, monitored) + { + if (monitored) + Firebug.Debugger.unmonitorScript(fn, script, "monitor"); + else + Firebug.Debugger.monitorScript(fn, script, "monitor"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "function", + + supportsObject: function(object, type) + { + return isFunction(object); + }, + + inspectObject: function(fn, context) + { + var sourceLink = findSourceForFunction(fn, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + if (FBTrace.DBG_FUNCTION_NAME) + FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink); + }, + + getTooltip: function(fn, context) + { + var script = findScriptForFunctionInContext(context, fn); + if (script) + return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]); + else + if (fn.toString) + return fn.toString(); + }, + + getTitle: function(fn, context) + { + var name = fn.name ? fn.name : "function"; + return name + "()"; + }, + + getContextMenuItems: function(fn, target, context, script) + { + if (!script) + script = findScriptForFunctionInContext(context, fn); + if (!script) + return; + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = script ? getFunctionName(script, context) : fn.name; + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, fn) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); + +// ************************************************************************************************ +/* +this.jsdScript = domplate(Firebug.Rep, +{ + copySource: function(script) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.copySource(fn); + }, + + monitor: function(fn, script, monitored) + { + fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.monitor(fn, script, monitored); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "jsdScript", + inspectable: false, + + supportsObject: function(object, type) + { + return object instanceof jsdIScript; + }, + + inspectObject: function(script, context) + { + var sourceLink = getSourceLinkForScript(script, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + }, + + getRealObject: function(script, context) + { + return script; + }, + + getTooltip: function(script) + { + return $STRF("jsdIScript", [script.tag]); + }, + + getTitle: function(script, context) + { + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.getTitle(fn, context); + }, + + getContextMenuItems: function(script, target, context) + { + var fn = script.functionObject.getWrappedValue(); + + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; + + var name = getFunctionName(script, context); + + return [ + {label: "CopySource", command: bindFixed(this.copySource, this, script) }, + "-", + {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, + type: "checkbox", checked: monitored, + command: bindFixed(this.monitor, this, fn, script, monitored) } + ]; + } +}); +/**/ +//************************************************************************************************ + +this.Obj = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + SPAN({"class": "objectTitle"}, "$object|getTitle "), + + SPAN({"class": "objectProps"}, + SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"), + FOR("prop", "$object|propIterator", + SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"), + SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"), + TAG("$prop.tag", {object: "$prop.object"}), + SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim") + ), + SPAN({"class": "objectRightBrace"}, "}") + ) + ), + + propNumberTag: + SPAN({"class": "objectProp-number"}, "$object"), + + propStringTag: + SPAN({"class": "objectProp-string"}, ""$object""), + + propObjectTag: + SPAN({"class": "objectProp-object"}, "$object"), + + propIterator: function (object) + { + ///Firebug.ObjectShortIteratorMax; + var maxLength = 55; // default max length for long representation + + if (!object) + return []; + + var props = []; + var length = 0; + + var numProperties = 0; + var numPropertiesShown = 0; + var maxLengthReached = false; + + var lib = this; + + var propRepsMap = + { + "boolean": this.propNumberTag, + "number": this.propNumberTag, + "string": this.propStringTag, + "object": this.propObjectTag + }; + + try + { + var title = Firebug.Rep.getTitle(object); + length += title.length; + + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var type = typeof(value); + if (type == "boolean" || + type == "number" || + (type == "string" && value) || + (type == "object" && value && value.toString)) + { + var tag = propRepsMap[type]; + + var value = (type == "object") ? + Firebug.getRep(value).getTitle(value) : + value + ""; + + length += name.length + value.length + 4; + + if (length <= maxLength) + { + props.push({ + tag: tag, + name: name, + object: value, + equal: "=", + delim: ", " + }); + + numPropertiesShown++; + } + else + maxLengthReached = true; + + } + + numProperties++; + + if (maxLengthReached && numProperties > numPropertiesShown) + break; + } + + if (numProperties > numPropertiesShown) + { + props.push({ + object: "...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }); + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + fb_1_6_propIterator: function (object, max) + { + max = max || 3; + if (!object) + return []; + + var props = []; + var len = 0, count = 0; + + try + { + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof(value); + if (t == "boolean" || t == "number" || (t == "string" && value) + || (t == "object" && value && value.toString)) + { + var rep = Firebug.getRep(value); + var tag = rep.shortTag || rep.tag; + if (t == "object") + { + value = rep.getTitle(value); + tag = rep.titleTag; + } + count++; + if (count <= max) + props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "}); + else + break; + } + } + if (count > max) + { + props[Math.max(1,max-1)] = { + object: "more...", //xxxHonza localization + tag: FirebugReps.Caption.tag, + name: "", + equal:"", + delim:"" + }; + } + else if (props.length > 0) + { + props[props.length-1].delim = ''; + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + return props; + }, + + /* + propIterator: function (object) + { + if (!object) + return []; + + var props = []; + var len = 0; + + try + { + for (var name in object) + { + var val; + try + { + val = object[name]; + } + catch (exc) + { + continue; + } + + var t = typeof val; + if (t == "boolean" || t == "number" || (t == "string" && val) + || (t == "object" && !isFunction(val) && val && val.toString)) + { + var title = (t == "object") + ? Firebug.getRep(val).getTitle(val) + : val+""; + + len += name.length + title.length + 1; + if (len < 50) + props.push({name: name, value: title}); + else + break; + } + } + } + catch (exc) + { + // Sometimes we get exceptions when trying to read from certain objects, like + // StorageList, but don't let that gum up the works + // XXXjjb also History.previous fails because object is a web-page object which does not have + // permission to read the history + } + + return props; + }, + /**/ + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object, type) + { + return true; + } +}); + + +// ************************************************************************************************ + +this.Arr = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|arrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + SPAN({"class": "arrayRightBracket", role : "presentation"}, "]") + ), + + shortTag: + OBJECTBOX({_repObject: "$object"}, + SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), + FOR("item", "$object|shortArrayIterator", + TAG("$item.tag", {object: "$item.object"}), + SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") + ), + // TODO: xxxpedro - confirm this on Firebug + //FOR("prop", "$object|shortPropIterator", + // " $prop.name=", + // SPAN({"class": "objectPropValue"}, "$prop.value|cropString") + //), + SPAN({"class": "arrayRightBracket"}, "]") + ), + + arrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + return items; + }, + + shortArrayIterator: function(array) + { + var items = []; + for (var i = 0; i < array.length && i < 3; ++i) + { + var value = array[i]; + var rep = Firebug.getRep(value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + var delim = (i == array.length-1 ? "" : ", "); + + items.push({object: value, tag: tag, delim: delim}); + } + + if (array.length > 3) + items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""}); + + return items; + }, + + shortPropIterator: this.Obj.propIterator, + + getItemIndex: function(child) + { + var arrayIndex = 0; + for (child = child.previousSibling; child; child = child.previousSibling) + { + if (child.repObject) + ++arrayIndex; + } + return arrayIndex; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "array", + + supportsObject: function(object) + { + return this.isArray(object); + }, + + // http://code.google.com/p/fbug/issues/detail?id=874 + // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007 + isArray: function(obj) { + try { + if (!obj) + return false; + else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8) + return true; + else if (isFinite(obj.length) && isFunction(obj.splice)) + return true; + else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments + return true; + else if (instanceOf(obj, "HTMLCollection")) + return true; + else if (instanceOf(obj, "NodeList")) + return true; + else + return false; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */ + FBTrace.sysout("isArray Fails on obj", obj); + } + } + + return false; + }, + // END Yahoo BSD SOURCE See license below. + + getTitle: function(object, context) + { + return "[" + object.length + "]"; + } +}); + +// ************************************************************************************************ + +this.Property = domplate(Firebug.Rep, +{ + supportsObject: function(object) + { + return object instanceof Property; + }, + + getRealObject: function(prop, context) + { + return prop.object[prop.name]; + }, + + getTitle: function(prop, context) + { + return prop.name; + } +}); + +// ************************************************************************************************ + +this.NetFile = domplate(this.Obj, +{ + supportsObject: function(object) + { + return object instanceof Firebug.NetFile; + }, + + browseObject: function(file, context) + { + openNewTab(file.href); + return true; + }, + + getRealObject: function(file, context) + { + return null; + } +}); + +// ************************************************************************************************ + +this.Except = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({_repObject: "$object"}, "$object.message"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "exception", + + supportsObject: function(object) + { + return object instanceof ErrorCopy; + } +}); + + +// ************************************************************************************************ + +this.Element = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), + FOR("attr", "$object|attrIterator", + " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ + ), + ">" + ), + + shortTag: + OBJECTLINK( + SPAN({"class": "$object|getVisible"}, + SPAN({"class": "selectorTag"}, "$object|getSelectorTag"), + SPAN({"class": "selectorId"}, "$object|getSelectorId"), + SPAN({"class": "selectorClass"}, "$object|getSelectorClass"), + SPAN({"class": "selectorValue"}, "$object|getValue") + ) + ), + + getVisible: function(elt) + { + return isVisible(elt) ? "" : "selectorHidden"; + }, + + getSelectorTag: function(elt) + { + return elt.nodeName.toLowerCase(); + }, + + getSelectorId: function(elt) + { + return elt.id ? "#" + elt.id : ""; + }, + + getSelectorClass: function(elt) + { + return elt.className ? "." + elt.className.split(" ")[0] : ""; + }, + + getValue: function(elt) + { + // TODO: xxxpedro + return ""; + var value; + if (elt instanceof HTMLImageElement) + value = getFileName(elt.src); + else if (elt instanceof HTMLAnchorElement) + value = getFileName(elt.href); + else if (elt instanceof HTMLInputElement) + value = elt.value; + else if (elt instanceof HTMLFormElement) + value = getFileName(elt.action); + else if (elt instanceof HTMLScriptElement) + value = getFileName(elt.src); + + return value ? " " + cropString(value, 20) : ""; + }, + + attrIterator: function(elt) + { + var attrs = []; + var idAttr, classAttr; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName && attr.nodeName.indexOf("firebug-") != -1) + continue; + else if (attr.nodeName == "id") + idAttr = attr; + else if (attr.nodeName == "class") + classAttr = attr; + else + attrs.push(attr); + } + } + if (classAttr) + attrs.splice(0, 0, classAttr); + if (idAttr) + attrs.splice(0, 0, idAttr); + + return attrs; + }, + + shortAttrIterator: function(elt) + { + var attrs = []; + if (elt.attributes) + { + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; + if (attr.nodeName == "id" || attr.nodeName == "class") + attrs.push(attr); + } + } + + return attrs; + }, + + getHidden: function(elt) + { + return isVisible(elt) ? "" : "nodeHidden"; + }, + + getXPath: function(elt) + { + return getElementTreeXPath(elt); + }, + + // TODO: xxxpedro remove this? + getNodeText: function(element) + { + var text = element.textContent; + if (Firebug.showFullTextNodes) + return text; + else + return cropString(text, 50); + }, + /**/ + + getNodeTextGroups: function(element) + { + var text = element.textContent; + if (!Firebug.showFullTextNodes) + { + text=cropString(text,50); + } + + var escapeGroups=[]; + + if (Firebug.showTextNodesWithWhitespace) + escapeGroups.push({ + 'group': 'whitespace', + 'class': 'nodeWhiteSpace', + 'extra': { + '\t': '_Tab', + '\n': '_Para', + ' ' : '_Space' + } + }); + if (Firebug.showTextNodesWithEntities) + escapeGroups.push({ + 'group':'text', + 'class':'nodeTextEntity', + 'extra':{} + }); + + if (escapeGroups.length) + return escapeGroupsForEntities(text, escapeGroups); + else + return [{str:text,'class':'',extra:''}]; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyHTML: function(elt) + { + var html = getElementXML(elt); + copyToClipboard(html); + }, + + copyInnerHTML: function(elt) + { + copyToClipboard(elt.innerHTML); + }, + + copyXPath: function(elt) + { + var xpath = getElementXPath(elt); + copyToClipboard(xpath); + }, + + persistor: function(context, xpath) + { + var elts = xpath + ? getElementsByXPath(context.window.document, xpath) + : null; + + return elts && elts.length ? elts[0] : null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "element", + + supportsObject: function(object) + { + //return object instanceof Element || object.nodeType == 1 && typeof object.nodeName == "string"; + return instanceOf(object, "Element"); + }, + + browseObject: function(elt, context) + { + var tag = elt.nodeName.toLowerCase(); + if (tag == "script") + openNewTab(elt.src); + else if (tag == "link") + openNewTab(elt.href); + else if (tag == "a") + openNewTab(elt.href); + else if (tag == "img") + openNewTab(elt.src); + + return true; + }, + + persistObject: function(elt, context) + { + var xpath = getElementXPath(elt); + + return bind(this.persistor, top, xpath); + }, + + getTitle: function(element, context) + { + return getElementCSSSelector(element); + }, + + getTooltip: function(elt) + { + return this.getXPath(elt); + }, + + getContextMenuItems: function(elt, target, context) + { + var monitored = areEventsMonitored(elt, null, context); + + return [ + {label: "CopyHTML", command: bindFixed(this.copyHTML, this, elt) }, + {label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) }, + {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) }, + "-", + {label: "ShowEventsInConsole", type: "checkbox", checked: monitored, + command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) }, + "-", + {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) } + ]; + } +}); + +// ************************************************************************************************ + +this.TextNode = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "TextNode"), + " textContent="", SPAN({"class": "nodeValue"}, "$object.textContent|cropString"), """, + ">" + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "textNode", + + supportsObject: function(object) + { + return object instanceof Text; + } +}); + +// ************************************************************************************************ + +this.Document = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(doc) + { + return doc.location ? getFileName(doc.location.href) : ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Document || object instanceof XMLDocument; + return instanceOf(object, "Document"); + }, + + browseObject: function(doc, context) + { + openNewTab(doc.location.href); + return true; + }, + + persistObject: function(doc, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window.document; + }, + + getTitle: function(win, context) + { + return "document"; + }, + + getTooltip: function(doc) + { + return doc.location.href; + } +}); + +// ************************************************************************************************ + +this.StyleSheet = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(styleSheet) + { + return getFileName(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(styleSheet) + { + copyToClipboard(styleSheet.href); + }, + + openInTab: function(styleSheet) + { + openNewTab(styleSheet.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof CSSStyleSheet; + return instanceOf(object, "CSSStyleSheet"); + }, + + browseObject: function(styleSheet, context) + { + openNewTab(styleSheet.href); + return true; + }, + + persistObject: function(styleSheet, context) + { + return bind(this.persistor, top, styleSheet.href); + }, + + getTooltip: function(styleSheet) + { + return styleSheet.href; + }, + + getContextMenuItems: function(styleSheet, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) } + ]; + }, + + persistor: function(context, href) + { + return getStyleSheetByHref(href, context); + } +}); + +// ************************************************************************************************ + +this.Window = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")), + + getLocation: function(win) + { + try + { + return (win && win.location && !win.closed) ? getFileName(win.location.href) : ""; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.Window window closed?"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + return instanceOf(object, "Window"); + }, + + browseObject: function(win, context) + { + openNewTab(win.location.href); + return true; + }, + + persistObject: function(win, context) + { + return this.persistor; + }, + + persistor: function(context) + { + return context.window; + }, + + getTitle: function(win, context) + { + return "window"; + }, + + getTooltip: function(win) + { + if (win && !win.closed) + return win.location.href; + } +}); + +// ************************************************************************************************ + +this.Event = domplate(Firebug.Rep, +{ + tag: TAG("$copyEventTag", {object: "$object|copyEvent"}), + + copyEventTag: + OBJECTLINK("$object|summarizeEvent"), + + summarizeEvent: function(event) + { + var info = [event.type, ' ']; + + var eventFamily = getEventFamily(event.type); + if (eventFamily == "mouse") + info.push("clientX=", event.clientX, ", clientY=", event.clientY); + else if (eventFamily == "key") + info.push("charCode=", event.charCode, ", keyCode=", event.keyCode); + + return info.join(""); + }, + + copyEvent: function(event) + { + return new EventCopy(event); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "object", + + supportsObject: function(object) + { + //return object instanceof Event || object instanceof EventCopy; + return instanceOf(object, "Event") || instanceOf(object, "EventCopy"); + }, + + getTitle: function(event, context) + { + return "Event " + event.type; + } +}); + +// ************************************************************************************************ + +this.SourceLink = domplate(Firebug.Rep, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + hideSourceLink: function(sourceLink) + { + return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true; + }, + + getSourceLinkTitle: function(sourceLink) + { + if (!sourceLink) + return ""; + + try + { + var fileName = getFileName(sourceLink.href); + fileName = decodeURIComponent(fileName); + fileName = cropString(fileName, 17); + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'"+fileName+"\': "+exc, exc); + } + + return typeof sourceLink.line == "number" ? + fileName + " (line " + sourceLink.line + ")" : + fileName; + + // TODO: xxxpedro + //return $STRF("Line", [fileName, sourceLink.line]); + }, + + copyLink: function(sourceLink) + { + copyToClipboard(sourceLink.href); + }, + + openInTab: function(sourceLink) + { + openNewTab(sourceLink.href); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceLink", + + supportsObject: function(object) + { + return object instanceof SourceLink; + }, + + getTooltip: function(sourceLink) + { + return decodeURI(sourceLink.href); + }, + + inspectObject: function(sourceLink, context) + { + if (sourceLink.type == "js") + { + var scriptFile = getSourceFileByHref(sourceLink.href, context); + if (scriptFile) + return Firebug.chrome.select(sourceLink); + } + else if (sourceLink.type == "css") + { + // If an object is defined, treat it as the highest priority for + // inspect actions + if (sourceLink.object) { + Firebug.chrome.select(sourceLink.object); + return; + } + + var stylesheet = getStyleSheetByHref(sourceLink.href, context); + if (stylesheet) + { + var ownerNode = stylesheet.ownerNode; + if (ownerNode) + { + Firebug.chrome.select(sourceLink, "html"); + return; + } + + var panel = context.getPanel("stylesheet"); + if (panel && panel.getRuleByLine(stylesheet, sourceLink.line)) + return Firebug.chrome.select(sourceLink); + } + } + + // Fallback is to just open the view-source window on the file + viewSource(sourceLink.href, sourceLink.line); + }, + + browseObject: function(sourceLink, context) + { + openNewTab(sourceLink.href); + return true; + }, + + getContextMenuItems: function(sourceLink, target, context) + { + return [ + {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceFile = domplate(this.SourceLink, +{ + tag: + OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"), + + persistor: function(context, href) + { + return getSourceFileByHref(href, context); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "sourceFile", + + supportsObject: function(object) + { + return object instanceof SourceFile; + }, + + persistObject: function(sourceFile) + { + return bind(this.persistor, top, sourceFile.href); + }, + + browseObject: function(sourceLink, context) + { + }, + + getTooltip: function(sourceFile) + { + return sourceFile.href; + } +}); + +// ************************************************************************************************ + +this.StackFrame = domplate(Firebug.Rep, // XXXjjb Since the repObject is fn the stack does not have correct line numbers +{ + tag: + OBJECTBLOCK( + A({"class": "objectLink objectLink-function focusRow a11yFocus", _repObject: "$object.fn"}, "$object|getCallName"), + " ( ", + FOR("arg", "$object|argIterator", + TAG("$arg.tag", {object: "$arg.value"}), + SPAN({"class": "arrayComma"}, "$arg.delim") + ), + " )", + SPAN({"class": "objectLink-sourceLink objectLink"}, "$object|getSourceLinkTitle") + ), + + getCallName: function(frame) + { + //TODO: xxxpedro reps StackFrame + return frame.name || "anonymous"; + + //return getFunctionName(frame.script, frame.context); + }, + + getSourceLinkTitle: function(frame) + { + //TODO: xxxpedro reps StackFrame + var fileName = cropString(getFileName(frame.href), 20); + return fileName + (frame.lineNo ? " (line " + frame.lineNo + ")" : ""); + + var fileName = cropString(getFileName(frame.href), 17); + return $STRF("Line", [fileName, frame.lineNo]); + }, + + argIterator: function(frame) + { + if (!frame.args) + return []; + + var items = []; + + for (var i = 0; i < frame.args.length; ++i) + { + var arg = frame.args[i]; + + if (!arg) + break; + + var rep = Firebug.getRep(arg.value); + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var delim = (i == frame.args.length-1 ? "" : ", "); + + items.push({name: arg.name, value: arg.value, tag: tag, delim: delim}); + } + + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackFrame", + + supportsObject: function(object) + { + return object instanceof StackFrame; + }, + + inspectObject: function(stackFrame, context) + { + var sourceLink = new SourceLink(stackFrame.href, stackFrame.lineNo, "js"); + Firebug.chrome.select(sourceLink); + }, + + getTooltip: function(stackFrame, context) + { + return $STRF("Line", [stackFrame.href, stackFrame.lineNo]); + } + +}); + +// ************************************************************************************************ + +this.StackTrace = domplate(Firebug.Rep, +{ + tag: + FOR("frame", "$object.frames focusRow", + TAG(this.StackFrame.tag, {object: "$frame"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "stackTrace", + + supportsObject: function(object) + { + return object instanceof StackTrace; + } +}); + +// ************************************************************************************************ + +this.jsdStackFrame = domplate(Firebug.Rep, +{ + inspectable: false, + + supportsObject: function(object) + { + return (object instanceof jsdIStackFrame) && (object.isValid); + }, + + getTitle: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + return getFunctionName(frame.script, context); + }, + + getTooltip: function(frame, context) + { + if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null + var sourceInfo = FBL.getSourceFileAndLineByScript(context, frame.script, frame); + if (sourceInfo) + return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]); + else + return $STRF("Line", [frame.script.fileName, frame.line]); + }, + + getContextMenuItems: function(frame, target, context) + { + var fn = frame.script.functionObject.getWrappedValue(); + return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script); + } +}); + +// ************************************************************************************************ + +this.ErrorMessage = domplate(Firebug.Rep, +{ + tag: + OBJECTBOX({ + $hasTwisty: "$object|hasStackTrace", + $hasBreakSwitch: "$object|hasBreakSwitch", + $breakForError: "$object|hasErrorBreak", + _repObject: "$object", + _stackTrace: "$object|getLastErrorStackTrace", + onclick: "$onToggleError"}, + + DIV({"class": "errorTitle a11yFocus", role : 'checkbox', 'aria-checked' : 'false'}, + "$object.message|getMessage" + ), + DIV({"class": "errorTrace"}), + DIV({"class": "errorSourceBox errorSource-$object|getSourceType"}, + IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':'false', title: "Break on this error"}), + A({"class": "errorSource a11yFocus"}, "$object|getLine") + ), + TAG(this.SourceLink.tag, {object: "$object|getSourceLink"}) + ), + + getLastErrorStackTrace: function(error) + { + return error.trace; + }, + + hasStackTrace: function(error) + { + var url = error.href.toString(); + var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1); + return !fromCommandLine && error.trace; + }, + + hasBreakSwitch: function(error) + { + return error.href && error.lineNo > 0; + }, + + hasErrorBreak: function(error) + { + return fbs.hasErrorBreakpoint(error.href, error.lineNo); + }, + + getMessage: function(message) + { + var re = /\[Exception... "(.*?)" nsresult:/; + var m = re.exec(message); + return m ? m[1] : message; + }, + + getLine: function(error) + { + if (error.category == "js") + { + if (error.source) + return cropString(error.source, 80); + else if (error.href && error.href.indexOf("XPCSafeJSObjectWrapper") == -1) + return cropString(error.getSourceLine(), 80); + } + }, + + getSourceLink: function(error) + { + var ext = error.category == "css" ? "css" : "js"; + return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null; + }, + + getSourceType: function(error) + { + // Errors occurring inside of HTML event handlers look like "foo.html (line 1)" + // so let's try to skip those + if (error.source) + return "syntax"; + else if (error.lineNo == 1 && getFileExtension(error.href) != "js") + return "none"; + else if (error.category == "css") + return "none"; + else if (!error.href || !error.lineNo) + return "none"; + else + return "exec"; + }, + + onToggleError: function(event) + { + var target = event.currentTarget; + if (hasClass(event.target, "errorBreak")) + { + this.breakOnThisError(target.repObject); + } + else if (hasClass(event.target, "errorSource")) + { + var panel = Firebug.getElementPanel(event.target); + this.inspectObject(target.repObject, panel.context); + } + else if (hasClass(event.target, "errorTitle")) + { + var traceBox = target.childNodes[1]; + toggleClass(target, "opened"); + event.target.setAttribute('aria-checked', hasClass(target, "opened")); + if (hasClass(target, "opened")) + { + if (target.stackTrace) + var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox); + if (Firebug.A11yModel.enabled) + { + var panel = Firebug.getElementPanel(event.target); + dispatch([Firebug.A11yModel], "onLogRowContentCreated", [panel , traceBox]); + } + } + else + clearNode(traceBox); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyError: function(error) + { + var message = [ + this.getMessage(error.message), + error.href, + "Line " + error.lineNo + ]; + copyToClipboard(message.join("\n")); + }, + + breakOnThisError: function(error) + { + if (this.hasErrorBreak(error)) + Firebug.Debugger.clearErrorBreakpoint(error.href, error.lineNo); + else + Firebug.Debugger.setErrorBreakpoint(error.href, error.lineNo); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "errorMessage", + inspectable: false, + + supportsObject: function(object) + { + return object instanceof ErrorMessage; + }, + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + FirebugReps.SourceLink.inspectObject(sourceLink, context); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + var items = [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) } + ]; + + if (error.category == "css") + { + items.push( + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + + optionMenu("BreakOnAllErrors", "breakOnErrors") + ); + } + + return items; + } +}); + +// ************************************************************************************************ + +this.Assert = domplate(Firebug.Rep, +{ + tag: + DIV( + DIV({"class": "errorTitle"}), + DIV({"class": "assertDescription"}) + ), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "assert", + + inspectObject: function(error, context) + { + var sourceLink = this.getSourceLink(error); + Firebug.chrome.select(sourceLink); + }, + + getContextMenuItems: function(error, target, context) + { + var breakOnThisError = this.hasErrorBreak(error); + + return [ + {label: "CopyError", command: bindFixed(this.copyError, this, error) }, + "-", + {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError, + command: bindFixed(this.breakOnThisError, this, error) }, + {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors, + command: bindFixed(this.breakOnAllErrors, this, error) } + ]; + } +}); + +// ************************************************************************************************ + +this.SourceText = domplate(Firebug.Rep, +{ + tag: + DIV( + FOR("line", "$object|lineIterator", + DIV({"class": "sourceRow", role : "presentation"}, + SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"), + SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text") + ) + ) + ), + + lineIterator: function(sourceText) + { + var maxLineNoChars = (sourceText.lines.length + "").length; + var list = []; + + for (var i = 0; i < sourceText.lines.length; ++i) + { + // Make sure all line numbers are the same width (with a fixed-width font) + var lineNo = (i+1) + ""; + while (lineNo.length < maxLineNoChars) + lineNo = " " + lineNo; + + list.push({lineNo: lineNo, text: sourceText.lines[i]}); + } + + return list; + }, + + getHTML: function(sourceText) + { + return getSourceLineRange(sourceText, 1, sourceText.lines.length); + } +}); + +//************************************************************************************************ +this.nsIDOMHistory = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showHistory"}, + OBJECTLINK("$object|summarizeHistory") + ), + + className: "nsIDOMHistory", + + summarizeHistory: function(history) + { + try + { + var items = history.length; + return items + " history entries"; + } + catch(exc) + { + return "object does not support history (nsIDOMHistory)"; + } + }, + + showHistory: function(history) + { + try + { + var items = history.length; // if this throws, then unsupported + Firebug.chrome.select(history); + } + catch (exc) + { + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object, type) + { + return (object instanceof Ci.nsIDOMHistory); + } +}); + +// ************************************************************************************************ +this.ApplicationCache = domplate(Firebug.Rep, +{ + tag:OBJECTBOX({onclick: "$showApplicationCache"}, + OBJECTLINK("$object|summarizeCache") + ), + + summarizeCache: function(applicationCache) + { + try + { + return applicationCache.length + " items in offline cache"; + } + catch(exc) + { + return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264"; + } + }, + + showApplicationCache: function(event) + { + openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "applicationCache", + + supportsObject: function(object, type) + { + if (Ci.nsIDOMOfflineResourceList) + return (object instanceof Ci.nsIDOMOfflineResourceList); + } + +}); + +this.Storage = domplate(Firebug.Rep, +{ + tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")), + + summarize: function(storage) + { + return storage.length +" items in Storage"; + }, + show: function(storage) + { + openNewTab("http://dev.w3.org/html5/webstorage/#storage-0"); + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + className: "Storage", + + supportsObject: function(object, type) + { + return (object instanceof Storage); + } + +}); + +// ************************************************************************************************ +Firebug.registerRep( + //this.nsIDOMHistory, // make this early to avoid exceptions + this.Undefined, + this.Null, + this.Number, + this.String, + this.Window, + //this.ApplicationCache, // must come before Arr (array) else exceptions. + //this.ErrorMessage, + this.Element, + //this.TextNode, + this.Document, + this.StyleSheet, + this.Event, + //this.SourceLink, + //this.SourceFile, + //this.StackTrace, + //this.StackFrame, + //this.jsdStackFrame, + //this.jsdScript, + //this.NetFile, + this.Property, + this.Except, + this.Arr +); + +Firebug.setDefaultReps(this.Func, this.Obj); + +}}); + +// ************************************************************************************************ +/* + * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source" + * in only this file reps.js. John J. Barton June 2007. + * +Software License Agreement (BSD License) + +Copyright (c) 2006, Yahoo! Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Yahoo! Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Yahoo! Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * / + */ + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var saveTimeout = 400; +var pageAmount = 10; + +// ************************************************************************************************ +// Globals + +var currentTarget = null; +var currentGroup = null; +var currentPanel = null; +var currentEditor = null; + +var defaultEditor = null; + +var originalClassName = null; + +var originalValue = null; +var defaultValue = null; +var previousValue = null; + +var invalidEditor = false; +var ignoreNextInput = false; + +// ************************************************************************************************ + +Firebug.Editor = extend(Firebug.Module, +{ + supportsStopEvent: true, + + dispatchName: "editor", + tabCharacter: " ", + + startEditing: function(target, value, editor) + { + this.stopEditing(); + + if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter")) + return; + + var panel = Firebug.getElementPanel(target); + if (!panel.editable) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.startEditing " + value, target); + + defaultValue = target.getAttribute("defaultValue"); + if (value == undefined) + { + var textContent = isIE ? "innerText" : "textContent"; + value = target[textContent]; + if (value == defaultValue) + value = ""; + } + + originalValue = previousValue = value; + + invalidEditor = false; + currentTarget = target; + currentPanel = panel; + currentGroup = getAncestorByClass(target, "editGroup"); + + currentPanel.editing = true; + + var panelEditor = currentPanel.getEditor(target, value); + currentEditor = editor ? editor : panelEditor; + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + var inlineParent = getInlineParent(target); + var targetSize = getOffsetSize(inlineParent); + + setClass(panel.panelNode, "editing"); + setClass(target, "editing"); + if (currentGroup) + setClass(currentGroup, "editing"); + + currentEditor.show(target, currentPanel, value, targetSize); + //dispatch(this.fbListeners, "onBeginEditing", [currentPanel, currentEditor, target, value]); + currentEditor.beginEditing(target, value); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Editor start panel "+currentPanel.name); + this.attachListeners(currentEditor, panel.context); + }, + + stopEditing: function(cancel) + { + if (!currentTarget) + return; + + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.stopEditing cancel:" + cancel+" saveTimeout: "+this.saveTimeout); + + clearTimeout(this.saveTimeout); + delete this.saveTimeout; + + this.detachListeners(currentEditor, currentPanel.context); + + removeClass(currentPanel.panelNode, "editing"); + removeClass(currentTarget, "editing"); + if (currentGroup) + removeClass(currentGroup, "editing"); + + var value = currentEditor.getValue(); + if (value == defaultValue) + value = ""; + + var removeGroup = currentEditor.endEditing(currentTarget, value, cancel); + + try + { + if (cancel) + { + //dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, removeGroup && !originalValue]); + if (value != originalValue) + this.saveEditAndNotifyListeners(currentTarget, originalValue, previousValue); + + if (removeGroup && !originalValue && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else if (!value) + { + this.saveEditAndNotifyListeners(currentTarget, null, previousValue); + + if (removeGroup && currentGroup) + currentGroup.parentNode.removeChild(currentGroup); + } + else + this.save(value); + } + catch (exc) + { + //throw exc.message; + //ERROR(exc); + } + + currentEditor.hide(); + currentPanel.editing = false; + + //dispatch(this.fbListeners, "onStopEdit", [currentPanel, currentEditor, currentTarget]); + //if (FBTrace.DBG_EDITOR) + // FBTrace.sysout("Editor stop panel "+currentPanel.name); + + currentTarget = null; + currentGroup = null; + currentPanel = null; + currentEditor = null; + originalValue = null; + invalidEditor = false; + + return value; + }, + + cancelEditing: function() + { + return this.stopEditing(true); + }, + + update: function(saveNow) + { + if (this.saveTimeout) + clearTimeout(this.saveTimeout); + + invalidEditor = true; + + currentEditor.layout(); + + if (saveNow) + this.save(); + else + { + var context = currentPanel.context; + this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.update saveTimeout: "+this.saveTimeout); + } + }, + + save: function(value) + { + if (!invalidEditor) + return; + + if (value == undefined) + value = currentEditor.getValue(); + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("editor.save saveTimeout: "+this.saveTimeout+" currentPanel: "+(currentPanel?currentPanel.name:"null")); + try + { + this.saveEditAndNotifyListeners(currentTarget, value, previousValue); + + previousValue = value; + invalidEditor = false; + } + catch (exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("editor.save FAILS "+exc, exc); + } + }, + + saveEditAndNotifyListeners: function(currentTarget, value, previousValue) + { + currentEditor.saveEdit(currentTarget, value, previousValue); + //dispatch(this.fbListeners, "onSaveEdit", [currentPanel, currentEditor, currentTarget, value, previousValue]); + }, + + setEditTarget: function(element) + { + if (!element) + { + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, true]); + this.stopEditing(); + } + else if (hasClass(element, "insertBefore")) + this.insertRow(element, "before"); + else if (hasClass(element, "insertAfter")) + this.insertRow(element, "after"); + else + this.startEditing(element); + }, + + tabNextEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var nextEditable = currentTarget; + do + { + nextEditable = !value && currentGroup + ? getNextOutsider(nextEditable, currentGroup) + : getNextByClass(nextEditable, "editable"); + } + while (nextEditable && !nextEditable.offsetHeight); + + this.setEditTarget(nextEditable); + }, + + tabPreviousEditor: function() + { + if (!currentTarget) + return; + + var value = currentEditor.getValue(); + var prevEditable = currentTarget; + do + { + prevEditable = !value && currentGroup + ? getPreviousOutsider(prevEditable, currentGroup) + : getPreviousByClass(prevEditable, "editable"); + } + while (prevEditable && !prevEditable.offsetHeight); + + this.setEditTarget(prevEditable); + }, + + insertRow: function(relative, insertWhere) + { + var group = + relative || getAncestorByClass(currentTarget, "editGroup") || currentTarget; + var value = this.stopEditing(); + + currentPanel = Firebug.getElementPanel(group); + + currentEditor = currentPanel.getEditor(group, value); + if (!currentEditor) + currentEditor = getDefaultEditor(currentPanel); + + currentGroup = currentEditor.insertNewRow(group, insertWhere); + if (!currentGroup) + return; + + var editable = hasClass(currentGroup, "editable") + ? currentGroup + : getNextByClass(currentGroup, "editable"); + + if (editable) + this.setEditTarget(editable); + }, + + insertRowForObject: function(relative) + { + var container = getAncestorByClass(relative, "insertInto"); + if (container) + { + relative = getChildByClass(container, "insertBefore"); + if (relative) + this.insertRow(relative, "before"); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + attachListeners: function(editor, context) + { + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + addEvent(win, "resize", this.onResize); + addEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + + this.listeners = [ + chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this)) + ]; + + if (editor.arrowCompletion) + { + this.listeners.push( + chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)), + chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)), + chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)), + chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount)) + ); + } + + if (currentEditor.tabNavigation) + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")), + chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)), + chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this)) + ); + } + else if (currentEditor.multiLine) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, insertTab) + ); + } + else + { + this.listeners.push( + chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this)) + ); + + if (currentEditor.tabCompletion) + { + this.listeners.push( + chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)), + chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1)) + ); + } + } + }, + + detachListeners: function(editor, context) + { + if (!this.listeners) + return; + + var win = isIE ? + currentTarget.ownerDocument.parentWindow : + currentTarget.ownerDocument.defaultView; + + removeEvent(win, "resize", this.onResize); + removeEvent(win, "blur", this.onBlur); + + var chrome = Firebug.chrome; + if (chrome) + { + for (var i = 0; i < this.listeners.length; ++i) + chrome.keyIgnore(this.listeners[i]); + } + + delete this.listeners; + }, + + onResize: function(event) + { + currentEditor.layout(true); + }, + + onBlur: function(event) + { + if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box)) + this.stopEditing(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + Firebug.Module.initialize.apply(this, arguments); + + this.onResize = bindFixed(this.onResize, this); + this.onBlur = bind(this.onBlur, this); + }, + + disable: function() + { + this.stopEditing(); + }, + + showContext: function(browser, context) + { + this.stopEditing(); + }, + + showPanel: function(browser, panel) + { + this.stopEditing(); + } +}); + +// ************************************************************************************************ +// BaseEditor + +Firebug.BaseEditor = extend(Firebug.MeasureBox, +{ + getValue: function() + { + }, + + setValue: function(value) + { + }, + + show: function(target, panel, value, textSize, targetSize) + { + }, + + hide: function() + { + }, + + layout: function(forceAll) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Support for context menus within inline editors. + + getContextMenuItems: function(target) + { + var items = []; + items.push({label: "Cut", commandID: "cmd_cut"}); + items.push({label: "Copy", commandID: "cmd_copy"}); + items.push({label: "Paste", commandID: "cmd_paste"}); + return items; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Editor Module listeners will get "onBeginEditing" just before this call + + beginEditing: function(target, value) + { + }, + + // Editor Module listeners will get "onSaveEdit" just after this call + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + } +}); + +// ************************************************************************************************ +// InlineEditor + +// basic inline editor attributes +var inlineEditorAttributes = { + "class": "textEditorInner", + + type: "text", + spellcheck: "false", + + onkeypress: "$onKeyPress", + + onoverflow: "$onOverflow", + oncontextmenu: "$onContextMenu" +}; + +// IE does not support the oninput event, so we're using the onkeydown to signalize +// the relevant keyboard events, and the onpropertychange to actually handle the +// input event, which should happen after the onkeydown event is fired and after the +// value of the input is updated, but before the onkeyup and before the input (with the +// new value) is rendered +if (isIE) +{ + inlineEditorAttributes.onpropertychange = "$onInput"; + inlineEditorAttributes.onkeydown = "$onKeyDown"; +} +// for other browsers we use the oninput event +else +{ + inlineEditorAttributes.oninput = "$onInput"; +} + +Firebug.InlineEditor = function(doc) +{ + this.initializeInline(doc); +}; + +Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor, +{ + enterOnBlur: true, + outerMargin: 8, + shadowExpand: 7, + + tag: + DIV({"class": "inlineEditor"}, + DIV({"class": "textEditorTop1"}, + DIV({"class": "textEditorTop2"}) + ), + DIV({"class": "textEditorInner1"}, + DIV({"class": "textEditorInner2"}, + INPUT( + inlineEditorAttributes + ) + ) + ), + DIV({"class": "textEditorBottom1"}, + DIV({"class": "textEditorBottom2"}) + ) + ), + + inputTag : + INPUT({"class": "textEditorInner", type: "text", + /*oninput: "$onInput",*/ onkeypress: "$onKeyPress", onoverflow: "$onOverflow"} + ), + + expanderTag: + IMG({"class": "inlineExpander", src: "blank.gif"}), + + initialize: function() + { + this.fixedWidth = false; + this.completeAsYouType = true; + this.tabNavigation = true; + this.multiLine = false; + this.tabCompletion = false; + this.arrowCompletion = true; + this.noWrap = true; + this.numeric = false; + }, + + destroy: function() + { + this.destroyInput(); + }, + + initializeInline: function(doc) + { + if (FBTrace.DBG_EDITOR) + FBTrace.sysout("Firebug.InlineEditor initializeInline()"); + + //this.box = this.tag.replace({}, doc, this); + this.box = this.tag.append({}, doc.body, this); + + //this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required + this.input = this.box.getElementsByTagName("input")[0]; + + if (isIElt8) + { + this.input.style.top = "-8px"; + } + + this.expander = this.expanderTag.replace({}, doc, this); + this.initialize(); + }, + + destroyInput: function() + { + // XXXjoe Need to remove input/keypress handlers to avoid leaks + }, + + getValue: function() + { + return this.input.value; + }, + + setValue: function(value) + { + // It's only a one-line editor, so new lines shouldn't be allowed + return this.input.value = stripNewLines(value); + }, + + show: function(target, panel, value, targetSize) + { + //dispatch([Firebug.A11yModel], "onInlineEditorShow", [panel, this]); + this.target = target; + this.panel = panel; + + this.targetSize = targetSize; + + // TODO: xxxpedro editor + //this.targetOffset = getClientOffset(target); + + // Some browsers (IE, Google Chrome and Safari) will have problem trying to get the + // offset values of invisible elements, or empty elements. So, in order to get the + // correct values, we temporary inject a character in the innerHTML of the empty element, + // then we get the offset values, and next, we restore the original innerHTML value. + var innerHTML = target.innerHTML; + var isEmptyElement = !innerHTML; + if (isEmptyElement) + target.innerHTML = "."; + + // Get the position of the target element (that is about to be edited) + this.targetOffset = + { + x: target.offsetLeft, + y: target.offsetTop + }; + + // Restore the original innerHTML value of the empty element + if (isEmptyElement) + target.innerHTML = innerHTML; + + this.originalClassName = this.box.className; + + var classNames = target.className.split(" "); + for (var i = 0; i < classNames.length; ++i) + setClass(this.box, "editor-" + classNames[i]); + + // Make the editor match the target's font style + copyTextStyles(target, this.box); + + this.setValue(value); + + if (this.fixedWidth) + this.updateLayout(true); + else + { + this.startMeasuring(target); + this.textSize = this.measureInputText(value); + + // Correct the height of the box to make the funky CSS drop-shadow line up + var parent = this.input.parentNode; + if (hasClass(parent, "textEditorInner2")) + { + var yDiff = this.textSize.height - this.shadowExpand; + + // IE6 height offset + if (isIE6) + yDiff -= 2; + + parent.style.height = yDiff + "px"; + parent.parentNode.style.height = yDiff + "px"; + } + + this.updateLayout(true); + } + + this.getAutoCompleter().reset(); + + if (isIElt8) + panel.panelNode.appendChild(this.box); + else + target.offsetParent.appendChild(this.box); + + //console.log(target); + //this.input.select(); // it's called bellow, with setTimeout + + if (isIE) + { + // reset input style + this.input.style.fontFamily = "Monospace"; + this.input.style.fontSize = "11px"; + } + + // Insert the "expander" to cover the target element with white space + if (!this.fixedWidth) + { + copyBoxStyles(target, this.expander); + + target.parentNode.replaceChild(this.expander, target); + collapse(target, true); + this.expander.parentNode.insertBefore(target, this.expander); + } + + //TODO: xxxpedro + //scrollIntoCenterView(this.box, null, true); + + // Display the editor after change its size and position to avoid flickering + this.box.style.display = "block"; + + // we need to call input.focus() and input.select() with a timeout, + // otherwise it won't work on all browsers due to timing issues + var self = this; + setTimeout(function(){ + self.input.focus(); + self.input.select(); + },0); + }, + + hide: function() + { + this.box.className = this.originalClassName; + + if (!this.fixedWidth) + { + this.stopMeasuring(); + + collapse(this.target, false); + + if (this.expander.parentNode) + this.expander.parentNode.removeChild(this.expander); + } + + if (this.box.parentNode) + { + ///setSelectionRange(this.input, 0, 0); + this.input.blur(); + + this.box.parentNode.removeChild(this.box); + } + + delete this.target; + delete this.panel; + }, + + layout: function(forceAll) + { + if (!this.fixedWidth) + this.textSize = this.measureInputText(this.input.value); + + if (forceAll) + this.targetOffset = getClientOffset(this.expander); + + this.updateLayout(false, forceAll); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + beginEditing: function(target, value) + { + }, + + saveEdit: function(target, value, previousValue) + { + }, + + endEditing: function(target, value, cancel) + { + // Remove empty groups by default + return true; + }, + + insertNewRow: function(target, insertWhere) + { + }, + + advanceToNext: function(target, charCode) + { + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleter: function() + { + if (!this.autoCompleter) + { + this.autoCompleter = new Firebug.AutoCompleter(null, + bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this), + true, false); + } + + return this.autoCompleter; + }, + + completeValue: function(amt) + { + //console.log("completeValue"); + + var selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0); + + if (selectRangeCallback) + { + Firebug.Editor.update(true); + + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + else + this.incrementValue(amt); + }, + + incrementValue: function(amt) + { + var value = this.input.value; + + // TODO: xxxpedro editor + if (isIE) + var start = getInputSelectionStart(this.input), end = start; + else + var start = this.input.selectionStart, end = this.input.selectionEnd; + + //debugger; + var range = this.getAutoCompleteRange(value, start); + if (!range || range.type != "int") + range = {start: 0, end: value.length-1}; + + var expr = value.substr(range.start, range.end-range.start+1); + preExpr = value.substr(0, range.start); + postExpr = value.substr(range.end+1); + + // See if the value is an integer, and if so increment it + var intValue = parseInt(expr); + if (!!intValue || intValue == 0) + { + var m = /\d+/.exec(expr); + var digitPost = expr.substr(m.index+m[0].length); + + var completion = intValue-amt; + this.input.value = preExpr + completion + digitPost + postExpr; + + setSelectionRange(this.input, start, end); + + Firebug.Editor.update(true); + + return true; + } + else + return false; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onKeyPress: function(event) + { + //console.log("onKeyPress", event); + if (event.keyCode == 27 && !this.completeAsYouType) + { + var reverted = this.getAutoCompleter().revert(this.input); + if (reverted) + cancelEvent(event); + } + else if (event.charCode && this.advanceToNext(this.target, event.charCode)) + { + Firebug.Editor.tabNextEditor(); + cancelEvent(event); + } + else + { + if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57) + && event.charCode != 45 && event.charCode != 46) + FBL.cancelEvent(event); + else + { + // If the user backspaces, don't autocomplete after the upcoming input event + this.ignoreNextInput = event.keyCode == 8; + } + } + }, + + onOverflow: function() + { + this.updateLayout(false, false, 3); + }, + + onKeyDown: function(event) + { + //console.log("onKeyDown", event.keyCode); + if (event.keyCode > 46 || event.keyCode == 32 || event.keyCode == 8) + { + this.keyDownPressed = true; + } + }, + + onInput: function(event) + { + //debugger; + + // skip not relevant onpropertychange calls on IE + if (isIE) + { + if (event.propertyName != "value" || !isVisible(this.input) || !this.keyDownPressed) + return; + + this.keyDownPressed = false; + } + + //console.log("onInput", event); + //console.trace(); + + var selectRangeCallback; + + if (this.ignoreNextInput) + { + this.ignoreNextInput = false; + this.getAutoCompleter().reset(); + } + else if (this.completeAsYouType) + selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, false); + else + this.getAutoCompleter().reset(); + + Firebug.Editor.update(); + + if (selectRangeCallback) + { + // We need to select the editor text after calling update in Safari/Chrome, + // otherwise the text won't be selected + if (isSafari) + setTimeout(selectRangeCallback,0); + else + selectRangeCallback(); + } + }, + + onContextMenu: function(event) + { + cancelEvent(event); + + var popup = $("fbInlineEditorPopup"); + FBL.eraseNode(popup); + + var target = event.target || event.srcElement; + var menu = this.getContextMenuItems(target); + if (menu) + { + for (var i = 0; i < menu.length; ++i) + FBL.createMenuItem(popup, menu[i]); + } + + if (!popup.firstChild) + return false; + + popup.openPopupAtScreen(event.screenX, event.screenY, true); + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateLayout: function(initial, forceAll, extraWidth) + { + if (this.fixedWidth) + { + this.box.style.left = (this.targetOffset.x) + "px"; + this.box.style.top = (this.targetOffset.y) + "px"; + + var w = this.target.offsetWidth; + var h = this.target.offsetHeight; + this.input.style.width = w + "px"; + this.input.style.height = (h-3) + "px"; + } + else + { + if (initial || forceAll) + { + this.box.style.left = this.targetOffset.x + "px"; + this.box.style.top = this.targetOffset.y + "px"; + } + + var approxTextWidth = this.textSize.width; + var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x) + - this.outerMargin; + + var wrapped = initial + ? this.noWrap && this.targetSize.height > this.textSize.height+3 + : this.noWrap && approxTextWidth > maxWidth; + + if (wrapped) + { + var style = isIE ? + this.target.currentStyle : + this.target.ownerDocument.defaultView.getComputedStyle(this.target, ""); + + targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight); + + // Make the width fit the remaining x-space from the offset to the far right + approxTextWidth = maxWidth - targetMargin; + + this.input.style.width = "100%"; + this.box.style.width = approxTextWidth + "px"; + } + else + { + // Make the input one character wider than the text value so that + // typing does not ever cause the textbox to scroll + var charWidth = this.measureInputText('m').width; + + // Sometimes we need to make the editor a little wider, specifically when + // an overflow happens, otherwise it will scroll off some text on the left + if (extraWidth) + charWidth *= extraWidth; + + var inputWidth = approxTextWidth + charWidth; + + if (initial) + { + if (isIE) + { + // TODO: xxxpedro + var xDiff = 13; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + else + this.box.style.width = "auto"; + } + else + { + // TODO: xxxpedro + var xDiff = isIE ? 13: this.box.scrollWidth - this.input.offsetWidth; + this.box.style.width = (inputWidth + xDiff) + "px"; + } + + this.input.style.width = inputWidth + "px"; + } + + this.expander.style.width = approxTextWidth + "px"; + this.expander.style.height = Math.max(this.textSize.height-3,0) + "px"; + } + + if (forceAll) + scrollIntoCenterView(this.box, null, true); + } +}); + +// ************************************************************************************************ +// Autocompletion + +Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive) +{ + var candidates = null; + var originalValue = null; + var originalOffset = -1; + var lastExpr = null; + var lastOffset = -1; + var exprOffset = 0; + var lastIndex = 0; + var preParsed = null; + var preExpr = null; + var postExpr = null; + + this.revert = function(textBox) + { + if (originalOffset != -1) + { + textBox.value = originalValue; + + setSelectionRange(textBox, originalOffset, originalOffset); + + this.reset(); + return true; + } + else + { + this.reset(); + return false; + } + }; + + this.reset = function() + { + candidates = null; + originalValue = null; + originalOffset = -1; + lastExpr = null; + lastOffset = 0; + exprOffset = 0; + }; + + this.complete = function(context, textBox, cycle, reverse) + { + //console.log("complete", context, textBox, cycle, reverse); + // TODO: xxxpedro important port to firebug (variable leak) + //var value = lastValue = textBox.value; + var value = textBox.value; + + //var offset = textBox.selectionStart; + var offset = getInputSelectionStart(textBox); + + // The result of selectionStart() in Safari/Chrome is 1 unit less than the result + // in Firefox. Therefore, we need to manually adjust the value here. + if (isSafari && !cycle && offset >= 0) offset++; + + if (!selectMode && originalOffset != -1) + offset = originalOffset; + + if (!candidates || !cycle || offset != lastOffset) + { + originalOffset = offset; + originalValue = value; + + // Find the part of the string that will be parsed + var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0; + preParsed = value.substr(0, parseStart); + var parsed = value.substr(parseStart); + + // Find the part of the string that is being completed + var range = getRange ? getRange(parsed, offset-parseStart, context) : null; + if (!range) + range = {start: 0, end: parsed.length-1 }; + + var expr = parsed.substr(range.start, range.end-range.start+1); + preExpr = parsed.substr(0, range.start); + postExpr = parsed.substr(range.end+1); + exprOffset = parseStart + range.start; + + if (!cycle) + { + if (!expr) + return; + else if (lastExpr && lastExpr.indexOf(expr) != 0) + { + candidates = null; + } + else if (lastExpr && lastExpr.length >= expr.length) + { + candidates = null; + lastExpr = expr; + return; + } + } + + lastExpr = expr; + lastOffset = offset; + + var searchExpr; + + // Check if the cursor is at the very right edge of the expression, or + // somewhere in the middle of it + if (expr && offset != parseStart+range.end+1) + { + if (cycle) + { + // We are in the middle of the expression, but we can + // complete by cycling to the next item in the values + // list after the expression + offset = range.start; + searchExpr = expr; + expr = ""; + } + else + { + // We can't complete unless we are at the ridge edge + return; + } + } + + var values = evaluator(preExpr, expr, postExpr, context); + if (!values) + return; + + if (expr) + { + // Filter the list of values to those which begin with expr. We + // will then go on to complete the first value in the resulting list + candidates = []; + + if (caseSensitive) + { + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.indexOf(expr) == 0) + candidates.push(name); + } + } + else + { + var lowerExpr = caseSensitive ? expr : expr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0) + candidates.push(name); + } + } + + lastIndex = reverse ? candidates.length-1 : 0; + } + else if (searchExpr) + { + var searchIndex = -1; + + // Find the first instance of searchExpr in the values list. We + // will then complete the string that is found + if (caseSensitive) + { + searchIndex = values.indexOf(expr); + } + else + { + var lowerExpr = searchExpr.toLowerCase(); + for (var i = 0; i < values.length; ++i) + { + var name = values[i]; + if (name && name.toLowerCase().indexOf(lowerExpr) == 0) + { + searchIndex = i; + break; + } + } + } + + // Nothing found, so there's nothing to complete to + if (searchIndex == -1) + return this.reset(); + + expr = searchExpr; + candidates = cloneArray(values); + lastIndex = searchIndex; + } + else + { + expr = ""; + candidates = []; + for (var i = 0; i < values.length; ++i) + { + if (values[i].substr) + candidates.push(values[i]); + } + lastIndex = -1; + } + } + + if (cycle) + { + expr = lastExpr; + lastIndex += reverse ? -1 : 1; + } + + if (!candidates.length) + return; + + if (lastIndex >= candidates.length) + lastIndex = 0; + else if (lastIndex < 0) + lastIndex = candidates.length-1; + + var completion = candidates[lastIndex]; + var preCompletion = expr.substr(0, offset-exprOffset); + var postCompletion = completion.substr(offset-exprOffset); + + textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr; + var offsetEnd = preParsed.length + preExpr.length + completion.length; + + // TODO: xxxpedro remove the following commented code, if the lib.setSelectionRange() + // is working well. + /* + if (textBox.setSelectionRange) + { + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + setTimeout(function(){ + if (selectMode) + textBox.setSelectionRange(offset, offsetEnd); + else + textBox.setSelectionRange(offsetEnd, offsetEnd); + },0); + } + /**/ + + // we must select the range with a timeout, otherwise the text won't + // be properly selected (because after this function executes, the editor's + // input will be resized to fit the whole text) + /* + setTimeout(function(){ + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + },0); + + return true; + /**/ + + // The editor text should be selected only after calling the editor.update() + // in Safari/Chrome, otherwise the text won't be selected. So, we're returning + // a function to be called later (in the proper time for all browsers). + // + // TODO: xxxpedro see if we can move the editor.update() calls to here, and avoid + // returning a closure. the complete() function seems to be called only twice in + // editor.js. See if this function is called anywhere else (like css.js for example). + return function(){ + //console.log("autocomplete ", textBox, offset, offsetEnd); + + if (selectMode) + setSelectionRange(textBox, offset, offsetEnd); + else + setSelectionRange(textBox, offsetEnd, offsetEnd); + }; + /**/ + }; +}; + +// ************************************************************************************************ +// Local Helpers + +var getDefaultEditor = function getDefaultEditor(panel) +{ + if (!defaultEditor) + { + var doc = panel.document; + defaultEditor = new Firebug.InlineEditor(doc); + } + + return defaultEditor; +} + +/** + * An outsider is the first element matching the stepper element that + * is not an child of group. Elements tagged with insertBefore or insertAfter + * classes are also excluded from these results unless they are the sibling + * of group, relative to group's parent editGroup. This allows for the proper insertion + * rows when groups are nested. + */ +var getOutsider = function getOutsider(element, group, stepper) +{ + var parentGroup = getAncestorByClass(group.parentNode, "editGroup"); + var next; + do + { + next = stepper(next || element); + } + while (isAncestor(next, group) || isGroupInsert(next, parentGroup)); + + return next; +} + +var isGroupInsert = function isGroupInsert(next, group) +{ + return (!group || isAncestor(next, group)) + && (hasClass(next, "insertBefore") || hasClass(next, "insertAfter")); +} + +var getNextOutsider = function getNextOutsider(element, group) +{ + return getOutsider(element, group, bind(getNextByClass, FBL, "editable")); +} + +var getPreviousOutsider = function getPreviousOutsider(element, group) +{ + return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable")); +} + +var getInlineParent = function getInlineParent(element) +{ + var lastInline = element; + for (; element; element = element.parentNode) + { + //var s = element.ownerDocument.defaultView.getComputedStyle(element, ""); + var s = isIE ? + element.currentStyle : + element.ownerDocument.defaultView.getComputedStyle(element, ""); + + if (s.display != "inline") + return lastInline; + else + lastInline = element; + } + return null; +} + +var insertTab = function insertTab() +{ + insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.Editor); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Inspector Module + +var ElementCache = Firebug.Lite.Cache.Element; + +var inspectorTS, inspectorTimer, isInspecting; + +Firebug.Inspector = +{ + create: function() + { + offlineFragment = Env.browser.document.createDocumentFragment(); + + createBoxModelInspector(); + createOutlineInspector(); + }, + + destroy: function() + { + destroyBoxModelInspector(); + destroyOutlineInspector(); + + offlineFragment = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inspect functions + + toggleInspect: function() + { + if (isInspecting) + { + this.stopInspecting(); + } + else + { + Firebug.chrome.inspectButton.changeState("pressed"); + this.startInspecting(); + } + }, + + startInspecting: function() + { + isInspecting = true; + + Firebug.chrome.selectPanel("HTML"); + + createInspectorFrame(); + + var size = Firebug.browser.getWindowScrollSize(); + + fbInspectFrame.style.width = size.width + "px"; + fbInspectFrame.style.height = size.height + "px"; + + //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody); + + addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + }, + + stopInspecting: function() + { + isInspecting = false; + + if (outlineVisible) this.hideOutline(); + removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); + removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); + + destroyInspectorFrame(); + + Firebug.chrome.inspectButton.restore(); + + if (Firebug.chrome.type == "popup") + Firebug.chrome.node.focus(); + }, + + onInspectingClick: function(e) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + //Firebug.Console.log(targ); + Firebug.Inspector.stopInspecting(); + }, + + onInspecting: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + fbInspectFrame.style.display = "none"; + var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); + fbInspectFrame.style.display = "block"; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache(targ)) + { + var target = ""+ElementCache.key(targ); + var lazySelect = function() + { + inspectorTS = new Date().getTime(); + + Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)) + }; + + if (inspectorTimer) + { + clearTimeout(inspectorTimer); + inspectorTimer = null; + } + + if (new Date().getTime() - inspectorTS > 200) + setTimeout(lazySelect, 0) + else + inspectorTimer = setTimeout(lazySelect, 300); + } + + lastInspecting = new Date().getTime(); + } + }, + + // TODO: xxxpedro remove this? + onInspectingBody: function(e) + { + if (new Date().getTime() - lastInspecting > 30) + { + var targ = e.target; + + // Avoid inspecting the outline, and the FirebugUI + var id = targ.id; + if (id && /^fbOutline\w$/.test(id)) return; + if (id == "FirebugUI") return; + + // Avoid looking at text nodes in Opera + while (targ.nodeType != 1) targ = targ.parentNode; + + if (targ.nodeName.toLowerCase() == "body") return; + + //Firebug.Console.log(e.clientX, e.clientY, targ); + Firebug.Inspector.drawOutline(targ); + + if (ElementCache.has(targ)) + FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)); + + lastInspecting = new Date().getTime(); + } + }, + + /** + * + * llttttttrr + * llttttttrr + * ll rr + * ll rr + * llbbbbbbrr + * llbbbbbbrr + */ + drawOutline: function(el) + { + var border = 2; + var scrollbarSize = 17; + + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + var box = Firebug.browser.getElementBox(el); + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width - + (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible + scrollbarSize : 0); + + var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height - + (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible + scrollbarSize : 0); + + var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1; + + var o = outlineElements; + var style; + + style = o.fbOutlineT.style; + style.top = top-border + "px"; + style.left = left + "px"; + style.height = border + "px"; // TODO: on initialize() + style.width = width + "px"; + + style = o.fbOutlineL.style; + style.top = top-border + "px"; + style.left = left-border + "px"; + style.height = height+ numVerticalBorders*border + "px"; + style.width = border + "px"; // TODO: on initialize() + + style = o.fbOutlineB.style; + if (freeVerticalSpace > 0) + { + style.top = top+height + "px"; + style.left = left + "px"; + style.width = width + "px"; + //style.height = border + "px"; // TODO: on initialize() or worst case? + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.width = border + "px"; + //style.height = border + "px"; + } + + style = o.fbOutlineR.style; + if (freeHorizontalSpace > 0) + { + style.top = top-border + "px"; + style.left = left+width + "px"; + style.height = height + numVerticalBorders*border + "px"; + style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px"; + } + else + { + style.top = -2*border + "px"; + style.left = -2*border + "px"; + style.height = border + "px"; + style.width = border + "px"; + } + + if (!outlineVisible) this.showOutline(); + }, + + hideOutline: function() + { + if (!outlineVisible) return; + + for (var name in outline) + offlineFragment.appendChild(outlineElements[name]); + + outlineVisible = false; + }, + + showOutline: function() + { + if (outlineVisible) return; + + if (boxModelVisible) this.hideBoxModel(); + + for (var name in outline) + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]); + + outlineVisible = true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Box Model + + drawBoxModel: function(el) + { + // avoid error when the element is not attached a document + if (!el || !el.parentNode) + return; + + var box = Firebug.browser.getElementBox(el); + + var windowSize = Firebug.browser.getWindowSize(); + var scrollPosition = Firebug.browser.getWindowScrollPosition(); + + // element may be occluded by the chrome, when in frame mode + var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0; + + // if element box is not inside the viewport, don't draw the box model + if (box.top > scrollPosition.top + windowSize.height - offsetHeight || + box.left > scrollPosition.left + windowSize.width || + scrollPosition.top > box.top + box.height || + scrollPosition.left > box.left + box.width ) + return; + + var top = box.top; + var left = box.left; + var height = box.height; + var width = box.width; + + var margin = Firebug.browser.getMeasurementBox(el, "margin"); + var padding = Firebug.browser.getMeasurementBox(el, "padding"); + var border = Firebug.browser.getMeasurementBox(el, "border"); + + boxModelStyle.top = top - margin.top + "px"; + boxModelStyle.left = left - margin.left + "px"; + boxModelStyle.height = height + margin.top + margin.bottom + "px"; + boxModelStyle.width = width + margin.left + margin.right + "px"; + + boxBorderStyle.top = margin.top + "px"; + boxBorderStyle.left = margin.left + "px"; + boxBorderStyle.height = height + "px"; + boxBorderStyle.width = width + "px"; + + boxPaddingStyle.top = margin.top + border.top + "px"; + boxPaddingStyle.left = margin.left + border.left + "px"; + boxPaddingStyle.height = height - border.top - border.bottom + "px"; + boxPaddingStyle.width = width - border.left - border.right + "px"; + + boxContentStyle.top = margin.top + border.top + padding.top + "px"; + boxContentStyle.left = margin.left + border.left + padding.left + "px"; + boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px"; + boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px"; + + if (!boxModelVisible) this.showBoxModel(); + }, + + hideBoxModel: function() + { + if (!boxModelVisible) return; + + offlineFragment.appendChild(boxModel); + boxModelVisible = false; + }, + + showBoxModel: function() + { + if (boxModelVisible) return; + + if (outlineVisible) this.hideOutline(); + + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel); + boxModelVisible = true; + } + +}; + +// ************************************************************************************************ +// Inspector Internals + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Shared variables + + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Internal variables + +var offlineFragment = null; + +var boxModelVisible = false; + +var boxModel, boxModelStyle, + boxMargin, boxMarginStyle, + boxBorder, boxBorderStyle, + boxPadding, boxPaddingStyle, + boxContent, boxContentStyle; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; +var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;"; + +var inspectStyle = resetStyle + "z-index: 2147483500;"; +var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" + + Env.Location.skinDir + "pixel_transparent.gif);"; + +//if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);"; + +var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;"; +var inspectModelStyle = inspectStyle + inspectModelOpacity; +var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;"; +var inspectBorderStyle = inspectStyle + "background: #666;"; +var inspectPaddingStyle = inspectStyle + "background: SlateBlue;"; +var inspectContentStyle = inspectStyle + "background: SkyBlue;"; + + +var outlineStyle = { + fbHorizontalLine: "background: #3875D7;height: 2px;", + fbVerticalLine: "background: #3875D7;width: 2px;" +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var lastInspecting = 0; +var fbInspectFrame = null; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var outlineVisible = false; +var outlineElements = {}; +var outline = { + "fbOutlineT": "fbHorizontalLine", + "fbOutlineL": "fbVerticalLine", + "fbOutlineB": "fbHorizontalLine", + "fbOutlineR": "fbVerticalLine" +}; + + +var getInspectingTarget = function() +{ + +}; + +// ************************************************************************************************ +// Section + +var createInspectorFrame = function createInspectorFrame() +{ + fbInspectFrame = createGlobalElement("div"); + fbInspectFrame.id = "fbInspectFrame"; + fbInspectFrame.firebugIgnore = true; + fbInspectFrame.style.cssText = inspectFrameStyle; + Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame); +}; + +var destroyInspectorFrame = function destroyInspectorFrame() +{ + if (fbInspectFrame) + { + Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame); + fbInspectFrame = null; + } +}; + +var createOutlineInspector = function createOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name] = createGlobalElement("div"); + el.id = name; + el.firebugIgnore = true; + el.style.cssText = inspectStyle + outlineStyle[outline[name]]; + offlineFragment.appendChild(el); + } +}; + +var destroyOutlineInspector = function destroyOutlineInspector() +{ + for (var name in outline) + { + var el = outlineElements[name]; + el.parentNode.removeChild(el); + } +}; + +var createBoxModelInspector = function createBoxModelInspector() +{ + boxModel = createGlobalElement("div"); + boxModel.id = "fbBoxModel"; + boxModel.firebugIgnore = true; + boxModelStyle = boxModel.style; + boxModelStyle.cssText = inspectModelStyle; + + boxMargin = createGlobalElement("div"); + boxMargin.id = "fbBoxMargin"; + boxMarginStyle = boxMargin.style; + boxMarginStyle.cssText = inspectMarginStyle; + boxModel.appendChild(boxMargin); + + boxBorder = createGlobalElement("div"); + boxBorder.id = "fbBoxBorder"; + boxBorderStyle = boxBorder.style; + boxBorderStyle.cssText = inspectBorderStyle; + boxModel.appendChild(boxBorder); + + boxPadding = createGlobalElement("div"); + boxPadding.id = "fbBoxPadding"; + boxPaddingStyle = boxPadding.style; + boxPaddingStyle.cssText = inspectPaddingStyle; + boxModel.appendChild(boxPadding); + + boxContent = createGlobalElement("div"); + boxContent.id = "fbBoxContent"; + boxContentStyle = boxContent.style; + boxContentStyle.cssText = inspectContentStyle; + boxModel.appendChild(boxContent); + + offlineFragment.appendChild(boxModel); +}; + +var destroyBoxModelInspector = function destroyBoxModelInspector() +{ + boxModel.parentNode.removeChild(boxModel); +}; + +// ************************************************************************************************ +// Section + + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +// next-generation Console Panel (will override consoje.js) +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Constants + +/* +const Cc = Components.classes; +const Ci = Components.interfaces; +const nsIPrefBranch2 = Ci.nsIPrefBranch2; +const PrefService = Cc["@mozilla.org/preferences-service;1"]; +const prefs = PrefService.getService(nsIPrefBranch2); +/**/ +/* + +// new offline message handler +o = {x:1,y:2}; + +r = Firebug.getRep(o); + +r.tag.tag.compile(); + +outputs = []; +html = r.tag.renderHTML({object:o}, outputs); + + +// finish rendering the template (the DOM part) +target = $("build"); +target.innerHTML = html; +root = target.firstChild; + +domArgs = [root, r.tag.context, 0]; +domArgs.push.apply(domArgs, r.tag.domArgs); +domArgs.push.apply(domArgs, outputs); +r.tag.tag.renderDOM.apply(self ? self : r.tag.subject, domArgs); + + + */ +var consoleQueue = []; +var lastHighlightedObject; +var FirebugContext = Env.browser; + +// ************************************************************************************************ + +var maxQueueRequests = 500; + +// ************************************************************************************************ + +Firebug.ConsoleBase = +{ + log: function(object, context, className, rep, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"log",[context, object, className, sourceLink]); + return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle); + }, + + logFormatted: function(objects, context, className, noThrottle, sourceLink) + { + //dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]); + return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle); + }, + + openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush) + { + return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle); + }, + + closeGroup: function(context, noThrottle) + { + return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true); + }, + + logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow) + { + // TODO: xxxpedro console console2 + noThrottle = true; // xxxpedro forced because there is no TabContext yet + + if (!context) + context = FirebugContext; + + if (FBTrace.DBG_ERRORS && !context) + FBTrace.sysout("Console.logRow has no context, skipping objects", objects); + + if (!context) + return; + + if (noThrottle || !context) + { + var panel = this.getPanel(context); + if (panel) + { + var row = panel.append(appender, objects, className, rep, sourceLink, noRow); + var container = panel.panelNode; + + // TODO: xxxpedro what is this? console console2 + /* + var template = Firebug.NetMonitor.NetLimit; + + while (container.childNodes.length > maxQueueRequests + 1) + { + clearDomplate(container.firstChild.nextSibling); + container.removeChild(container.firstChild.nextSibling); + panel.limit.limitInfo.totalCount++; + template.updateCounter(panel.limit); + } + dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]); + /**/ + return row; + } + else + { + consoleQueue.push([appender, objects, context, className, rep, sourceLink, noThrottle, noRow]); + } + } + else + { + if (!context.throttle) + { + //FBTrace.sysout("console.logRow has not context.throttle! "); + return; + } + var args = [appender, objects, context, className, rep, sourceLink, true, noRow]; + context.throttle(this.logRow, this, args); + } + }, + + appendFormatted: function(args, row, context) + { + if (!context) + context = FirebugContext; + + var panel = this.getPanel(context); + panel.appendFormatted(args, row); + }, + + clear: function(context) + { + if (!context) + //context = FirebugContext; + context = Firebug.context; + + /* + if (context) + Firebug.Errors.clear(context); + /**/ + + var panel = this.getPanel(context, true); + if (panel) + { + panel.clear(); + } + }, + + // Override to direct output to your panel + getPanel: function(context, noCreate) + { + //return context.getPanel("console", noCreate); + // TODO: xxxpedro console console2 + return Firebug.chrome ? Firebug.chrome.getPanel("Console") : null; + } + +}; + +// ************************************************************************************************ + +//TODO: xxxpedro +//var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase); +var ActivableConsole = extend(Firebug.ConsoleBase, +{ + isAlwaysEnabled: function() + { + return true; + } +}); + +Firebug.Console = Firebug.Console = extend(ActivableConsole, +//Firebug.Console = extend(ActivableConsole, +{ + dispatchName: "console", + + error: function() + { + Firebug.Console.logFormatted(arguments, Firebug.browser, "error"); + }, + + flush: function() + { + dispatch(this.fbListeners,"flush",[]); + + for (var i=0, length=consoleQueue.length; i objects.length) // then too few parameters for format, assume unformatted. + { + format = ""; + objIndex = -1; + parts.length = 0; + break; + } + } + + } + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + if (typeof(object) != "undefined") + this.appendObject(object, row, part.rep); + else + this.appendObject(part.type, row, FirebugReps.Text); + } + else + FirebugReps.Text.tag.append({object: part}, row); + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + logText(" ", row); + var object = objects[i]; + if (typeof(object) == "string") + FirebugReps.Text.tag.append({object: object}, row); + else + this.appendObject(object, row); + } + }, + + appendOpenGroup: function(objects, row, rep) + { + if (!this.groups) + this.groups = []; + + setClass(row, "logGroup"); + setClass(row, "opened"); + + var innerRow = this.createRow("logRow"); + setClass(innerRow, "logGroupLabel"); + if (rep) + rep.tag.replace({"objects": objects}, innerRow); + else + this.appendFormatted(objects, innerRow, rep); + row.appendChild(innerRow); + //dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]); + var groupBody = this.createRow("logGroupBody"); + row.appendChild(groupBody); + groupBody.setAttribute('role', 'group'); + this.groups.push(groupBody); + + addEvent(innerRow, "mousedown", function(event) + { + if (isLeftClick(event)) + { + //console.log(event.currentTarget == event.target); + + var target = event.target || event.srcElement; + + target = getAncestorByClass(target, "logGroupLabel"); + + var groupRow = target.parentNode; + + if (hasClass(groupRow, "opened")) + { + removeClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'false'); + } + else + { + setClass(groupRow, "opened"); + target.setAttribute('aria-expanded', 'true'); + } + } + }); + }, + + appendCloseGroup: function(object, row, rep) + { + if (this.groups) + this.groups.pop(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // TODO: xxxpedro console2 + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + onMouseDown: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + var repObject = object ? object.repObject : null; + + if (!repObject) + { + return; + } + + if (hasClass(object, "objectLink-object")) + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(repObject, true); + } + else if (hasClass(object, "objectLink-element")) + { + Firebug.chrome.selectPanel("HTML"); + Firebug.chrome.getPanel("HTML").select(repObject, true); + } + + /* + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + /**/ + + }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "Console", + title: "Console", + //searchable: true, + //breakable: true, + //editable: false, + + options: + { + hasCommandLine: true, + hasToolButtons: true, + isPreRendered: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.context = Firebug.browser.window; + this.document = Firebug.chrome.document; + this.onMouseMove = bind(this.onMouseMove, this); + this.onMouseDown = bind(this.onMouseDown, this); + + this.clearButton = new Button({ + element: $("fbConsole_btClear"), + owner: Firebug.Console, + onClick: Firebug.Console.clear + }); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); // loads persisted content + //Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content + + if (!this.persistedContent && Firebug.Console.isAlwaysEnabled()) + { + this.insertLogLimit(this.context); + + // Initialize log limit and listen for changes. + this.updateMaxLimit(); + + if (this.context.consoleReloadWarning) // we have not yet injected the console + this.insertReloadWarning(); + } + + //Firebug.Console.injector.install(Firebug.browser.window); + + addEvent(this.panelNode, "mouseover", this.onMouseMove); + addEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.clearButton.initialize(); + + //consolex.trace(); + //TODO: xxxpedro remove this + /* + Firebug.Console.openGroup(["asd"], null, "group", null, false); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + Firebug.Console.log("asd"); + /**/ + + //TODO: xxxpedro preferences prefs + //prefs.addObserver(Firebug.prefDomain, this, false); + }, + + initializeNode : function() + { + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this]); + if (FBTrace.DBG_CONSOLE) + { + this.onScroller = bind(this.onScroll, this); + addEvent(this.panelNode, "scroll", this.onScroller); + } + + this.onResizer = bind(this.onResize, this); + this.resizeEventTarget = Firebug.chrome.$('fbContentBox'); + addEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + destroyNode : function() + { + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this]); + if (this.onScroller) + removeEvent(this.panelNode, "scroll", this.onScroller); + + //removeEvent(this.resizeEventTarget, "resize", this.onResizer); + }, + + shutdown: function() + { + //TODO: xxxpedro console console2 + this.clearButton.shutdown(); + + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + + //TODO: xxxpedro preferences prefs + //prefs.removeObserver(Firebug.prefDomain, this, false); + }, + + ishow: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel show; " + this.context.getName(), state); + + var enabled = Firebug.Console.isAlwaysEnabled(); + if (enabled) + { + Firebug.Console.disabledPanelPage.hide(this); + this.showCommandLine(true); + this.showToolbarButtons("fbConsoleButtons", true); + Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent); + + if (state && state.wasScrolledToBottom) + { + this.wasScrolledToBottom = state.wasScrolledToBottom; + delete state.wasScrolledToBottom; + } + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + } + else + { + this.hide(state); + Firebug.Console.disabledPanelPage.show(this); + } + }, + + ihide: function(state) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("Console.panel hide; " + this.context.getName(), state); + + this.showToolbarButtons("fbConsoleButtons", false); + this.showCommandLine(false); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + destroy: function(state) + { + if (this.panelNode.offsetHeight) + this.wasScrolledToBottom = isScrolledToBottom(this.panelNode); + + if (state) + state.wasScrolledToBottom = this.wasScrolledToBottom; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", " + this.context.getName()); + }, + + shouldBreakOnNext: function() + { + // xxxHonza: shouldn't the breakOnErrors be context related? + // xxxJJB, yes, but we can't support it because we can't yet tell + // which window the error is on. + return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors"); + }, + + getBreakOnNextTooltip: function(enabled) + { + return (enabled ? $STR("console.Disable Break On All Errors") : + $STR("console.Break On All Errors")); + }, + + enablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.enablePanel.apply(this, arguments); + + this.showCommandLine(true); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + }, + + disablePanel: function(module) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName()); + + Firebug.ActivablePanel.disablePanel.apply(this, arguments); + + this.showCommandLine(false); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowJavaScriptErrors", "showJSErrors"), + optionMenu("ShowJavaScriptWarnings", "showJSWarnings"), + optionMenu("ShowCSSErrors", "showCSSErrors"), + optionMenu("ShowXMLErrors", "showXMLErrors"), + optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"), + optionMenu("ShowChromeErrors", "showChromeErrors"), + optionMenu("ShowChromeMessages", "showChromeMessages"), + optionMenu("ShowExternalErrors", "showExternalErrors"), + optionMenu("ShowNetworkErrors", "showNetworkErrors"), + this.getShowStackTraceMenuItem(), + this.getStrictOptionMenuItem(), + "-", + optionMenu("LargeCommandLine", "largeCommandLine") + ]; + }, + + getShowStackTraceMenuItem: function() + { + var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace"); + if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled()) + menuItem.disabled = true; + return menuItem; + }, + + getStrictOptionMenuItem: function() + { + var strictDomain = "javascript.options"; + var strictName = "strict"; + var strictValue = prefs.getBoolPref(strictDomain+"."+strictName); + return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue, + command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) }; + }, + + getBreakOnMenuItems: function() + { + //xxxHonza: no BON options for now. + /*return [ + optionMenu("console.option.Persist Break On Error", "persistBreakOnError") + ];*/ + return []; + }, + + search: function(text) + { + if (!text) + return; + + // Make previously visible nodes invisible again + if (this.matchSet) + { + for (var i in this.matchSet) + removeClass(this.matchSet[i], "matched"); + } + + this.matchSet = []; + + function findRow(node) { return getAncestorByClass(node, "logRow"); } + var search = new TextSearch(this.panelNode, findRow); + + var logRow = search.find(text); + if (!logRow) + { + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]); + return false; + } + for (; logRow; logRow = search.findNext()) + { + setClass(logRow, "matched"); + this.matchSet.push(logRow); + } + dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]); + return true; + }, + + breakOnNext: function(breaking) + { + Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // private + + createRow: function(rowName, className) + { + var elt = this.document.createElement("div"); + elt.className = rowName + (className ? " " + rowName + "-" + className : ""); + return elt; + }, + + getTopContainer: function() + { + if (this.groups && this.groups.length) + return this.groups[this.groups.length-1]; + else + return this.panelNode; + }, + + filterLogRow: function(logRow, scrolledToBottom) + { + if (this.searchText) + { + setClass(logRow, "matching"); + setClass(logRow, "matched"); + + // Search after a delay because we must wait for a frame to be created for + // the new logRow so that the finder will be able to locate it + setTimeout(bindFixed(function() + { + if (this.searchFilter(this.searchText, logRow)) + this.matchSet.push(logRow); + else + removeClass(logRow, "matched"); + + removeClass(logRow, "matching"); + + if (scrolledToBottom) + scrollToBottom(this.panelNode); + }, this), 100); + } + }, + + searchFilter: function(text, logRow) + { + var count = this.panelNode.childNodes.length; + var searchRange = this.document.createRange(); + searchRange.setStart(this.panelNode, 0); + searchRange.setEnd(this.panelNode, count); + + var startPt = this.document.createRange(); + startPt.setStartBefore(logRow); + + var endPt = this.document.createRange(); + endPt.setStartAfter(logRow); + + return finder.Find(text, searchRange, startPt, endPt) != null; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + // xxxHonza check this out. + var prefDomain = "Firebug.extension."; + var prefName = data.substr(prefDomain.length); + if (prefName == "console.logLimit") + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = 1000; + //TODO: xxxpedro preferences log limit? + //var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + }, + + showCommandLine: function(shouldShow) + { + //TODO: xxxpedro show command line important + return; + + if (shouldShow) + { + collapse(Firebug.chrome.$("fbCommandBox"), false); + Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome); + } + else + { + // Make sure that entire content of the Console panel is hidden when + // the panel is disabled. + Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine); + collapse(Firebug.chrome.$("fbCommandBox"), true); + } + }, + + onScroll: function(event) + { + // Update the scroll position flag if the position changes. + this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", wasScrolledToBottom: " + + this.context.getName(), event); + }, + + onResize: function(event) + { + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " + + this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight + + ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " + + this.panelNode.scrollHeight + ", " + this.context.getName(), event); + + if (this.wasScrolledToBottom) + scrollToBottom(this.panelNode); + } +}); + +// ************************************************************************************************ + +function parseFormat(format) +{ + var parts = []; + if (format.length <= 0) + return parts; + + var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + if (m[0].substr(0, 2) == "%%") + { + parts.push(format.substr(0, m.index)); + parts.push(m[0].substr(1)); + } + else + { + var type = m[8] ? m[8] : m[5]; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + var rep = null; + switch (type) + { + case "s": + rep = FirebugReps.Text; + break; + case "f": + case "i": + case "d": + rep = FirebugReps.Number; + break; + case "o": + rep = null; + break; + } + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({rep: rep, precision: precision, type: ("%" + type)}); + } + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + return parts; +} + +// ************************************************************************************************ + +var appendObject = Firebug.ConsolePanel.prototype.appendObject; +var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted; +var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup; +var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup; + +// ************************************************************************************************ + +//Firebug.registerActivableModule(Firebug.Console); +Firebug.registerModule(Firebug.Console); +Firebug.registerPanel(Firebug.ConsolePanel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +var frameCounters = {}; +var traceRecursion = 0; + +Firebug.Console.injector = +{ + install: function(context) + { + var win = context.window; + + var consoleHandler = new FirebugConsoleHandler(context, win); + + var properties = + [ + "log", + "debug", + "info", + "warn", + "error", + "assert", + "dir", + "dirxml", + "group", + "groupCollapsed", + "groupEnd", + "time", + "timeEnd", + "count", + "trace", + "profile", + "profileEnd", + "clear", + "open", + "close" + ]; + + var Handler = function(name) + { + var c = consoleHandler; + var f = consoleHandler[name]; + return function(){return f.apply(c,arguments)}; + }; + + var installer = function(c) + { + for (var i=0, l=properties.length; i 1) + { + traceRecursion--; + return; + } + + var frames = []; + + for (var fn = arguments.callee.caller.caller; fn; fn = fn.caller) + { + if (wasVisited(fn)) break; + + var args = []; + + for (var i = 0, l = fn.arguments.length; i < l; ++i) + { + args.push({value: fn.arguments[i]}); + } + + frames.push({fn: fn, name: getFuncName(fn), args: args}); + } + + + // **************************************************************************************** + + try + { + (0)(); + } + catch(e) + { + var result = e; + + var stack = + result.stack || // Firefox / Google Chrome + result.stacktrace || // Opera + ""; + + stack = stack.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks + var items = stack.split(/[\n\r]/); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Google Chrome + if (FBL.isSafari) + { + //var reChromeStackItem = /^\s+at\s+([^\(]+)\s\((.*)\)$/; + //var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/; + + var reChromeStackItemName = /\s*\($/; + var reChromeStackItemValue = /^(.+)\:(\d+\:\d+)\)?$/; + + var framePos = 0; + for (var i=4, length=items.length; i 1) + { + objects = [errorObject]; + for (var i = 1; i < args.length; i++) + objects.push(args[i]); + } + + var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle + row.scrollIntoView(); + } + + function getComponentsStackDump() + { + // Starting with our stack, walk back to the user-level code + var frame = Components.stack; + var userURL = win.location.href.toString(); + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame); + + // Drop frames until we get into user code. + while (frame && FBL.isSystemURL(frame.filename) ) + frame = frame.caller; + + // Drop two more frames, the injected console function and firebugAppendConsole() + if (frame) + frame = frame.caller; + if (frame) + frame = frame.caller; + + if (FBTrace.DBG_CONSOLE) + FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame); + + return frame; + } + + function getStackLink() + { + // TODO: xxxpedro console2 + return; + //return FBL.getFrameSourceLink(getComponentsStackDump()); + } + + function getJSDUserStack() + { + var trace = FBL.getCurrentStackTrace(context); + + var frames = trace ? trace.frames : null; + if (frames && (frames.length > 0) ) + { + var oldest = frames.length - 1; // 6 - 1 = 5 + for (var i = 0; i < frames.length; i++) + { + if (frames[oldest - i].href.indexOf("chrome:") == 0) break; + var fn = frames[oldest - i].fn + ""; + if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line + } + FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace); + trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code + + return trace; + } + else + return "Firebug failed to get stack trace with any frames"; + } +} + +// ************************************************************************************************ +// Register console namespace + +FBL.registerConsole = function() +{ + //TODO: xxxpedro console options override + //if (Env.Options.overrideConsole) + var win = Env.browser.window; + Firebug.Console.injector.install(win); +}; + +registerConsole(); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + + +// ************************************************************************************************ +// Globals + +var commandPrefix = ">>>"; +var reOpenBracket = /[\[\(\{]/; +var reCloseBracket = /[\]\)\}]/; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var commandHistory = []; +var commandPointer = -1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var isAutoCompleting = null; +var autoCompletePrefix = null; +var autoCompleteExpr = null; +var autoCompleteBuffer = null; +var autoCompletePosition = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var fbCommandLine = null; +var fbLargeCommandLine = null; +var fbLargeCommandButtons = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _completion = +{ + window: + [ + "console" + ], + + document: + [ + "getElementById", + "getElementsByTagName" + ] +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var _stack = function(command) +{ + commandHistory.push(command); + commandPointer = commandHistory.length; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +// ************************************************************************************************ +// CommandLine + +Firebug.CommandLine = extend(Firebug.Module, +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + element: null, + isMultiLine: false, + isActive: false, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + initialize: function(doc) + { + this.clear = bind(this.clear, this); + this.enter = bind(this.enter, this); + + this.onError = bind(this.onError, this); + this.onKeyDown = bind(this.onKeyDown, this); + this.onMultiLineKeyDown = bind(this.onMultiLineKeyDown, this); + + addEvent(Firebug.browser.window, "error", this.onError); + addEvent(Firebug.chrome.window, "error", this.onError); + }, + + shutdown: function(doc) + { + this.deactivate(); + + removeEvent(Firebug.browser.window, "error", this.onError); + removeEvent(Firebug.chrome.window, "error", this.onError); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + activate: function(multiLine, hideToggleIcon, onRun) + { + defineCommandLineAPI(); + + if (this.isActive) + { + if (this.isMultiLine == multiLine) return; + + this.deactivate(); + } + + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); + + if (multiLine) + { + onRun = onRun || this.enter; + + this.isMultiLine = true; + + this.element = fbLargeCommandLine; + + addEvent(this.element, "keydown", this.onMultiLineKeyDown); + + addEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton = new Button({ + element: $("fbCommand_btRun"), + owner: Firebug.CommandLine, + onClick: onRun + }); + + this.runButton.initialize(); + + this.clearButton = new Button({ + element: $("fbCommand_btClear"), + owner: Firebug.CommandLine, + onClick: this.clear + }); + + this.clearButton.initialize(); + } + else + { + this.isMultiLine = false; + this.element = fbCommandLine; + + if (!fbCommandLine) + return; + + addEvent(this.element, "keydown", this.onKeyDown); + } + + //Firebug.Console.log("activate", this.element); + + if (isOpera) + fixOperaTabKey(this.element); + + if(this.lastValue) + this.element.value = this.lastValue; + + this.isActive = true; + }, + + deactivate: function() + { + if (!this.isActive) return; + + //Firebug.Console.log("deactivate", this.element); + + this.isActive = false; + + this.lastValue = this.element.value; + + if (this.isMultiLine) + { + removeEvent(this.element, "keydown", this.onMultiLineKeyDown); + + removeEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine); + + this.runButton.destroy(); + this.clearButton.destroy(); + } + else + { + removeEvent(this.element, "keydown", this.onKeyDown); + } + + this.element = null + delete this.element; + + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + focus: function() + { + this.element.focus(); + }, + + blur: function() + { + this.element.blur(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + clear: function() + { + this.element.value = ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + evaluate: function(expr) + { + // TODO: need to register the API in console.firebug.commandLineAPI + var api = "Firebug.CommandLine.API" + + var result = Firebug.context.evaluate(expr, "window", api, Firebug.Console.error); + + return result; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + enter: function() + { + var command = this.element.value; + + if (!command) return; + + _stack(command); + + Firebug.Console.log(commandPrefix + " " + stripNewLines(command), Firebug.browser, "command", FirebugReps.Text); + + var result = this.evaluate(command); + + Firebug.Console.log(result); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + prevCommand: function() + { + if (commandPointer > 0 && commandHistory.length > 0) + this.element.value = commandHistory[--commandPointer]; + }, + + nextCommand: function() + { + var element = this.element; + + var limit = commandHistory.length -1; + var i = commandPointer; + + if (i < limit) + element.value = commandHistory[++commandPointer]; + + else if (i == limit) + { + ++commandPointer; + element.value = ""; + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + autocomplete: function(reverse) + { + var element = this.element; + + var command = element.value; + var offset = getExpressionOffset(command); + + var valBegin = offset ? command.substr(0, offset) : ""; + var val = command.substr(offset); + + var buffer, obj, objName, commandBegin, result, prefix; + + // if it is the beginning of the completion + if(!isAutoCompleting) + { + + // group1 - command begin + // group2 - base object + // group3 - property prefix + var reObj = /(.*[^_$\w\d\.])?((?:[_$\w][_$\w\d]*\.)*)([_$\w][_$\w\d]*)?$/; + var r = reObj.exec(val); + + // parse command + if (r[1] || r[2] || r[3]) + { + commandBegin = r[1] || ""; + objName = r[2] || ""; + prefix = r[3] || ""; + } + else if (val == "") + { + commandBegin = objName = prefix = ""; + } else + return; + + isAutoCompleting = true; + + // find base object + if(objName == "") + obj = window; + + else + { + objName = objName.replace(/\.$/, ""); + + var n = objName.split("."); + var target = window, o; + + for (var i=0, ni; ni = n[i]; i++) + { + if (o = target[ni]) + target = o; + + else + { + target = null; + break; + } + } + obj = target; + } + + // map base object + if(obj) + { + autoCompletePrefix = prefix; + autoCompleteExpr = valBegin + commandBegin + (objName ? objName + "." : ""); + autoCompletePosition = -1; + + buffer = autoCompleteBuffer = isIE ? + _completion[objName || "window"] || [] : []; + + for(var p in obj) + buffer.push(p); + } + + // if it is the continuation of the last completion + } else + buffer = autoCompleteBuffer; + + if (buffer) + { + prefix = autoCompletePrefix; + + var diff = reverse ? -1 : 1; + + for(var i=autoCompletePosition+diff, l=buffer.length, bi; i>=0 && i', msg, '', + '' + ]; + + // TODO: xxxpedro ajust to Console2 + //Firebug.Console.writeRow(html, "error"); + }, + + onKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + /*tab, shift, control, alt*/ + if (code != 9 && code != 16 && code != 17 && code != 18) + { + isAutoCompleting = false; + } + + if (code == 13 /* enter */) + { + this.enter(); + this.clear(); + } + else if (code == 27 /* ESC */) + { + setTimeout(this.clear, 0); + } + else if (code == 38 /* up */) + { + this.prevCommand(); + } + else if (code == 40 /* down */) + { + this.nextCommand(); + } + else if (code == 9 /* tab */) + { + this.autocomplete(e.shiftKey); + } + else + return; + + cancelEvent(e, true); + return false; + }, + + onMultiLineKeyDown: function(e) + { + e = e || event; + + var code = e.keyCode; + + if (code == 13 /* enter */ && e.ctrlKey) + { + this.enter(); + } + } +}); + +Firebug.registerModule(Firebug.CommandLine); + + +// ************************************************************************************************ +// + +function getExpressionOffset(command) +{ + // XXXjoe This is kind of a poor-man's JavaScript parser - trying + // to find the start of the expression that the cursor is inside. + // Not 100% fool proof, but hey... + + var bracketCount = 0; + + var start = command.length-1; + for (; start >= 0; --start) + { + var c = command[start]; + if ((c == "," || c == ";" || c == " ") && !bracketCount) + break; + if (reOpenBracket.test(c)) + { + if (bracketCount) + --bracketCount; + else + break; + } + else if (reCloseBracket.test(c)) + ++bracketCount; + } + + return start + 1; +} + +// ************************************************************************************************ +// CommandLine API + +var CommandLineAPI = +{ + $: function(id) + { + return Firebug.browser.document.getElementById(id) + }, + + $$: function(selector, context) + { + context = context || Firebug.browser.document; + return Firebug.Selector ? + Firebug.Selector(selector, context) : + Firebug.Console.error("Firebug.Selector module not loaded."); + }, + + $0: null, + + $1: null, + + dir: function(o) + { + Firebug.Console.log(o, Firebug.context, "dir", Firebug.DOMPanel.DirTable); + }, + + dirxml: function(o) + { + ///if (o instanceof Window) + if (instanceOf(o, "Window")) + o = o.document.documentElement; + ///else if (o instanceof Document) + else if (instanceOf(o, "Document")) + o = o.documentElement; + + // TODO: xxxpedro html3 + ///Firebug.Console.log(o, Firebug.context, "dirxml", Firebug.HTMLPanel.SoloElement); + var div = Firebug.Console.log(o, Firebug.context, "dirxml"); + var html = []; + Firebug.Reps.appendNode(o, html); + div.innerHTML = html.join(""); + + } +}; + +// ************************************************************************************************ + +var defineCommandLineAPI = function defineCommandLineAPI() +{ + Firebug.CommandLine.API = {}; + for (var m in CommandLineAPI) + if (!Env.browser.window[m]) + Firebug.CommandLine.API[m] = CommandLineAPI[m]; + + var stack = FirebugChrome.htmlSelectionStack; + if (stack) + { + Firebug.CommandLine.API.$0 = stack[0]; + Firebug.CommandLine.API.$1 = stack[1]; + } +}; + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +if (Env.Options.disableXHRListener) + return; + +// ************************************************************************************************ +// XHRSpy + +var XHRSpy = function() +{ + this.requestHeaders = []; + this.responseHeaders = []; +}; + +XHRSpy.prototype = +{ + method: null, + url: null, + async: null, + + xhrRequest: null, + + href: null, + + loaded: false, + + logRow: null, + + responseText: null, + + requestHeaders: null, + responseHeaders: null, + + sourceLink: null, // {href:"file.html", line: 22} + + getURL: function() + { + return this.href; + } +}; + +// ************************************************************************************************ +// XMLHttpRequestWrapper + +var XMLHttpRequestWrapper = function(activeXObject) +{ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal variables + + var xhrRequest = typeof activeXObject != "undefined" ? + activeXObject : + new _XMLHttpRequest(), + + spy = new XHRSpy(), + + self = this, + + reqType, + reqUrl, + reqStartTS; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // XMLHttpRequestWrapper internal methods + + var updateSelfPropertiesIgnore = { + abort: 1, + channel: 1, + getAllResponseHeaders: 1, + getInterface: 1, + getResponseHeader: 1, + mozBackgroundRequest: 1, + multipart: 1, + onreadystatechange: 1, + open: 1, + send: 1, + setRequestHeader: 1 + }; + + var updateSelfProperties = function() + { + if (supportsXHRIterator) + { + for (var propName in xhrRequest) + { + if (propName in updateSelfPropertiesIgnore) + continue; + + try + { + var propValue = xhrRequest[propName]; + + if (propValue && !isFunction(propValue)) + self[propName] = propValue; + } + catch(E) + { + //console.log(propName, E.message); + } + } + } + else + { + // will fail to read these xhrRequest properties if the request is not completed + if (xhrRequest.readyState == 4) + { + self.status = xhrRequest.status; + self.statusText = xhrRequest.statusText; + self.responseText = xhrRequest.responseText; + self.responseXML = xhrRequest.responseXML; + } + } + }; + + var updateXHRPropertiesIgnore = { + channel: 1, + onreadystatechange: 1, + readyState: 1, + responseBody: 1, + responseText: 1, + responseXML: 1, + status: 1, + statusText: 1, + upload: 1 + }; + + var updateXHRProperties = function() + { + for (var propName in self) + { + if (propName in updateXHRPropertiesIgnore) + continue; + + try + { + var propValue = self[propName]; + + if (propValue && !xhrRequest[propName]) + { + xhrRequest[propName] = propValue; + } + } + catch(E) + { + //console.log(propName, E.message); + } + } + }; + + var logXHR = function() + { + var row = Firebug.Console.log(spy, null, "spy", Firebug.Spy.XHR); + + if (row) + { + setClass(row, "loading"); + spy.logRow = row; + } + }; + + var finishXHR = function() + { + var duration = new Date().getTime() - reqStartTS; + var success = xhrRequest.status == 200; + + var responseHeadersText = xhrRequest.getAllResponseHeaders(); + var responses = responseHeadersText ? responseHeadersText.split(/[\n\r]/) : []; + var reHeader = /^(\S+):\s*(.*)/; + + for (var i=0, l=responses.length; i 0; + + /**/ + + return this; +}; + +// ************************************************************************************************ +// ActiveXObject Wrapper (IE6 only) + +var _ActiveXObject; +var isIE6 = /msie 6/i.test(navigator.appVersion); + +if (isIE6) +{ + _ActiveXObject = window.ActiveXObject; + + var xhrObjects = " MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP "; + + window.ActiveXObject = function(name) + { + var error = null; + + try + { + var activeXObject = new _ActiveXObject(name); + } + catch(e) + { + error = e; + } + finally + { + if (!error) + { + if (xhrObjects.indexOf(" " + name + " ") != -1) + return new XMLHttpRequestWrapper(activeXObject); + else + return activeXObject; + } + else + throw error.message; + } + }; +} + +// ************************************************************************************************ + +// Register the XMLHttpRequestWrapper for non-IE6 browsers +if (!isIE6) +{ + var _XMLHttpRequest = XMLHttpRequest; + window.XMLHttpRequest = function() + { + return new XMLHttpRequestWrapper(); + }; +} + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var reIgnore = /about:|javascript:|resource:|chrome:|jar:/; +var layoutInterval = 300; +var indentWidth = 18; + +var cacheSession = null; +var contexts = new Array(); +var panelName = "net"; +var maxQueueRequests = 500; +//var panelBar1 = $("fbPanelBar1"); // chrome not available at startup +var activeRequests = []; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var mimeExtensionMap = +{ + "txt": "text/plain", + "html": "text/html", + "htm": "text/html", + "xhtml": "text/html", + "xml": "text/xml", + "css": "text/css", + "js": "application/x-javascript", + "jss": "application/x-javascript", + "jpg": "image/jpg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "png": "image/png", + "bmp": "image/bmp", + "swf": "application/x-shockwave-flash", + "flv": "video/x-flv" +}; + +var fileCategories = +{ + "undefined": 1, + "html": 1, + "css": 1, + "js": 1, + "xhr": 1, + "image": 1, + "flash": 1, + "txt": 1, + "bin": 1 +}; + +var textFileCategories = +{ + "txt": 1, + "html": 1, + "xhr": 1, + "css": 1, + "js": 1 +}; + +var binaryFileCategories = +{ + "bin": 1, + "flash": 1 +}; + +var mimeCategoryMap = +{ + "text/plain": "txt", + "application/octet-stream": "bin", + "text/html": "html", + "text/xml": "html", + "text/css": "css", + "application/x-javascript": "js", + "text/javascript": "js", + "application/javascript" : "js", + "image/jpeg": "image", + "image/jpg": "image", + "image/gif": "image", + "image/png": "image", + "image/bmp": "image", + "application/x-shockwave-flash": "flash", + "video/x-flv": "flash" +}; + +var binaryCategoryMap = +{ + "image": 1, + "flash" : 1 +}; + +// ************************************************************************************************ + +/** + * @module Represents a module object for the Net panel. This object is derived + * from Firebug.ActivableModule in order to support activation (enable/disable). + * This allows to avoid (performance) expensive features if the functionality is not necessary + * for the user. + */ +Firebug.NetMonitor = extend(Firebug.ActivableModule, +{ + dispatchName: "netMonitor", + + clear: function(context) + { + // The user pressed a Clear button so, remove content of the panel... + var panel = context.getPanel(panelName, true); + if (panel) + panel.clear(); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + initialize: function() + { + return; + + this.panelName = panelName; + + Firebug.ActivableModule.initialize.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + // HTTP observer must be registered now (and not in monitorContext, since if a + // page is opened in a new tab the top document request would be missed otherwise. + NetHttpObserver.registerObserver(); + NetHttpActivityObserver.registerObserver(); + + Firebug.Debugger.addListener(this.DebuggerListener); + }, + + shutdown: function() + { + return; + + prefs.removeObserver(Firebug.prefDomain, this, false); + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + + NetHttpObserver.unregisterObserver(); + NetHttpActivityObserver.unregisterObserver(); + + Firebug.Debugger.removeListener(this.DebuggerListener); + } +}); + + +/** + * @domplate Represents a template that is used to reneder detailed info about a request. + * This template is rendered when a request is expanded. + */ +Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep, new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoBody", _repObject: "$file"}, + TAG("$infoTabs", {file: "$file"}), + TAG("$infoBodies", {file: "$file"}) + ), + + infoTabs: + DIV({"class": "netInfoTabs focusRow subFocusRow", "role": "tablist"}, + A({"class": "netInfoParamsTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Params", + $collapsed: "$file|hideParams"}, + $STR("URLParameters") + ), + A({"class": "netInfoHeadersTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Headers"}, + $STR("Headers") + ), + A({"class": "netInfoPostTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Post", + $collapsed: "$file|hidePost"}, + $STR("Post") + ), + A({"class": "netInfoPutTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Put", + $collapsed: "$file|hidePut"}, + $STR("Put") + ), + A({"class": "netInfoResponseTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Response", + $collapsed: "$file|hideResponse"}, + $STR("Response") + ), + A({"class": "netInfoCacheTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Cache", + $collapsed: "$file|hideCache"}, + $STR("Cache") + ), + A({"class": "netInfoHtmlTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab", + view: "Html", + $collapsed: "$file|hideHtml"}, + $STR("HTML") + ) + ), + + infoBodies: + DIV({"class": "netInfoBodies outerFocusRow"}, + TABLE({"class": "netInfoParamsText netInfoText netInfoParamsTable", "role": "tabpanel", + cellpadding: 0, cellspacing: 0}, TBODY()), + DIV({"class": "netInfoHeadersText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPostText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoPutText netInfoText", "role": "tabpanel"}), + PRE({"class": "netInfoResponseText netInfoText", "role": "tabpanel"}), + DIV({"class": "netInfoCacheText netInfoText", "role": "tabpanel"}, + TABLE({"class": "netInfoCacheTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("Cache")}) + ) + ), + DIV({"class": "netInfoHtmlText netInfoText", "role": "tabpanel"}, + IFRAME({"class": "netInfoHtmlPreview", "role": "document"}) + ) + ), + + headerDataTag: + FOR("param", "$headers", + TR({"role": "listitem"}, + TD({"class": "netInfoParamName", "role": "presentation"}, + TAG("$param|getNameTag", {param: "$param"}) + ), + TD({"class": "netInfoParamValue", "role": "list", "aria-label": "$param.name"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class": "focusRow subFocusRow", "role": "listitem"}, "$line") + ) + ) + ) + ), + + customTab: + A({"class": "netInfo$tabId\\Tab netInfoTab", onclick: "$onClickTab", view: "$tabId", "role": "tab"}, + "$tabTitle" + ), + + customBody: + DIV({"class": "netInfo$tabId\\Text netInfoText", "role": "tabpanel"}), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + nameTag: + SPAN("$param|getParamName"), + + nameWithTooltipTag: + SPAN({title: "$param.name"}, "$param|getParamName"), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getNameTag: function(param) + { + return (this.getParamName(param) == param.name) ? this.nameTag : this.nameWithTooltipTag; + }, + + getParamName: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + name = name.substr(0, limit) + "..."; + return name; + }, + + getParamTitle: function(param) + { + var limit = 25; + var name = param.name; + if (name.length > limit) + return name; + return ""; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + hideParams: function(file) + { + return !file.urlParams || !file.urlParams.length; + }, + + hidePost: function(file) + { + return file.method.toUpperCase() != "POST"; + }, + + hidePut: function(file) + { + return file.method.toUpperCase() != "PUT"; + }, + + hideResponse: function(file) + { + return false; + //return file.category in binaryFileCategories; + }, + + hideCache: function(file) + { + return true; + //xxxHonza: I don't see any reason why not to display the cache also info for images. + return !file.cacheEntry; // || file.category=="image"; + }, + + hideHtml: function(file) + { + return (file.mimeType != "text/html") && (file.mimeType != "application/xhtml+xml"); + }, + + onClickTab: function(event) + { + this.selectTab(event.currentTarget || event.srcElement); + }, + + getParamValueIterator: function(param) + { + // TODO: xxxpedro console2 + return param.value; + + // This value is inserted into CODE element and so, make sure the HTML isn't escaped (1210). + // This is why the second parameter is true. + // The CODE (with style white-space:pre) element preserves whitespaces so they are + // displayed the same, as they come from the server (1194). + // In case of a long header values of post parameters the value must be wrapped (2105). + return wrapText(param.value, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + appendTab: function(netInfoBox, tabId, tabTitle) + { + // Create new tab and body. + var args = {tabId: tabId, tabTitle: tabTitle}; + ///this.customTab.append(args, netInfoBox.getElementsByClassName("netInfoTabs").item(0)); + ///this.customBody.append(args, netInfoBox.getElementsByClassName("netInfoBodies").item(0)); + this.customTab.append(args, $$(".netInfoTabs", netInfoBox)[0]); + this.customBody.append(args, $$(".netInfoBodies", netInfoBox)[0]); + }, + + selectTabByName: function(netInfoBox, tabName) + { + var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab"); + if (tab) + this.selectTab(tab); + }, + + selectTab: function(tab) + { + var view = tab.getAttribute("view"); + + var netInfoBox = getAncestorByClass(tab, "netInfoBody"); + + var selectedTab = netInfoBox.selectedTab; + + if (selectedTab) + { + //netInfoBox.selectedText.removeAttribute("selected"); + removeClass(netInfoBox.selectedText, "netInfoTextSelected"); + + removeClass(selectedTab, "netInfoTabSelected"); + //selectedTab.removeAttribute("selected"); + selectedTab.setAttribute("aria-selected", "false"); + } + + var textBodyName = "netInfo" + view + "Text"; + + selectedTab = netInfoBox.selectedTab = tab; + + netInfoBox.selectedText = $$("."+textBodyName, netInfoBox)[0]; + //netInfoBox.selectedText = netInfoBox.getElementsByClassName(textBodyName).item(0); + + //netInfoBox.selectedText.setAttribute("selected", "true"); + setClass(netInfoBox.selectedText, "netInfoTextSelected"); + + setClass(selectedTab, "netInfoTabSelected"); + selectedTab.setAttribute("selected", "true"); + selectedTab.setAttribute("aria-selected", "true"); + + var file = Firebug.getRepObject(netInfoBox); + + //var context = Firebug.getElementPanel(netInfoBox).context; + var context = Firebug.chrome; + + this.updateInfo(netInfoBox, file, context); + }, + + updateInfo: function(netInfoBox, file, context) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.updateInfo; file", file); + + if (!netInfoBox) + { + if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS) + FBTrace.sysout("net.updateInfo; ERROR netInfo == null " + file.href, file); + return; + } + + var tab = netInfoBox.selectedTab; + + if (hasClass(tab, "netInfoParamsTab")) + { + if (file.urlParams && !netInfoBox.urlParamsPresented) + { + netInfoBox.urlParamsPresented = true; + this.insertHeaderRows(netInfoBox, file.urlParams, "Params"); + } + } + + else if (hasClass(tab, "netInfoHeadersTab")) + { + var headersText = $$(".netInfoHeadersText", netInfoBox)[0]; + //var headersText = netInfoBox.getElementsByClassName("netInfoHeadersText").item(0); + + if (file.responseHeaders && !netInfoBox.responseHeadersPresented) + { + netInfoBox.responseHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.responseHeaders, "ResponseHeaders"); + } + + if (file.requestHeaders && !netInfoBox.requestHeadersPresented) + { + netInfoBox.requestHeadersPresented = true; + NetInfoHeaders.renderHeaders(headersText, file.requestHeaders, "RequestHeaders"); + } + } + + else if (hasClass(tab, "netInfoPostTab")) + { + if (!netInfoBox.postPresented) + { + netInfoBox.postPresented = true; + //var postText = netInfoBox.getElementsByClassName("netInfoPostText").item(0); + var postText = $$(".netInfoPostText", netInfoBox)[0]; + NetInfoPostData.render(context, postText, file); + } + } + + else if (hasClass(tab, "netInfoPutTab")) + { + if (!netInfoBox.putPresented) + { + netInfoBox.putPresented = true; + //var putText = netInfoBox.getElementsByClassName("netInfoPutText").item(0); + var putText = $$(".netInfoPutText", netInfoBox)[0]; + NetInfoPostData.render(context, putText, file); + } + } + + else if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented) + { + ///var responseTextBox = netInfoBox.getElementsByClassName("netInfoResponseText").item(0); + var responseTextBox = $$(".netInfoResponseText", netInfoBox)[0]; + if (file.category == "image") + { + netInfoBox.responsePresented = true; + + var responseImage = netInfoBox.ownerDocument.createElement("img"); + responseImage.src = file.href; + + clearNode(responseTextBox); + responseTextBox.appendChild(responseImage, responseTextBox); + } + else ///if (!(binaryCategoryMap.hasOwnProperty(file.category))) + { + this.setResponseText(file, netInfoBox, responseTextBox, context); + } + } + + else if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented) + { + var responseTextBox = netInfoBox.getElementsByClassName("netInfoCacheText").item(0); + if (file.cacheEntry) { + netInfoBox.cachePresented = true; + this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache"); + } + } + + else if (hasClass(tab, "netInfoHtmlTab") && file.loaded && !netInfoBox.htmlPresented) + { + netInfoBox.htmlPresented = true; + + var text = Utils.getResponseText(file, context); + + ///var iframe = netInfoBox.getElementsByClassName("netInfoHtmlPreview").item(0); + var iframe = $$(".netInfoHtmlPreview", netInfoBox)[0]; + + ///iframe.contentWindow.document.body.innerHTML = text; + + // TODO: xxxpedro net - remove scripts + var reScript = //gi; + + text = text.replace(reScript, ""); + + iframe.contentWindow.document.write(text); + iframe.contentWindow.document.close(); + } + + // Notify listeners about update so, content of custom tabs can be updated. + dispatch(NetInfoBody.fbListeners, "updateTabBody", [netInfoBox, file, context]); + }, + + setResponseText: function(file, netInfoBox, responseTextBox, context) + { + //********************************************** + //********************************************** + //********************************************** + netInfoBox.responsePresented = true; + // line breaks somehow are different in IE + // make this only once in the initialization? we don't have net panels and modules yet. + if (isIE) + responseTextBox.style.whiteSpace = "nowrap"; + + responseTextBox[ + typeof responseTextBox.textContent != "undefined" ? + "textContent" : + "innerText" + ] = file.responseText; + + return; + //********************************************** + //********************************************** + //********************************************** + + // Get response text and make sure it doesn't exceed the max limit. + var text = Utils.getResponseText(file, context); + var limit = Firebug.netDisplayedResponseLimit + 15; + var limitReached = text ? (text.length > limit) : false; + if (limitReached) + text = text.substr(0, limit) + "..."; + + // Insert the response into the UI. + if (text) + insertWrappedText(text, responseTextBox); + else + insertWrappedText("", responseTextBox); + + // Append a message informing the user that the response isn't fully displayed. + if (limitReached) + { + var object = { + text: $STR("net.responseSizeLimitMessage"), + onClickLink: function() { + var panel = context.getPanel("net", true); + panel.openResponseInTab(file); + } + }; + Firebug.NetMonitor.ResponseSizeLimit.append(object, responseTextBox); + } + + netInfoBox.responsePresented = true; + + if (FBTrace.DBG_NET) + FBTrace.sysout("net.setResponseText; response text updated"); + }, + + insertHeaderRows: function(netInfoBox, headers, tableName, rowName) + { + if (!headers.length) + return; + + var headersTable = $$(".netInfo"+tableName+"Table", netInfoBox)[0]; + //var headersTable = netInfoBox.getElementsByClassName("netInfo"+tableName+"Table").item(0); + var tbody = getChildByClass(headersTable, "netInfo" + rowName + "Body"); + if (!tbody) + tbody = headersTable.firstChild; + var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title"); + + this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody); + removeClass(titleRow, "collapsed"); + } +}); + +var NetInfoBody = Firebug.NetMonitor.NetInfoBody; + +// ************************************************************************************************ + +/** + * @domplate Used within the Net panel to display raw source of request and response headers + * as well as pretty-formatted summary of these headers. + */ +Firebug.NetMonitor.NetInfoHeaders = domplate(Firebug.Rep, //new Firebug.Listener(), +{ + tag: + DIV({"class": "netInfoHeadersTable", "role": "tabpanel"}, + DIV({"class": "netInfoHeadersGroup netInfoResponseHeadersTitle"}, + SPAN($STR("ResponseHeaders")), + SPAN({"class": "netHeadersViewSource response collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "ResponseHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoResponseHeadersBody", "role": "list", + "aria-label": $STR("ResponseHeaders")}) + ), + DIV({"class": "netInfoHeadersGroup netInfoRequestHeadersTitle"}, + SPAN($STR("RequestHeaders")), + SPAN({"class": "netHeadersViewSource request collapsed", onclick: "$onViewSource", + _sourceDisplayed: false, _rowName: "RequestHeaders"}, + $STR("net.headers.view source") + ) + ), + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY({"class": "netInfoRequestHeadersBody", "role": "list", + "aria-label": $STR("RequestHeaders")}) + ) + ), + + sourceTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + PRE({"class": "source"}) + ) + ), + + onViewSource: function(event) + { + var target = event.target; + var requestHeaders = (target.rowName == "RequestHeaders"); + + var netInfoBox = getAncestorByClass(target, "netInfoBody"); + var file = netInfoBox.repObject; + + if (target.sourceDisplayed) + { + var headers = requestHeaders ? file.requestHeaders : file.responseHeaders; + this.insertHeaderRows(netInfoBox, headers, target.rowName); + target.innerHTML = $STR("net.headers.view source"); + } + else + { + var source = requestHeaders ? file.requestHeadersText : file.responseHeadersText; + this.insertSource(netInfoBox, source, target.rowName); + target.innerHTML = $STR("net.headers.pretty print"); + } + + target.sourceDisplayed = !target.sourceDisplayed; + + cancelEvent(event); + }, + + insertSource: function(netInfoBox, source, rowName) + { + // This breaks copy to clipboard. + //if (source) + // source = source.replace(/\r\n/gm, "\\r\\n\r\n"); + + ///var tbody = netInfoBox.getElementsByClassName("netInfo" + rowName + "Body").item(0); + var tbody = $$(".netInfo" + rowName + "Body", netInfoBox)[0]; + var node = this.sourceTag.replace({}, tbody); + ///var sourceNode = node.getElementsByClassName("source").item(0); + var sourceNode = $$(".source", node)[0]; + sourceNode.innerHTML = source; + }, + + insertHeaderRows: function(netInfoBox, headers, rowName) + { + var headersTable = $$(".netInfoHeadersTable", netInfoBox)[0]; + var tbody = $$(".netInfo" + rowName + "Body", headersTable)[0]; + + //var headersTable = netInfoBox.getElementsByClassName("netInfoHeadersTable").item(0); + //var tbody = headersTable.getElementsByClassName("netInfo" + rowName + "Body").item(0); + + clearNode(tbody); + + if (!headers.length) + return; + + NetInfoBody.headerDataTag.insertRows({headers: headers}, tbody); + + var titleRow = getChildByClass(headersTable, "netInfo" + rowName + "Title"); + removeClass(titleRow, "collapsed"); + }, + + init: function(parent) + { + var rootNode = this.tag.append({}, parent); + + var netInfoBox = getAncestorByClass(parent, "netInfoBody"); + var file = netInfoBox.repObject; + + var viewSource; + + viewSource = $$(".request", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource request").item(0); + if (file.requestHeadersText) + removeClass(viewSource, "collapsed"); + + viewSource = $$(".response", rootNode)[0]; + //viewSource = rootNode.getElementsByClassName("netHeadersViewSource response").item(0); + if (file.responseHeadersText) + removeClass(viewSource, "collapsed"); + }, + + renderHeaders: function(parent, headers, rowName) + { + if (!parent.firstChild) + this.init(parent); + + this.insertHeaderRows(parent, headers, rowName); + } +}); + +var NetInfoHeaders = Firebug.NetMonitor.NetInfoHeaders; + +// ************************************************************************************************ + +/** + * @domplate Represents posted data within request info (the info, which is visible when + * a request entry is expanded. This template renders content of the Post tab. + */ +Firebug.NetMonitor.NetInfoPostData = domplate(Firebug.Rep, /*new Firebug.Listener(),*/ +{ + // application/x-www-form-urlencoded + paramsTable: + TABLE({"class": "netInfoPostParamsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parameters")}, + TR({"class": "netInfoPostParamsTitle", "role": "presentation"}, + TD({colspan: 3, "role": "presentation"}, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parameters"), + SPAN({"class": "netInfoPostContentType"}, + "application/x-www-form-urlencoded" + ) + ) + ) + ) + ) + ), + + // multipart/form-data + partsTable: + TABLE({"class": "netInfoPostPartsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Parts")}, + TR({"class": "netInfoPostPartsTitle", "role": "presentation"}, + TD({colspan: 2, "role":"presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("net.label.Parts"), + SPAN({"class": "netInfoPostContentType"}, + "multipart/form-data" + ) + ) + ) + ) + ) + ), + + // application/json + jsonTable: + TABLE({"class": "netInfoPostJSONTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + ///TBODY({"role": "list", "aria-label": $STR("jsonviewer.tab.JSON")}, + TBODY({"role": "list", "aria-label": $STR("JSON")}, + TR({"class": "netInfoPostJSONTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + ///$STR("jsonviewer.tab.JSON") + $STR("JSON") + ) + ) + ), + TR( + TD({"class": "netInfoPostJSONBody"}) + ) + ) + ), + + // application/xml + xmlTable: + TABLE({"class": "netInfoPostXMLTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("xmlviewer.tab.XML")}, + TR({"class": "netInfoPostXMLTitle", "role": "presentation"}, + TD({"role": "presentation" }, + DIV({"class": "netInfoPostParams"}, + $STR("xmlviewer.tab.XML") + ) + ) + ), + TR( + TD({"class": "netInfoPostXMLBody"}) + ) + ) + ), + + sourceTable: + TABLE({"class": "netInfoPostSourceTable", cellpadding: 0, cellspacing: 0, "role": "presentation"}, + TBODY({"role": "list", "aria-label": $STR("net.label.Source")}, + TR({"class": "netInfoPostSourceTitle", "role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + DIV({"class": "netInfoPostSource"}, + $STR("net.label.Source") + ) + ) + ) + ) + ), + + sourceBodyTag: + TR({"role": "presentation"}, + TD({colspan: 2, "role": "presentation"}, + FOR("line", "$param|getParamValueIterator", + CODE({"class":"focusRow subFocusRow" , "role": "listitem"},"$line") + ) + ) + ), + + getParamValueIterator: function(param) + { + return NetInfoBody.getParamValueIterator(param); + }, + + render: function(context, parentNode, file) + { + //debugger; + var spy = getAncestorByClass(parentNode, "spyHead"); + var spyObject = spy.repObject; + var data = spyObject.data; + + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + var contentType = file.mimeType; + + ///var text = Utils.getPostText(file, context, true); + ///if (text == undefined) + /// return; + + ///if (Utils.isURLEncodedRequest(file, context)) + // fake Utils.isURLEncodedRequest identification + if (contentType && contentType == "application/x-www-form-urlencoded" || + data && data.indexOf("=") != -1) + { + ///var lines = text.split("\n"); + ///var params = parseURLEncodedText(lines[lines.length-1]); + var params = parseURLEncodedTextArray(data); + if (params) + this.insertParameters(parentNode, params); + } + + ///if (Utils.isMultiPartRequest(file, context)) + ///{ + /// var data = this.parseMultiPartText(file, context); + /// if (data) + /// this.insertParts(parentNode, data); + ///} + + // moved to the top + ///var contentType = Utils.findHeader(file.requestHeaders, "content-type"); + + ///if (Firebug.JSONViewerModel.isJSON(contentType)) + var jsonData = { + responseText: data + }; + + if (Firebug.JSONViewerModel.isJSON(contentType, data)) + ///this.insertJSON(parentNode, file, context); + this.insertJSON(parentNode, jsonData, context); + + ///if (Firebug.XMLViewerModel.isXML(contentType)) + /// this.insertXML(parentNode, file, context); + + ///var postText = Utils.getPostText(file, context); + ///postText = Utils.formatPostText(postText); + var postText = data; + if (postText) + this.insertSource(parentNode, postText); + }, + + insertParameters: function(parentNode, params) + { + if (!params || !params.length) + return; + + var paramTable = this.paramsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostParamsTitle", paramTable)[0]; + //var paramTable = this.paramsTable.append(null, parentNode); + //var row = paramTable.getElementsByClassName("netInfoPostParamsTitle").item(0); + + var tbody = paramTable.getElementsByTagName("tbody")[0]; + + NetInfoBody.headerDataTag.insertRows({headers: params}, row); + }, + + insertParts: function(parentNode, data) + { + if (!data.params || !data.params.length) + return; + + var partsTable = this.partsTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostPartsTitle", paramTable)[0]; + //var partsTable = this.partsTable.append(null, parentNode); + //var row = partsTable.getElementsByClassName("netInfoPostPartsTitle").item(0); + + NetInfoBody.headerDataTag.insertRows({headers: data.params}, row); + }, + + insertJSON: function(parentNode, file, context) + { + ///var text = Utils.getPostText(file, context); + var text = file.responseText; + ///var data = parseJSONString(text, "http://" + file.request.originalURI.host); + var data = parseJSONString(text); + if (!data) + return; + + ///var jsonTable = this.jsonTable.append(null, parentNode); + var jsonTable = this.jsonTable.append({}, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostJSONBody").item(0); + var jsonBody = $$(".netInfoPostJSONBody", jsonTable)[0]; + + if (!this.toggles) + this.toggles = {}; + + Firebug.DOMPanel.DirTable.tag.replace( + {object: data, toggles: this.toggles}, jsonBody); + }, + + insertXML: function(parentNode, file, context) + { + var text = Utils.getPostText(file, context); + + var jsonTable = this.xmlTable.append(null, parentNode); + ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostXMLBody").item(0); + var jsonBody = $$(".netInfoPostXMLBody", jsonTable)[0]; + + Firebug.XMLViewerModel.insertXML(jsonBody, text); + }, + + insertSource: function(parentNode, text) + { + var sourceTable = this.sourceTable.append({object:{}}, parentNode); + var row = $$(".netInfoPostSourceTitle", sourceTable)[0]; + //var sourceTable = this.sourceTable.append(null, parentNode); + //var row = sourceTable.getElementsByClassName("netInfoPostSourceTitle").item(0); + + var param = {value: [text]}; + this.sourceBodyTag.insertRows({param: param}, row); + }, + + parseMultiPartText: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text == undefined) + return null; + + FBTrace.sysout("net.parseMultiPartText; boundary: ", text); + + var boundary = text.match(/\s*boundary=\s*(.*)/)[1]; + + var divider = "\r\n\r\n"; + var bodyStart = text.indexOf(divider); + var body = text.substr(bodyStart + divider.length); + + var postData = {}; + postData.mimeType = "multipart/form-data"; + postData.params = []; + + var parts = body.split("--" + boundary); + for (var i=0; i 1) ? m[1] : "", + value: trim(part[1]) + }); + } + + return postData; + } +}); + +var NetInfoPostData = Firebug.NetMonitor.NetInfoPostData; + +// ************************************************************************************************ + + +// TODO: xxxpedro net i18n +var $STRP = function(a){return a;}; + +Firebug.NetMonitor.NetLimit = domplate(Firebug.Rep, +{ + collapsed: true, + + tableTag: + DIV( + TABLE({width: "100%", cellpadding: 0, cellspacing: 0}, + TBODY() + ) + ), + + limitTag: + TR({"class": "netRow netLimitRow", $collapsed: "$isCollapsed"}, + TD({"class": "netCol netLimitCol", colspan: 6}, + TABLE({cellpadding: 0, cellspacing: 0}, + TBODY( + TR( + TD( + SPAN({"class": "netLimitLabel"}, + $STRP("plural.Limit_Exceeded", [0]) + ) + ), + TD({style: "width:100%"}), + TD( + BUTTON({"class": "netLimitButton", title: "$limitPrefsTitle", + onclick: "$onPreferences"}, + $STR("LimitPrefs") + ) + ), + TD(" ") + ) + ) + ) + ) + ), + + isCollapsed: function() + { + return this.collapsed; + }, + + onPreferences: function(event) + { + openNewTab("about:config"); + }, + + updateCounter: function(row) + { + removeClass(row, "collapsed"); + + // Update info within the limit row. + var limitLabel = row.getElementsByClassName("netLimitLabel").item(0); + limitLabel.firstChild.nodeValue = $STRP("plural.Limit_Exceeded", [row.limitInfo.totalCount]); + }, + + createTable: function(parent, limitInfo) + { + var table = this.tableTag.replace({}, parent); + var row = this.createRow(table.firstChild.firstChild, limitInfo); + return [table, row]; + }, + + createRow: function(parent, limitInfo) + { + var row = this.limitTag.insertRows(limitInfo, parent, this)[0]; + row.limitInfo = limitInfo; + return row; + }, + + // nsIPrefObserver + observe: function(subject, topic, data) + { + // We're observing preferences only. + if (topic != "nsPref:changed") + return; + + if (data.indexOf("net.logLimit") != -1) + this.updateMaxLimit(); + }, + + updateMaxLimit: function() + { + var value = Firebug.getPref(Firebug.prefDomain, "net.logLimit"); + maxQueueRequests = value ? value : maxQueueRequests; + } +}); + +var NetLimit = Firebug.NetMonitor.NetLimit; + +// ************************************************************************************************ + +Firebug.NetMonitor.ResponseSizeLimit = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "netInfoResponseSizeLimit"}, + SPAN("$object.beforeLink"), + A({"class": "objectLink", onclick: "$onClickLink"}, + "$object.linkText" + ), + SPAN("$object.afterLink") + ), + + reLink: /^(.*)(.*)<\/a>(.*$)/, + append: function(obj, parent) + { + var m = obj.text.match(this.reLink); + return this.tag.append({onClickLink: obj.onClickLink, + object: { + beforeLink: m[1], + linkText: m[2], + afterLink: m[3] + }}, parent, this); + } +}); + +// ************************************************************************************************ +// ************************************************************************************************ + +Firebug.NetMonitor.Utils = +{ + findHeader: function(headers, name) + { + if (!headers) + return null; + + name = name.toLowerCase(); + for (var i = 0; i < headers.length; ++i) + { + var headerName = headers[i].name.toLowerCase(); + if (headerName == name) + return headers[i].value; + } + }, + + formatPostText: function(text) + { + if (text instanceof XMLDocument) + return getElementXML(text.documentElement); + else + return text; + }, + + getPostText: function(file, context, noLimit) + { + if (!file.postText) + { + file.postText = readPostTextFromRequest(file.request, context); + + if (!file.postText && context) + file.postText = readPostTextFromPage(file.href, context); + } + + if (!file.postText) + return file.postText; + + var limit = Firebug.netDisplayedPostBodyLimit; + if (file.postText.length > limit && !noLimit) + { + return cropString(file.postText, limit, + "\n\n... " + $STR("net.postDataSizeLimitMessage") + " ...\n\n"); + } + + return file.postText; + }, + + getResponseText: function(file, context) + { + // The response can be also empty string so, check agains "undefined". + return (typeof(file.responseText) != "undefined")? file.responseText : + context.sourceCache.loadText(file.href, file.method, file); + }, + + isURLEncodedRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded") == 0) + return true; + + // The header value doesn't have to be always exactly "application/x-www-form-urlencoded", + // there can be even charset specified. So, use indexOf rather than just "==". + var headerValue = Utils.findHeader(file.requestHeaders, "content-type"); + if (headerValue && headerValue.indexOf("application/x-www-form-urlencoded") == 0) + return true; + + return false; + }, + + isMultiPartRequest: function(file, context) + { + var text = Utils.getPostText(file, context); + if (text && text.toLowerCase().indexOf("content-type: multipart/form-data") == 0) + return true; + return false; + }, + + getMimeType: function(mimeType, uri) + { + if (!mimeType || !(mimeCategoryMap.hasOwnProperty(mimeType))) + { + var ext = getFileExtension(uri); + if (!ext) + return mimeType; + else + { + var extMimeType = mimeExtensionMap[ext.toLowerCase()]; + return extMimeType ? extMimeType : mimeType; + } + } + else + return mimeType; + }, + + getDateFromSeconds: function(s) + { + var d = new Date(); + d.setTime(s*1000); + return d; + }, + + getHttpHeaders: function(request, file) + { + try + { + var http = QI(request, Ci.nsIHttpChannel); + file.status = request.responseStatus; + + // xxxHonza: is there any problem to do this in requestedFile method? + file.method = http.requestMethod; + file.urlParams = parseURLParams(file.href); + file.mimeType = Utils.getMimeType(request.contentType, request.name); + + if (!file.responseHeaders && Firebug.collectHttpHeaders) + { + var requestHeaders = [], responseHeaders = []; + + http.visitRequestHeaders({ + visitHeader: function(name, value) + { + requestHeaders.push({name: name, value: value}); + } + }); + http.visitResponseHeaders({ + visitHeader: function(name, value) + { + responseHeaders.push({name: name, value: value}); + } + }); + + file.requestHeaders = requestHeaders; + file.responseHeaders = responseHeaders; + } + } + catch (exc) + { + // An exception can be throwed e.g. when the request is aborted and + // request.responseStatus is accessed. + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("net.getHttpHeaders FAILS " + file.href, exc); + } + }, + + isXHR: function(request) + { + try + { + var callbacks = request.notificationCallbacks; + var xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null; + if (FBTrace.DBG_NET) + FBTrace.sysout("net.isXHR; " + (xhrRequest != null) + ", " + safeGetName(request)); + + return (xhrRequest != null); + } + catch (exc) + { + } + + return false; + }, + + getFileCategory: function(file) + { + if (file.category) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; current: " + file.category + " for: " + file.href, file); + return file.category; + } + + if (file.isXHR) + { + if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; XHR for: " + file.href, file); + return file.category = "xhr"; + } + + if (!file.mimeType) + { + var ext = getFileExtension(file.href); + if (ext) + file.mimeType = mimeExtensionMap[ext.toLowerCase()]; + } + + /*if (FBTrace.DBG_NET) + FBTrace.sysout("net.getFileCategory; " + mimeCategoryMap[file.mimeType] + + ", mimeType: " + file.mimeType + " for: " + file.href, file);*/ + + if (!file.mimeType) + return ""; + + // Solve cases when charset is also specified, eg "text/html; charset=UTF-8". + var mimeType = file.mimeType; + if (mimeType) + mimeType = mimeType.split(";")[0]; + + return (file.category = mimeCategoryMap[mimeType]); + } +}; + +var Utils = Firebug.NetMonitor.Utils; + +// ************************************************************************************************ + +//Firebug.registerRep(Firebug.NetMonitor.NetRequestTable); +//Firebug.registerActivableModule(Firebug.NetMonitor); +//Firebug.registerPanel(NetPanel); + +Firebug.registerModule(Firebug.NetMonitor); +//Firebug.registerRep(Firebug.NetMonitor.BreakpointRep); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; + +// List of contexts with XHR spy attached. +var contexts = []; + +// ************************************************************************************************ +// Spy Module + +/** + * @module Represents a XHR Spy module. The main purpose of the XHR Spy feature is to monitor + * XHR activity of the current page and create appropriate log into the Console panel. + * This feature can be controlled by an option Show XMLHttpRequests (from within the + * console panel). + * + * The module is responsible for attaching/detaching a HTTP Observers when Firebug is + * activated/deactivated for a site. + */ +Firebug.Spy = extend(Firebug.Module, +/** @lends Firebug.Spy */ +{ + dispatchName: "spy", + + initialize: function() + { + if (Firebug.TraceModule) + Firebug.TraceModule.addListener(this.TraceListener); + + Firebug.Module.initialize.apply(this, arguments); + }, + + shutdown: function() + { + Firebug.Module.shutdown.apply(this, arguments); + + if (Firebug.TraceModule) + Firebug.TraceModule.removeListener(this.TraceListener); + }, + + initContext: function(context) + { + context.spies = []; + + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, context.window); + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.initContext " + contexts.length + " ", context.getName()); + }, + + destroyContext: function(context) + { + // For any spies that are in progress, remove our listeners so that they don't leak + this.detachObserver(context, null); + + if (FBTrace.DBG_SPY && context.spies.length) + FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies (" + + context.spies.length + ") " + context.getName()); + + delete context.spies; + + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.destroyContext " + contexts.length + " ", context.getName()); + }, + + watchWindow: function(context, win) + { + if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled()) + this.attachObserver(context, win); + }, + + unwatchWindow: function(context, win) + { + try + { + // This make sure that the existing context is properly removed from "contexts" array. + this.detachObserver(context, win); + } + catch (ex) + { + // Get exceptions here sometimes, so let's just ignore them + // since the window is going away anyhow + ERROR(ex); + } + }, + + updateOption: function(name, value) + { + // XXXjjb Honza, if Console.isEnabled(context) false, then this can't be called, + // but somehow seems not correct + if (name == "showXMLHttpRequests") + { + var tach = value ? this.attachObserver : this.detachObserver; + for (var i = 0; i < TabWatcher.contexts.length; ++i) + { + var context = TabWatcher.contexts[i]; + iterateWindows(context.window, function(win) + { + tach.apply(this, [context, win]); + }); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Attaching Spy to XHR requests. + + /** + * Returns false if Spy should not be attached to XHRs executed by the specified window. + */ + skipSpy: function(win) + { + if (!win) + return true; + + // Don't attach spy to chrome. + var uri = safeGetWindowLocation(win); + if (uri && (uri.indexOf("about:") == 0 || uri.indexOf("chrome:") == 0)) + return true; + }, + + attachObserver: function(context, win) + { + if (Firebug.Spy.skipSpy(win)) + return; + + for (var i=0; insIHttpChannel. + * Returns null if the request doesn't represent XHR. + */ + getXHR: function(request) + { + // Does also query-interface for nsIHttpChannel. + if (!(request instanceof Ci.nsIHttpChannel)) + return null; + + try + { + var callbacks = request.notificationCallbacks; + return (callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null); + } + catch (exc) + { + if (exc.name == "NS_NOINTERFACE") + { + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.getXHR; Request is not nsIXMLHttpRequest: " + + safeGetRequestName(request)); + } + } + + return null; + } +}); + + + + + +// ************************************************************************************************ + +/* +function getSpyForXHR(request, xhrRequest, context, noCreate) +{ + var spy = null; + + // Iterate all existing spy objects in this context and look for one that is + // already created for this request. + var length = context.spies.length; + for (var i=0; i= 3) + { + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (netInfoBox) + { + netInfoBox.htmlPresented = false; + netInfoBox.responsePresented = false; + } + } + + // If the request is loading update the end time. + if (spy.xhrRequest.readyState == 3) + { + spy.responseTime = spy.endTime - spy.sendTime; + updateTime(spy); + } + + // Request loaded. Get all the info from the request now, just in case the + // XHR would be aborted in the original onReadyStateChange handler. + if (spy.xhrRequest.readyState == 4) + { + // Cumulate response so, multipart response content is properly displayed. + if (SpyHttpActivityObserver.getActivityDistributor()) + spy.responseText += spy.xhrRequest.responseText; + else + { + // xxxHonza: remove from FB 1.6 + if (!spy.responseText) + spy.responseText = spy.xhrRequest.responseText; + } + + // The XHR is loaded now (used also by the activity observer). + spy.loaded = true; + + // Update UI. + updateHttpSpyInfo(spy); + + // Notify Net pane about a request beeing loaded. + // xxxHonza: I don't think this is necessary. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.stopFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); + + // Notify registered listeners about finish of the XHR. + dispatch(Firebug.Spy.fbListeners, "onLoad", [spy.context, spy]); + } + + // Pass the event to the original page handler. + callPageHandler(spy, event, originalHandler); +} + +function onHTTPSpyLoad(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyLoad: " + spy.href, spy); + + // Detach must be done in onLoad (not in onreadystatechange) otherwise + // onAbort would not be handled. + spy.detach(); + + // xxxHonza: Still needed for Fx 3.5 (#502959) + if (!SpyHttpActivityObserver.getActivityDistributor()) + onHTTPSpyReadyStateChange(spy, null); +} + +function onHTTPSpyError(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyError; " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } +} + +function onHTTPSpyAbort(spy) +{ + if (FBTrace.DBG_SPY) + FBTrace.sysout("spy.onHTTPSpyAbort: " + spy.href, spy); + + spy.detach(); + spy.loaded = true; + + if (spy.logRow) + { + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "error"); + } + + spy.statusText = "Aborted"; + updateLogRow(spy); + + // Notify Net pane about a request beeing aborted. + // xxxHonza: the net panel shoud find out this itself. + var netProgress = spy.context.netProgress; + if (netProgress) + netProgress.post(netProgress.abortFile, [spy.request, spy.endTime, spy.postText, spy.responseText]); +} +/**/ + +// ************************************************************************************************ + +/** + * @domplate Represents a template for XHRs logged in the Console panel. The body of the + * log (displayed when expanded) is rendered using {@link Firebug.NetMonitor.NetInfoBody}. + */ + +Firebug.Spy.XHR = domplate(Firebug.Rep, +/** @lends Firebug.Spy.XHR */ + +{ + tag: + DIV({"class": "spyHead", _repObject: "$object"}, + TABLE({"class": "spyHeadTable focusRow outerFocusRow", cellpadding: 0, cellspacing: 0, + "role": "listitem", "aria-expanded": "false"}, + TBODY({"role": "presentation"}, + TR({"class": "spyRow"}, + TD({"class": "spyTitleCol spyCol", onclick: "$onToggleBody"}, + DIV({"class": "spyTitle"}, + "$object|getCaption" + ), + DIV({"class": "spyFullTitle spyTitle"}, + "$object|getFullUri" + ) + ), + TD({"class": "spyCol"}, + DIV({"class": "spyStatus"}, "$object|getStatus") + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyIcon"}) + ), + TD({"class": "spyCol"}, + SPAN({"class": "spyTime"}) + ), + TD({"class": "spyCol"}, + TAG(FirebugReps.SourceLink.tag, {object: "$object.sourceLink"}) + ) + ) + ) + ) + ), + + getCaption: function(spy) + { + return spy.method.toUpperCase() + " " + cropString(spy.getURL(), 100); + }, + + getFullUri: function(spy) + { + return spy.method.toUpperCase() + " " + spy.getURL(); + }, + + getStatus: function(spy) + { + var text = ""; + if (spy.statusCode) + text += spy.statusCode + " "; + + if (spy.statusText) + return text += spy.statusText; + + return text; + }, + + onToggleBody: function(event) + { + var target = event.currentTarget || event.srcElement; + var logRow = getAncestorByClass(target, "logRow-spy"); + + if (isLeftClick(event)) + { + toggleClass(logRow, "opened"); + + var spy = getChildByClass(logRow, "spyHead").repObject; + var spyHeadTable = getAncestorByClass(target, "spyHeadTable"); + + if (hasClass(logRow, "opened")) + { + updateHttpSpyInfo(spy, logRow); + if (spyHeadTable) + spyHeadTable.setAttribute('aria-expanded', 'true'); + } + else + { + //var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + //dispatch(Firebug.NetMonitor.NetInfoBody.fbListeners, "destroyTabBody", [netInfoBox, spy]); + //if (spyHeadTable) + // spyHeadTable.setAttribute('aria-expanded', 'false'); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + copyURL: function(spy) + { + copyToClipboard(spy.getURL()); + }, + + copyParams: function(spy) + { + var text = spy.postText; + if (!text) + return; + + var url = reEncodeURL(spy, text, true); + copyToClipboard(url); + }, + + copyResponse: function(spy) + { + copyToClipboard(spy.responseText); + }, + + openInTab: function(spy) + { + openNewTab(spy.getURL(), spy.postText); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + supportsObject: function(object) + { + // TODO: xxxpedro spy xhr + return false; + + return object instanceof Firebug.Spy.XMLHttpRequestSpy; + }, + + browseObject: function(spy, context) + { + var url = spy.getURL(); + openNewTab(url); + return true; + }, + + getRealObject: function(spy, context) + { + return spy.xhrRequest; + }, + + getContextMenuItems: function(spy) + { + var items = [ + {label: "CopyLocation", command: bindFixed(this.copyURL, this, spy) } + ]; + + if (spy.postText) + { + items.push( + {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, spy) } + ); + } + + items.push( + {label: "CopyResponse", command: bindFixed(this.copyResponse, this, spy) }, + "-", + {label: "OpenInTab", command: bindFixed(this.openInTab, this, spy) } + ); + + return items; + } +}); + +// ************************************************************************************************ + +function updateTime(spy) +{ + var timeBox = spy.logRow.getElementsByClassName("spyTime").item(0); + if (spy.responseTime) + timeBox.textContent = " " + formatTime(spy.responseTime); +} + +function updateLogRow(spy) +{ + updateTime(spy); + + var statusBox = spy.logRow.getElementsByClassName("spyStatus").item(0); + statusBox.textContent = Firebug.Spy.XHR.getStatus(spy); + + removeClass(spy.logRow, "loading"); + setClass(spy.logRow, "loaded"); + + try + { + var errorRange = Math.floor(spy.xhrRequest.status/100); + if (errorRange == 4 || errorRange == 5) + setClass(spy.logRow, "error"); + } + catch (exc) + { + } +} + +var updateHttpSpyInfo = function updateHttpSpyInfo(spy, logRow) +{ + if (!spy.logRow && logRow) + spy.logRow = logRow; + + if (!spy.logRow || !hasClass(spy.logRow, "opened")) + return; + + if (!spy.params) + //spy.params = parseURLParams(spy.href+""); + spy.params = parseURLParams(spy.href+""); + + if (!spy.requestHeaders) + spy.requestHeaders = getRequestHeaders(spy); + + if (!spy.responseHeaders && spy.loaded) + spy.responseHeaders = getResponseHeaders(spy); + + var template = Firebug.NetMonitor.NetInfoBody; + var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody"); + if (!netInfoBox) + { + var head = getChildByClass(spy.logRow, "spyHead"); + netInfoBox = template.tag.append({"file": spy}, head); + dispatch(template.fbListeners, "initTabBody", [netInfoBox, spy]); + template.selectTabByName(netInfoBox, "Response"); + } + else + { + template.updateInfo(netInfoBox, spy, spy.context); + } +}; + + + +// ************************************************************************************************ + +function getRequestHeaders(spy) +{ + var headers = []; + + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitRequestHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + + return headers; +} + +function getResponseHeaders(spy) +{ + var headers = []; + + try + { + var channel = spy.xhrRequest.channel; + if (channel instanceof Ci.nsIHttpChannel) + { + channel.visitResponseHeaders({ + visitHeader: function(name, value) + { + headers.push({name: name, value: value}); + } + }); + } + } + catch (exc) + { + if (FBTrace.DBG_SPY || FBTrace.DBG_ERRORS) + FBTrace.sysout("spy.getResponseHeaders; EXCEPTION " + + safeGetRequestName(spy.request), exc); + } + + return headers; +} + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.Spy); +//Firebug.registerRep(Firebug.Spy.XHR); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ + +// List of JSON content types. +var contentTypes = +{ + "text/plain": 1, + "text/javascript": 1, + "text/x-javascript": 1, + "text/json": 1, + "text/x-json": 1, + "application/json": 1, + "application/x-json": 1, + "application/javascript": 1, + "application/x-javascript": 1, + "application/json-rpc": 1 +}; + +// ************************************************************************************************ +// Model implementation + +Firebug.JSONViewerModel = extend(Firebug.Module, +{ + dispatchName: "jsonViewer", + initialize: function() + { + Firebug.NetMonitor.NetInfoBody.addListener(this); + + // Used by Firebug.DOMPanel.DirTable domplate. + this.toggles = {}; + }, + + shutdown: function() + { + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody", infoBox); + + // Let listeners to parse the JSON. + dispatch(this.fbListeners, "onParseJSON", [file]); + + // The JSON is still no there, try to parse most common cases. + if (!file.jsonObject) + { + ///if (this.isJSON(safeGetContentType(file.request), file.responseText)) + if (this.isJSON(file.mimeType, file.responseText)) + file.jsonObject = this.parseJSON(file); + } + + // The jsonObject is created so, the JSON tab can be displayed. + if (file.jsonObject && hasProperties(file.jsonObject)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "JSON", + ///$STR("jsonviewer.tab.JSON")); + $STR("JSON")); + + if (FBTrace.DBG_JSONVIEWER) + FBTrace.sysout("jsonviewer.initTabBody; JSON object available " + + (typeof(file.jsonObject) != "undefined"), file.jsonObject); + } + }, + + isJSON: function(contentType, data) + { + // Workaround for JSON responses without proper content type + // Let's consider all responses starting with "{" as JSON. In the worst + // case there will be an exception when parsing. This means that no-JSON + // responses (and post data) (with "{") can be parsed unnecessarily, + // which represents a little overhead, but this happens only if the request + // is actually expanded by the user in the UI (Net & Console panels). + + ///var responseText = data ? trimLeft(data) : null; + ///if (responseText && responseText.indexOf("{") == 0) + /// return true; + var responseText = data ? trim(data) : null; + if (responseText && responseText.indexOf("{") == 0) + return true; + + if (!contentType) + return false; + + contentType = contentType.split(";")[0]; + contentType = trim(contentType); + return contentTypes[contentType]; + }, + + // Update listener for TabView + updateTabBody: function(infoBox, file, context) + { + var tab = infoBox.selectedTab; + ///var tabBody = infoBox.getElementsByClassName("netInfoJSONText").item(0); + var tabBody = $$(".netInfoJSONText", infoBox)[0]; + if (!hasClass(tab, "netInfoJSONTab") || tabBody.updated) + return; + + tabBody.updated = true; + + if (file.jsonObject) { + Firebug.DOMPanel.DirTable.tag.replace( + {object: file.jsonObject, toggles: this.toggles}, tabBody); + } + }, + + parseJSON: function(file) + { + var jsonString = new String(file.responseText); + ///return parseJSONString(jsonString, "http://" + file.request.originalURI.host); + return parseJSONString(jsonString); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.JSONViewerModel); + +// ************************************************************************************************ +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +// List of XML related content types. +var xmlContentTypes = +[ + "text/xml", + "application/xml", + "application/xhtml+xml", + "application/rss+xml", + "application/atom+xml",, + "application/vnd.mozilla.maybe.feed", + "application/rdf+xml", + "application/vnd.mozilla.xul+xml" +]; + +// ************************************************************************************************ +// Model implementation + +/** + * @module Implements viewer for XML based network responses. In order to create a new + * tab wihin network request detail, a listener is registered into + * Firebug.NetMonitor.NetInfoBody object. + */ +Firebug.XMLViewerModel = extend(Firebug.Module, +{ + dispatchName: "xmlViewer", + + initialize: function() + { + ///Firebug.ActivableModule.initialize.apply(this, arguments); + Firebug.Module.initialize.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.addListener(this); + }, + + shutdown: function() + { + ///Firebug.ActivableModule.shutdown.apply(this, arguments); + Firebug.Module.shutdown.apply(this, arguments); + Firebug.NetMonitor.NetInfoBody.removeListener(this); + }, + + /** + * Check response's content-type and if it's a XML, create a new tab with XML preview. + */ + initTabBody: function(infoBox, file) + { + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody", infoBox); + + // If the response is XML let's display a pretty preview. + ///if (this.isXML(safeGetContentType(file.request))) + if (this.isXML(file.mimeType, file.responseText)) + { + Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML", + ///$STR("xmlviewer.tab.XML")); + $STR("XML")); + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.initTabBody; XML response available"); + } + }, + + isXML: function(contentType) + { + if (!contentType) + return false; + + // Look if the response is XML based. + for (var i=0; i\s*/, ""); + + var div = parentNode.ownerDocument.createElement("div"); + div.innerHTML = xmlText; + + var root = div.getElementsByTagName("*")[0]; + + /*** + var parser = CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser"); + var doc = parser.parseFromString(text, "text/xml"); + var root = doc.documentElement; + + // Error handling + var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml"; + if (root.namespaceURI == nsURI && root.nodeName == "parsererror") + { + this.ParseError.tag.replace({error: { + message: root.firstChild.nodeValue, + source: root.lastChild.textContent + }}, parentNode); + return; + } + /**/ + + if (FBTrace.DBG_XMLVIEWER) + FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc); + + // Override getHidden in these templates. The parsed XML documen is + // hidden, but we want to display it using 'visible' styling. + /* + var templates = [ + Firebug.HTMLPanel.CompleteElement, + Firebug.HTMLPanel.Element, + Firebug.HTMLPanel.TextElement, + Firebug.HTMLPanel.EmptyElement, + Firebug.HTMLPanel.XEmptyElement, + ]; + + var originals = []; + for (var i=0; iFirebug.XMLViewerModel. + */ +Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "xmlInfoError"}, + DIV({"class": "xmlInfoErrorMsg"}, "$error.message"), + PRE({"class": "xmlInfoErrorSource"}, "$error|getSource") + ), + + getSource: function(error) + { + var parts = error.source.split("\n"); + if (parts.length != 2) + return error.source; + + var limit = 50; + var column = parts[1].length; + if (column >= limit) { + parts[0] = "..." + parts[0].substr(column - limit); + parts[1] = "..." + parts[1].substr(column - limit); + } + + if (parts[0].length > 80) + parts[0] = parts[0].substr(0, 80) + "..."; + + return parts.join("\n"); + } +}); + +// ************************************************************************************************ +// Registration + +Firebug.registerModule(Firebug.XMLViewerModel); + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var ElementCache = Firebug.Lite.Cache.Element; +var cacheID = Firebug.Lite.Cache.ID; + +var ignoreHTMLProps = +{ + // ignores the attributes injected by Sizzle, otherwise it will + // be visible on IE (when enumerating element.attributes) + sizcache: 1, + sizset: 1 +}; + +// ignores also the cache property injected by firebug +ignoreHTMLProps[cacheID] = 1; + + +// ************************************************************************************************ +// HTML Module + +Firebug.HTML = extend(Firebug.Module, +{ + appendTreeNode: function(nodeArray, html) + { + var reTrim = /^\s+|\s+$/g; + + if (!nodeArray.length) nodeArray = [nodeArray]; + + for (var n=0, node; node=nodeArray[n]; n++) + { + if (node.nodeType == 1) + { + if (Firebug.ignoreFirebugElements && node.firebugIgnore) continue; + + var uid = ElementCache(node); + var child = node.childNodes; + var childLength = child.length; + + var nodeName = node.nodeName.toLowerCase(); + + var nodeVisible = isVisible(node); + + var hasSingleTextChild = childLength == 1 && node.firstChild.nodeType == 3 && + nodeName != "script" && nodeName != "style"; + + var nodeControl = !hasSingleTextChild && childLength > 0 ? + ('
      ') : ''; + + var isIE = false; + + if(isIE && nodeControl) + html.push(nodeControl); + + if (typeof uid != 'undefined') + html.push( + '
      ', + !isIE && nodeControl ? nodeControl: "", + '<', nodeName, '' + ); + else + html.push( + '
      <', + nodeName, '' + ); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || Firebug.ignoreFirebugElements && + ignoreHTMLProps.hasOwnProperty(attr.nodeName)) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? formatStyles(node.style.cssText) : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + /* + // source code nodes + if (nodeName == 'script' || nodeName == 'style') + { + + if(document.all){ + var src = node.innerHTML+'\n'; + + }else { + var src = '\n'+node.innerHTML+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + '
      '; + } + + html.push('>
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ', + '
      </', + nodeName, + '>
      ', + '
      ' + ); + + + }/**/ + + // Just a single text node child + if (hasSingleTextChild) + { + var value = child[0].nodeValue.replace(reTrim, ''); + if(value) + { + html.push( + '>', + escapeHTML(value), + '</', + nodeName, + '>' + ); + } + else + html.push('/>'); // blank text, print as childless node + + } + else if (childLength > 0) + { + html.push('>'); + } + else + html.push('/>'); + + } + else if (node.nodeType == 3) + { + if ( node.parentNode && ( node.parentNode.nodeName.toLowerCase() == "script" || + node.parentNode.nodeName.toLowerCase() == "style" ) ) + { + var value = node.nodeValue.replace(reTrim, ''); + + if(isIE){ + var src = value+'\n'; + + }else { + var src = '\n'+value+'\n'; + } + + var match = src.match(/\n/g); + var num = match ? match.length : 0; + var s = [], sl = 0; + + for(var c=1; c' + c + ''; + } + + html.push('
      ', + s.join(''), + '
      ',
      +                            escapeHTML(src),
      +                            '
      ' + ); + + } + else + { + var value = node.nodeValue.replace(reTrim, ''); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + } + } + }, + + appendTreeChildren: function(treeNode) + { + var doc = Firebug.chrome.document; + var uid = treeNode.id; + var parentNode = ElementCache.get(uid); + + if (parentNode.childNodes.length == 0) return; + + var treeNext = treeNode.nextSibling; + var treeParent = treeNode.parentNode; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl nodeMaximized'; + + var html = []; + var children = doc.createElement("div"); + children.className = "nodeChildren"; + this.appendTreeNode(parentNode.childNodes, html); + children.innerHTML = html.join(""); + + treeParent.insertBefore(children, treeNext); + + var closeElement = doc.createElement("div"); + closeElement.className = "objectBox-element"; + closeElement.innerHTML = '</' + + parentNode.nodeName.toLowerCase() + '>' + + treeParent.insertBefore(closeElement, treeNext); + + }, + + removeTreeChildren: function(treeNode) + { + var children = treeNode.nextSibling; + var closeTag = children.nextSibling; + + var isIE = false; + var control = isIE ? treeNode.previousSibling : treeNode.firstChild; + control.className = 'nodeControl'; + + children.parentNode.removeChild(children); + closeTag.parentNode.removeChild(closeTag); + }, + + isTreeNodeVisible: function(id) + { + return $(id); + }, + + select: function(el) + { + var id = el && ElementCache(el); + if (id) + this.selectTreeNode(id); + }, + + selectTreeNode: function(id) + { + id = ""+id; + var node, stack = []; + while(id && !this.isTreeNodeVisible(id)) + { + stack.push(id); + + var node = ElementCache.get(id).parentNode; + + if (node) + id = ElementCache(node); + else + break; + } + + stack.push(id); + + while(stack.length > 0) + { + id = stack.pop(); + node = $(id); + + if (stack.length > 0 && ElementCache.get(id).childNodes.length > 0) + this.appendTreeChildren(node); + } + + selectElement(node); + + // TODO: xxxpedro + if (fbPanel1) + fbPanel1.scrollTop = Math.round(node.offsetTop - fbPanel1.clientHeight/2); + } + +}); + +Firebug.registerModule(Firebug.HTML); + +// ************************************************************************************************ +// HTML Panel + +function HTMLPanel(){}; + +HTMLPanel.prototype = extend(Firebug.Panel, +{ + name: "HTML", + title: "HTML", + + options: { + hasSidePanel: true, + //hasToolButtons: true, + isPreRendered: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "4px 3px 1px 15px"; + this.panelNode.style.minWidth = "500px"; + + if (Env.Options.enablePersistent || Firebug.chrome.type != "popup") + this.createUI(); + + if(!this.sidePanelBar.selectedPanel) + { + this.sidePanelBar.selectPanel("css"); + } + }, + + destroy: function() + { + selectedElement = null + fbPanel1 = null; + + selectedSidePanelTS = null; + selectedSidePanelTimer = null; + + Firebug.Panel.destroy.apply(this, arguments); + }, + + createUI: function() + { + var rootNode = Firebug.browser.document.documentElement; + var html = []; + Firebug.HTML.appendTreeNode(rootNode, html); + + this.panelNode.innerHTML = html.join(""); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + addEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = $("fbPanel1"); + + if(!selectedElement) + { + Firebug.HTML.selectTreeNode(ElementCache(Firebug.browser.document.body)); + } + + // TODO: xxxpedro + addEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + addEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + addEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + }, + + shutdown: function() + { + // TODO: xxxpedro + removeEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove); + removeEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove); + removeEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove); + + removeEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick); + + fbPanel1 = null; + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + reattach: function() + { + // TODO: panel reattach + if(FirebugChrome.selectedHTMLElementId) + Firebug.HTML.selectTreeNode(FirebugChrome.selectedHTMLElementId); + }, + + updateSelection: function(object) + { + var id = ElementCache(object); + + if (id) + { + Firebug.HTML.selectTreeNode(id); + } + } +}); + +Firebug.registerPanel(HTMLPanel); + +// ************************************************************************************************ + +var formatStyles = function(styles) +{ + return isIE ? + // IE return CSS property names in upper case, so we need to convert them + styles.replace(/([^\s]+)\s*:/g, function(m,g){return g.toLowerCase()+":"}) : + // other browsers are just fine + styles; +}; + +// ************************************************************************************************ + +var selectedElement = null +var fbPanel1 = null; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +var selectedSidePanelTS, selectedSidePanelTimer; + +var selectElement= function selectElement(e) +{ + if (e != selectedElement) + { + if (selectedElement) + selectedElement.className = "objectBox-element"; + + e.className = e.className + " selectedElement"; + + if (FBL.isFirefox) + e.style.MozBorderRadius = "2px"; + + else if (FBL.isSafari) + e.style.WebkitBorderRadius = "2px"; + + selectedElement = e; + + FirebugChrome.selectedHTMLElementId = e.id; + + var target = ElementCache.get(e.id); + var selectedSidePanel = Firebug.chrome.getPanel("HTML").sidePanelBar.selectedPanel; + + var stack = FirebugChrome.htmlSelectionStack; + + stack.unshift(target); + + if (stack.length > 2) + stack.pop(); + + var lazySelect = function() + { + selectedSidePanelTS = new Date().getTime(); + + selectedSidePanel.select(target, true); + }; + + if (selectedSidePanelTimer) + { + clearTimeout(selectedSidePanelTimer); + selectedSidePanelTimer = null; + } + + if (new Date().getTime() - selectedSidePanelTS > 100) + setTimeout(lazySelect, 0) + else + selectedSidePanelTimer = setTimeout(lazySelect, 150); + } +} + + +// ************************************************************************************************ +// *** TODO: REFACTOR ************************************************************************** +// ************************************************************************************************ +Firebug.HTML.onTreeClick = function (e) +{ + e = e || event; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + + if (targ.className.indexOf('nodeControl') != -1 || targ.className == 'nodeTag') + { + var isIE = false; + + if(targ.className == 'nodeTag') + { + var control = isIE ? (targ.parentNode.previousSibling || targ) : + (targ.parentNode.previousSibling || targ); + + selectElement(targ.parentNode.parentNode); + + if (control.className.indexOf('nodeControl') == -1) + return; + + } else + control = targ; + + FBL.cancelEvent(e); + + var treeNode = isIE ? control.nextSibling : control.parentNode; + + //FBL.Firebug.Console.log(treeNode); + + if (control.className.indexOf(' nodeMaximized') != -1) { + FBL.Firebug.HTML.removeTreeChildren(treeNode); + } else { + FBL.Firebug.HTML.appendTreeChildren(treeNode); + } + } + else if (targ.className == 'nodeValue' || targ.className == 'nodeName') + { + /* + var input = FBL.Firebug.chrome.document.getElementById('treeInput'); + + input.style.display = "block"; + input.style.left = targ.offsetLeft + 'px'; + input.style.top = FBL.topHeight + targ.offsetTop - FBL.fbPanel1.scrollTop + 'px'; + input.style.width = targ.offsetWidth + 6 + 'px'; + input.value = targ.textContent || targ.innerText; + input.focus(); + /**/ + } +} + +function onListMouseOut(e) +{ + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + if (hasClass(targ, "fbPanel")) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + } +}; + +var hoverElement = null; +var hoverElementTS = 0; + +Firebug.HTML.onListMouseMove = function onListMouseMove(e) +{ + try + { + e = e || event || window; + var targ; + + if (e.target) targ = e.target; + else if (e.srcElement) targ = e.srcElement; + if (targ.nodeType == 3) // defeat Safari bug + targ = targ.parentNode; + + var found = false; + while (targ && !found) { + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) + targ = targ.parentNode; + else + found = true; + } + + if (!targ) + { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + /* + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + /**/ + + if (typeof targ.attributes[cacheID] == 'undefined') return; + + var uid = targ.attributes[cacheID]; + if (!uid) return; + + var el = ElementCache.get(uid.value); + + var nodeName = el.nodeName.toLowerCase(); + + if (FBL.isIE && " meta title script link ".indexOf(" "+nodeName+" ") != -1) + return; + + if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) return; + + if (el.id == "FirebugUI" || " html head body br script link iframe ".indexOf(" "+nodeName+" ") != -1) { + FBL.Firebug.Inspector.hideBoxModel(); + hoverElement = null; + return; + } + + if ((new Date().getTime() - hoverElementTS > 40) && hoverElement != el) { + hoverElementTS = new Date().getTime(); + hoverElement = el; + FBL.Firebug.Inspector.drawBoxModel(el); + } + } + catch(E) + { + } +} + + +// ************************************************************************************************ + +Firebug.Reps = { + + appendText: function(object, html) + { + html.push(escapeHTML(objectToString(object))); + }, + + appendNull: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendString: function(object, html) + { + html.push('"', escapeHTML(objectToString(object)), + '"'); + }, + + appendInteger: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFloat: function(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + }, + + appendFunction: function(object, html) + { + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m && m[1] ? m[1] : "function"; + html.push('', escapeHTML(name), '()'); + }, + + appendObject: function(object, html) + { + /* + var rep = Firebug.getRep(object); + var outputs = []; + + rep.tag.tag.compile(); + + var str = rep.tag.renderHTML({object: object}, outputs); + html.push(str); + /**/ + + try + { + if (object == undefined) + this.appendNull("undefined", html); + else if (object == null) + this.appendNull("null", html); + else if (typeof object == "string") + this.appendString(object, html); + else if (typeof object == "number") + this.appendInteger(object, html); + else if (typeof object == "boolean") + this.appendInteger(object, html); + else if (typeof object == "function") + this.appendFunction(object, html); + else if (object.nodeType == 1) + this.appendSelector(object, html); + else if (typeof object == "object") + { + if (typeof object.length != "undefined") + this.appendArray(object, html); + else + this.appendObjectFormatted(object, html); + } + else + this.appendText(object, html); + } + catch (exc) + { + } + /**/ + }, + + appendObjectFormatted: function(object, html) + { + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push('', m ? m[1] : text, '') + }, + + appendSelector: function(object, html) + { + var uid = ElementCache(object); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push(''); + + html.push('', escapeHTML(object.nodeName.toLowerCase()), ''); + if (object.id) + html.push('#', escapeHTML(object.id), ''); + if (object.className) + html.push('.', escapeHTML(object.className), ''); + + html.push(''); + }, + + appendNode: function(node, html) + { + if (node.nodeType == 1) + { + var uid = ElementCache(node); + var uidString = uid ? [cacheID, '="', uid, '"'].join("") : ""; + + html.push( + '
      ', + '', + '<', node.nodeName.toLowerCase(), ''); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified || attr.nodeName == cacheID) + continue; + + var name = attr.nodeName.toLowerCase(); + var value = name == "style" ? node.style.cssText : attr.nodeValue; + + html.push(' ', name, + '="', escapeHTML(value), + '"') + } + + if (node.firstChild) + { + html.push('>
      '); + + for (var child = node.firstChild; child; child = child.nextSibling) + this.appendNode(child, html); + + html.push('
      </', + node.nodeName.toLowerCase(), '>
      '); + } + else + html.push('/>'); + } + else if (node.nodeType == 3) + { + var value = trim(node.nodeValue); + if (value) + html.push('
      ', escapeHTML(value),'
      '); + } + }, + + appendArray: function(object, html) + { + html.push('[ '); + + for (var i = 0, l = object.length, obj; i < l; ++i) + { + this.appendObject(object[i], html); + + if (i < l-1) + html.push(', '); + } + + html.push(' ]'); + } + +}; + + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +/* + +Hack: +Firebug.chrome.currentPanel = Firebug.chrome.selectedPanel; +Firebug.showInfoTips = true; +Firebug.InfoTip.initializeBrowser(Firebug.chrome); + +/**/ + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// Constants + +var maxWidth = 100, maxHeight = 80; +var infoTipMargin = 10; +var infoTipWindowPadding = 25; + +// ************************************************************************************************ + +Firebug.InfoTip = extend(Firebug.Module, +{ + dispatchName: "infoTip", + tags: domplate( + { + infoTipTag: DIV({"class": "infoTip"}), + + colorTag: + DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, " "), + + imgTag: + DIV({"class": "infoTipImageBox infoTipLoading"}, + IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat", + onload: "$onLoadImage"}), + IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}), + DIV({"class": "infoTipCaption"}) + ), + + onLoadImage: function(event) + { + var img = event.currentTarget || event.srcElement; + ///var bgImg = img.nextSibling; + ///if (!bgImg) + /// return; // Sometimes gets called after element is dead + + ///var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + /// TODO: xxxpedro infoTip hack + var caption = getElementByClass(innerBox, "infoTipCaption"); + var bgImg = getElementByClass(innerBox, "infoTipBgImage"); + if (!bgImg) + return; // Sometimes gets called after element is dead + + // TODO: xxxpedro infoTip IE and timing issue + // TODO: use offline document to avoid flickering + if (isIE) + removeClass(innerBox, "infoTipLoading"); + + var updateInfoTip = function(){ + + var w = img.naturalWidth || img.width || 10, + h = img.naturalHeight || img.height || 10; + + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + //caption.innerHTML = $STRF("Dimensions", [w, h]); + caption.innerHTML = $STRF(w + " x " + h); + + + }; + + if (isIE) + setTimeout(updateInfoTip, 0); + else + { + updateInfoTip(); + removeClass(innerBox, "infoTipLoading"); + } + + /// + } + + /* + /// onLoadImage original + onLoadImage: function(event) + { + var img = event.currentTarget; + var bgImg = img.nextSibling; + if (!bgImg) + return; // Sometimes gets called after element is dead + + var caption = bgImg.nextSibling; + var innerBox = img.parentNode; + + var w = img.naturalWidth, h = img.naturalHeight; + var repeat = img.getAttribute("repeat"); + + if (repeat == "repeat-x" || (w == 1 && h > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-x"; + bgImg.style.width = maxWidth + "px"; + if (h > maxHeight) + bgImg.style.height = maxHeight + "px"; + else + bgImg.style.height = h + "px"; + } + else if (repeat == "repeat-y" || (h == 1 && w > 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat-y"; + bgImg.style.height = maxHeight + "px"; + if (w > maxWidth) + bgImg.style.width = maxWidth + "px"; + else + bgImg.style.width = w + "px"; + } + else if (repeat == "repeat" || (w == 1 && h == 1)) + { + collapse(img, true); + collapse(bgImg, false); + bgImg.style.background = "url(" + img.src + ") repeat"; + bgImg.style.width = maxWidth + "px"; + bgImg.style.height = maxHeight + "px"; + } + else + { + if (w > maxWidth || h > maxHeight) + { + if (w > h) + { + img.style.width = maxWidth + "px"; + img.style.height = Math.round((h / w) * maxWidth) + "px"; + } + else + { + img.style.width = Math.round((w / h) * maxHeight) + "px"; + img.style.height = maxHeight + "px"; + } + } + } + + caption.innerHTML = $STRF("Dimensions", [w, h]); + + removeClass(innerBox, "infoTipLoading"); + } + /**/ + + }), + + initializeBrowser: function(browser) + { + browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser); + browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser); + + ///var doc = browser.contentDocument; + var doc = browser.document; + if (!doc) + return; + + ///doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true); + addEvent(doc, "mouseover", browser.onInfoTipMouseMove); + addEvent(doc, "mouseout", browser.onInfoTipMouseOut); + addEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc)); + }, + + uninitializeBrowser: function(browser) + { + if (browser.infoTip) + { + ///var doc = browser.contentDocument; + var doc = browser.document; + ///doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true); + ///doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true); + ///doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true); + removeEvent(doc, "mouseover", browser.onInfoTipMouseMove); + removeEvent(doc, "mouseout", browser.onInfoTipMouseOut); + removeEvent(doc, "mousemove", browser.onInfoTipMouseMove); + + browser.infoTip.parentNode.removeChild(browser.infoTip); + delete browser.infoTip; + delete browser.onInfoTipMouseMove; + } + }, + + showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset) + { + if (!Firebug.showInfoTips) + return; + + var scrollParent = getOverflowParent(target); + var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0); + + if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset)) + { + var htmlElt = infoTip.ownerDocument.documentElement; + var panelWidth = htmlElt.clientWidth; + var panelHeight = htmlElt.clientHeight; + + if (x+infoTip.offsetWidth+infoTipMargin > panelWidth) + { + infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px"; + infoTip.style.right = "auto"; + } + else + { + infoTip.style.left = (x+infoTipMargin) + "px"; + infoTip.style.right = "auto"; + } + + if (y+infoTip.offsetHeight+infoTipMargin > panelHeight) + { + infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px"; + infoTip.style.bottom = "auto"; + } + else + { + infoTip.style.top = (y+infoTipMargin) + "px"; + infoTip.style.bottom = "auto"; + } + + if (FBTrace.DBG_INFOTIP) + FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top + + ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom + + ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight + + ", offsetWidth: " + infoTip.offsetWidth + + ", x: " + x + ", panelWidth: " + panelWidth + + ", y: " + y + ", panelHeight: " + panelHeight); + + infoTip.setAttribute("active", "true"); + } + else + this.hideInfoTip(infoTip); + }, + + hideInfoTip: function(infoTip) + { + if (infoTip) + infoTip.removeAttribute("active"); + }, + + onMouseOut: function(event, browser) + { + if (!event.relatedTarget) + this.hideInfoTip(browser.infoTip); + }, + + onMouseMove: function(event, browser) + { + // Ignore if the mouse is moving over the existing info tip. + if (getAncestorByClass(event.target, "infoTip")) + return; + + if (browser.currentPanel) + { + var x = event.clientX, y = event.clientY, target = event.target || event.srcElement; + this.showInfoTip(browser.infoTip, browser.currentPanel, target, x, y, event.rangeParent, event.rangeOffset); + } + else + this.hideInfoTip(browser.infoTip); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + populateColorInfoTip: function(infoTip, color) + { + this.tags.colorTag.replace({rgbValue: color}, infoTip); + return true; + }, + + populateImageInfoTip: function(infoTip, url, repeat) + { + if (!repeat) + repeat = "no-repeat"; + + this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip); + + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Module + + disable: function() + { + // XXXjoe For each browser, call uninitializeBrowser + }, + + showPanel: function(browser, panel) + { + if (panel) + { + var infoTip = panel.panelBrowser.infoTip; + if (!infoTip) + infoTip = this.initializeBrowser(panel.panelBrowser); + this.hideInfoTip(infoTip); + } + + }, + + showSidePanel: function(browser, panel) + { + this.showPanel(browser, panel); + } +}); + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.InfoTip); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +// move to FBL +(function() { + +// ************************************************************************************************ +// XPath + +/** + * Gets an XPath for an element which describes its hierarchical location. + */ +this.getElementXPath = function(element) +{ + if (element && element.id) + return '//*[@id="' + element.id + '"]'; + else + return this.getElementTreeXPath(element); +}; + +this.getElementTreeXPath = function(element) +{ + var paths = []; + + for (; element && element.nodeType == 1; element = element.parentNode) + { + var index = 0; + for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) + { + if (sibling.nodeName == element.nodeName) + ++index; + } + + var tagName = element.nodeName.toLowerCase(); + var pathIndex = (index ? "[" + (index+1) + "]" : ""); + paths.splice(0, 0, tagName + pathIndex); + } + + return paths.length ? "/" + paths.join("/") : null; +}; + +this.getElementsByXPath = function(doc, xpath) +{ + var nodes = []; + + try { + var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + for (var item = result.iterateNext(); item; item = result.iterateNext()) + nodes.push(item); + } + catch (exc) + { + // Invalid xpath expressions make their way here sometimes. If that happens, + // we still want to return an empty set without an exception. + } + + return nodes; +}; + +this.getRuleMatchingElements = function(rule, doc) +{ + var css = rule.selectorText; + var xpath = this.cssToXPath(css); + return this.getElementsByXPath(doc, xpath); +}; + + +}).call(FBL); + + + + +FBL.ns(function() { with (FBL) { + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + +var toCamelCase = function toCamelCase(s) +{ + return s.replace(reSelectorCase, toCamelCaseReplaceFn); +}; + +var toSelectorCase = function toSelectorCase(s) +{ + return s.replace(reCamelCase, "-$1").toLowerCase(); + +}; + +var reCamelCase = /([A-Z])/g; +var reSelectorCase = /\-(.)/g; +var toCamelCaseReplaceFn = function toCamelCaseReplaceFn(m,g) +{ + return g.toUpperCase(); +}; + + + + + +// ************************************************************************************************ + +var ElementCache = Firebug.Lite.Cache.Element; +var StyleSheetCache = Firebug.Lite.Cache.StyleSheet; + +var globalCSSRuleIndex; + +var externalStyleSheetURLs = []; +var externalStyleSheetWarning = domplate(Firebug.Rep, +{ + tag: + DIV({"class": "warning focusRow", style: "font-weight:normal;", role: 'listitem'}, + SPAN("$object|STR"), + A({"href": "$href", target:"_blank"}, "$link|STR") + ) +}); + + +var processAllStyleSheetsTimeout = null; +var loadExternalStylesheet = function(doc, styleSheetIterator, styleSheet) +{ + var url = styleSheet.href; + styleSheet.firebugIgnore = true; + + var source = Firebug.Lite.Proxy.load(url); + + // TODO: check for null and error responses + + + // remove comments + //var reMultiComment = /(\/\*([^\*]|\*(?!\/))*\*\/)/g; + //source = source.replace(reMultiComment, ""); + + // convert relative addresses to absolute ones + source = source.replace(/url\(([^\)]+)\)/g, function(a,name){ + + var hasDomain = /\w+:\/\/./.test(name); + + if (!hasDomain) + { + name = name.replace(/^(["'])(.+)\1$/, "$2"); + var first = name.charAt(0); + + // relative path, based on root + if (first == "/") + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLRoot + var m = /^([^:]+:\/{1,3}[^\/]+)/.exec(url); + + return m ? + "url(" + m[1] + name + ")" : + "url(" + name + ")"; + } + // relative path, based on current location + else + { + // TODO: xxxpedro move to lib or Firebug.Lite.something + // getURLPath + var path = url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g, ""); + + path = path + name; + + var reBack = /[^\/]+\/\.\.\//; + while(reBack.test(path)) + { + path = path.replace(reBack, ""); + } + + //console.log("url(" + path + ")"); + + return "url(" + path + ")"; + } + } + + // if it is an absolute path, there is nothing to do + return a; + }); + + var oldStyle = styleSheet.ownerNode; + + if (!oldStyle) return; + + if (!oldStyle.parentNode) return; + + var style = createGlobalElement("style"); + style.setAttribute("charset","utf-8"); + style.setAttribute("type", "text/css"); + style.innerHTML = source; + + //debugger; + oldStyle.parentNode.insertBefore(style, oldStyle.nextSibling); + oldStyle.parentNode.removeChild(oldStyle); + + + //doc.getElementsByTagName("head")[0].appendChild(style); + + doc.styleSheets[doc.styleSheets.length-1].externalURL = url; + + console.log(url, "call " + externalStyleSheetURLs.length, source); + + externalStyleSheetURLs.pop(); + + if (processAllStyleSheetsTimeout) + { + clearTimeout(processAllStyleSheetsTimeout); + } + + processAllStyleSheetsTimeout = setTimeout(function(){ + console.log("processing"); + FBL.processAllStyleSheets(doc, styleSheetIterator); + processAllStyleSheetsTimeout = null; + },200); + +}; + + +FBL.processAllStyleSheets = function(doc, styleSheetIterator) +{ + styleSheetIterator = styleSheetIterator || processStyleSheet; + + globalCSSRuleIndex = -1; + + var styleSheets = doc.styleSheets; + var importedStyleSheets = []; + + if (FBTrace.DBG_CSS) + var start = new Date().getTime(); + + for(var i=0, length=styleSheets.length; i maxSpecificity) + { + maxSpecificity = spec; + mostSpecificSelector = sel; + } + } + } + + rule.specificity = maxSpecificity; + } + } + + rules.sort(sortElementRules); + //rules.sort(solveRulesTied); + + return rules; +}; + +var sortElementRules = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + var specificityA = ruleA.specificity; + var specificityB = ruleB.specificity; + + if (specificityA > specificityB) + return 1; + + else if (specificityA < specificityB) + return -1; + + else + return ruleA.order > ruleB.order ? 1 : -1; +}; + +var solveRulesTied = function(a, b) +{ + var ruleA = CSSRuleMap[a]; + var ruleB = CSSRuleMap[b]; + + if (ruleA.specificity == ruleB.specificity) + return ruleA.order > ruleB.order ? 1 : -1; + + return null; +}; + +var reSelectorTag = /(^|\s)(?:\w+)/g; +var reSelectorClass = /\.[\w\d_-]+/g; +var reSelectorId = /#[\w\d_-]+/g; + +var getCSSRuleSpecificity = function(selector) +{ + var match = selector.match(reSelectorTag); + var tagCount = match ? match.length : 0; + + match = selector.match(reSelectorClass); + var classCount = match ? match.length : 0; + + match = selector.match(reSelectorId); + var idCount = match ? match.length : 0; + + return tagCount + 10*classCount + 100*idCount; +}; + +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ +// ************************************************************************************************ + + +// ************************************************************************************************ +// Constants + +//const Cc = Components.classes; +//const Ci = Components.interfaces; +//const nsIDOMCSSStyleRule = Ci.nsIDOMCSSStyleRule; +//const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor; +//const nsISelectionDisplay = Ci.nsISelectionDisplay; +//const nsISelectionController = Ci.nsISelectionController; + +// See: http://mxr.mozilla.org/mozilla1.9.2/source/content/events/public/nsIEventStateManager.h#153 +//const STATE_ACTIVE = 0x01; +//const STATE_FOCUS = 0x02; +//const STATE_HOVER = 0x04; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +Firebug.SourceBoxPanel = Firebug.Panel; + +var domUtils = null; + +var textContent = isIE ? "innerText" : "textContent"; +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var CSSDomplateBase = { + isEditable: function(rule) + { + return !rule.isSystemSheet; + }, + isSelectorEditable: function(rule) + { + return rule.isSelectorEditable && this.isEditable(rule); + } +}; + +var CSSPropTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssProp focusRow", $disabledStyle: "$prop.disabled", + $editGroup: "$rule|isEditable", + $cssOverridden: "$prop.overridden", role : "option"}, + A({"class": "cssPropDisable"}, "  "), + SPAN({"class": "cssPropName", $editable: "$rule|isEditable"}, "$prop.name"), + SPAN({"class": "cssColon"}, ":"), + SPAN({"class": "cssPropValue", $editable: "$rule|isEditable"}, "$prop.value$prop.important"), + SPAN({"class": "cssSemi"}, ";") + ) +}); + +var CSSRuleTag = + TAG("$rule.tag", {rule: "$rule"}); + +var CSSImportRuleTag = domplate({ + tag: DIV({"class": "cssRule insertInto focusRow importRule", _repObject: "$rule.rule"}, + "@import "", + A({"class": "objectLink", _repObject: "$rule.rule.styleSheet"}, "$rule.rule.href"), + "";" + ) +}); + +var CSSStyleRuleTag = domplate(CSSDomplateBase, { + tag: DIV({"class": "cssRule insertInto", + $cssEditableRule: "$rule|isEditable", + $editGroup: "$rule|isSelectorEditable", + _repObject: "$rule.rule", + "ruleId": "$rule.id", role : 'presentation'}, + DIV({"class": "cssHead focusRow", role : 'listitem'}, + SPAN({"class": "cssSelector", $editable: "$rule|isSelectorEditable"}, "$rule.selector"), " {" + ), + DIV({role : 'group'}, + DIV({"class": "cssPropertyListBox", role : 'listbox'}, + FOR("prop", "$rule.props", + TAG(CSSPropTag.tag, {rule: "$rule", prop: "$prop"}) + ) + ) + ), + DIV({"class": "editable insertBefore", role:"presentation"}, "}") + ) +}); + +var reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/; + +var reURL = /url\("?([^"\)]+)?"?\)/; + +var reRepeat = /no-repeat|repeat-x|repeat-y|repeat/; + +//const sothinkInstalled = !!$("swfcatcherKey_sidebar"); +var sothinkInstalled = false; +var styleGroups = +{ + text: [ + "font-family", + "font-size", + "font-weight", + "font-style", + "color", + "text-transform", + "text-decoration", + "letter-spacing", + "word-spacing", + "line-height", + "text-align", + "vertical-align", + "direction", + "column-count", + "column-gap", + "column-width" + ], + + background: [ + "background-color", + "background-image", + "background-repeat", + "background-position", + "background-attachment", + "opacity" + ], + + box: [ + "width", + "height", + "top", + "right", + "bottom", + "left", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + "-moz-border-top-radius", + "-moz-border-right-radius", + "-moz-border-bottom-radius", + "-moz-border-left-radius", + "outline-top-width", + "outline-right-width", + "outline-bottom-width", + "outline-left-width", + "outline-top-color", + "outline-right-color", + "outline-bottom-color", + "outline-left-color", + "outline-top-style", + "outline-right-style", + "outline-bottom-style", + "outline-left-style" + ], + + layout: [ + "position", + "display", + "visibility", + "z-index", + "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow + "overflow-y", + "overflow-clip", + "white-space", + "clip", + "float", + "clear", + "-moz-box-sizing" + ], + + other: [ + "cursor", + "list-style-image", + "list-style-position", + "list-style-type", + "marker-offset", + "user-focus", + "user-select", + "user-modify", + "user-input" + ] +}; + +var styleGroupTitles = +{ + text: "Text", + background: "Background", + box: "Box Model", + layout: "Layout", + other: "Other" +}; + +Firebug.CSSModule = extend(Firebug.Module, +{ + freeEdit: function(styleSheet, value) + { + if (!styleSheet.editStyleSheet) + { + var ownerNode = getStyleSheetOwnerNode(styleSheet); + styleSheet.disabled = true; + + var url = CCSV("@mozilla.org/network/standard-url;1", Components.interfaces.nsIURL); + url.spec = styleSheet.href; + + var editStyleSheet = ownerNode.ownerDocument.createElementNS( + "http://www.w3.org/1999/xhtml", + "style"); + unwrapObject(editStyleSheet).firebugIgnore = true; + editStyleSheet.setAttribute("type", "text/css"); + editStyleSheet.setAttributeNS( + "http://www.w3.org/XML/1998/namespace", + "base", + url.directory); + if (ownerNode.hasAttribute("media")) + { + editStyleSheet.setAttribute("media", ownerNode.getAttribute("media")); + } + + // Insert the edited stylesheet directly after the old one to ensure the styles + // cascade properly. + ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling); + + styleSheet.editStyleSheet = editStyleSheet; + } + + styleSheet.editStyleSheet.innerHTML = value; + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n"); + + dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]); + }, + + insertRule: function(styleSheet, cssText, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("Insert: " + ruleIndex + " " + cssText); + var insertIndex = styleSheet.insertRule(cssText, ruleIndex); + + dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]); + + return insertIndex; + }, + + deleteRule: function(styleSheet, ruleIndex) + { + if (FBTrace.DBG_CSS) FBTrace.sysout("deleteRule: " + ruleIndex + " " + styleSheet.cssRules.length, styleSheet.cssRules); + dispatch(this.fbListeners, "onCSSDeleteRule", [styleSheet, ruleIndex]); + + styleSheet.deleteRule(ruleIndex); + }, + + setProperty: function(rule, propName, propValue, propPriority) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + // good browsers + if (style.getPropertyValue) + { + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect + // unless we remove the property first + style.removeProperty(propName); + + style.setProperty(propName, propValue, propPriority); + } + // sad browsers + else + { + // TODO: xxxpedro parse CSS rule to find property priority in IE? + //console.log(propName, propValue); + style[toCamelCase(propName)] = propValue; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue, propPriority, prevValue, prevPriority, rule, baseText]); + } + }, + + removeProperty: function(rule, propName, parent) + { + var style = rule.style || rule; + + // Record the original CSS text for the inline case so we can reconstruct at a later + // point for diffing purposes + var baseText = style.cssText; + + if (style.getPropertyValue) + { + + var prevValue = style.getPropertyValue(propName); + var prevPriority = style.getPropertyPriority(propName); + + style.removeProperty(propName); + } + else + { + style[toCamelCase(propName)] = ""; + } + + if (propName) { + dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue, prevPriority, rule, baseText]); + } + }/*, + + cleanupSheets: function(doc, context) + { + // Due to the manner in which the layout engine handles multiple + // references to the same sheet we need to kick it a little bit. + // The injecting a simple stylesheet then removing it will force + // Firefox to regenerate it's CSS hierarchy. + // + // WARN: This behavior was determined anecdotally. + // See http://code.google.com/p/fbug/issues/detail?id=2440 + var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + style.setAttribute("charset","utf-8"); + unwrapObject(style).firebugIgnore = true; + style.setAttribute("type", "text/css"); + style.innerHTML = "#fbIgnoreStyleDO_NOT_USE {}"; + addStyleSheet(doc, style); + style.parentNode.removeChild(style); + + // https://bugzilla.mozilla.org/show_bug.cgi?id=500365 + // This voodoo touches each style sheet to force some Firefox internal change to allow edits. + var styleSheets = getAllStyleSheets(context); + for(var i = 0; i < styleSheets.length; i++) + { + try + { + var rules = styleSheets[i].cssRules; + if (rules.length > 0) + var touch = rules[0]; + if (FBTrace.DBG_CSS && touch) + FBTrace.sysout("css.show() touch "+typeof(touch)+" in "+(styleSheets[i].href?styleSheets[i].href:context.getName())); + } + catch(e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.show: sheet.cssRules FAILS for "+(styleSheets[i]?styleSheets[i].href:"null sheet")+e, e); + } + } + }, + cleanupSheetHandler: function(event, context) + { + var target = event.target || event.srcElement, + tagName = (target.tagName || "").toLowerCase(); + if (tagName == "link") + { + this.cleanupSheets(target.ownerDocument, context); + } + }, + watchWindow: function(context, win) + { + var cleanupSheets = bind(this.cleanupSheets, this), + cleanupSheetHandler = bind(this.cleanupSheetHandler, this, context), + doc = win.document; + + //doc.addEventListener("DOMAttrModified", cleanupSheetHandler, false); + //doc.addEventListener("DOMNodeInserted", cleanupSheetHandler, false); + }, + loadedContext: function(context) + { + var self = this; + iterateWindows(context.browser.contentWindow, function(subwin) + { + self.cleanupSheets(subwin.document, context); + }); + } + /**/ +}); + +// ************************************************************************************************ + +Firebug.CSSStyleSheetPanel = function() {}; + +Firebug.CSSStyleSheetPanel.prototype = extend(Firebug.SourceBoxPanel, +{ + template: domplate( + { + tag: + DIV({"class": "cssSheet insertInto a11yCSSView"}, + FOR("rule", "$rules", + CSSRuleTag + ), + DIV({"class": "cssSheet editable insertBefore"}, "") + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + refresh: function() + { + if (this.location) + this.updateLocation(this.location); + else if (this.selection) + this.updateSelection(this.selection); + }, + + toggleEditing: function() + { + if (!this.stylesheetEditor) + this.stylesheetEditor = new StyleSheetEditor(this.document); + + if (this.editing) + Firebug.Editor.stopEditing(); + else + { + if (!this.location) + return; + + var styleSheet = this.location.editStyleSheet + ? this.location.editStyleSheet.sheet + : this.location; + + var css = getStyleSheetCSS(styleSheet, this.context); + //var topmost = getTopmostRuleLine(this.panelNode); + + this.stylesheetEditor.styleSheet = this.location; + Firebug.Editor.startEditing(this.panelNode, css, this.stylesheetEditor); + //this.stylesheetEditor.scrollToLine(topmost.line, topmost.offset); + } + }, + + getStylesheetURL: function(rule) + { + if (this.location.href) + return this.location.href; + else + return this.context.window.location.href; + }, + + getRuleByLine: function(styleSheet, line) + { + if (!domUtils) + return null; + + var cssRules = styleSheet.cssRules; + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + if (rule instanceof CSSStyleRule) + { + var ruleLine = domUtils.getRuleLine(rule); + if (ruleLine >= line) + return rule; + } + } + }, + + highlightRule: function(rule) + { + var ruleElement = Firebug.getElementByRepObject(this.panelNode.firstChild, rule); + if (ruleElement) + { + scrollIntoCenterView(ruleElement, this.panelNode); + setClassTimed(ruleElement, "jumpHighlight", this.context); + } + }, + + getStyleSheetRules: function(context, styleSheet) + { + var isSystemSheet = isSystemStyleSheet(styleSheet); + + function appendRules(cssRules) + { + for (var i = 0; i < cssRules.length; ++i) + { + var rule = cssRules[i]; + + // TODO: xxxpedro opera instanceof stylesheet remove the following comments when + // the issue with opera and style sheet Classes has been solved. + + //if (rule instanceof CSSStyleRule) + if (instanceOf(rule, "CSSStyleRule")) + { + var props = this.getRuleProperties(context, rule); + //var line = domUtils.getRuleLine(rule); + var line = null; + + var selector = rule.selectorText; + + if (isIE) + { + selector = selector.replace(reSelectorTag, + function(s){return s.toLowerCase();}); + } + + var ruleId = rule.selectorText+"/"+line; + rules.push({tag: CSSStyleRuleTag.tag, rule: rule, id: ruleId, + selector: selector, props: props, + isSystemSheet: isSystemSheet, + isSelectorEditable: true}); + } + //else if (rule instanceof CSSImportRule) + else if (instanceOf(rule, "CSSImportRule")) + rules.push({tag: CSSImportRuleTag.tag, rule: rule}); + //else if (rule instanceof CSSMediaRule) + else if (instanceOf(rule, "CSSMediaRule")) + appendRules.apply(this, [rule.cssRules]); + else + { + if (FBTrace.DBG_ERRORS || FBTrace.DBG_CSS) + FBTrace.sysout("css getStyleSheetRules failed to classify a rule ", rule); + } + } + } + + var rules = []; + appendRules.apply(this, [styleSheet.cssRules || styleSheet.rules]); + return rules; + }, + + parseCSSProps: function(style, inheritMode) + { + var props = []; + + if (Firebug.expandShorthandProps) + { + var count = style.length-1, + index = style.length; + while (index--) + { + var propName = style.item(count - index); + this.addProperty(propName, style.getPropertyValue(propName), !!style.getPropertyPriority(propName), false, inheritMode, props); + } + } + else + { + var lines = style.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g); + var propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/; + var line,i=0; + // TODO: xxxpedro port to firebug: variable leaked into global namespace + var m; + + while(line=lines[i++]){ + m = propRE.exec(line); + if(!m) + continue; + //var name = m[1], value = m[2], important = !!m[3]; + if (m[2]) + this.addProperty(m[1], m[2], !!m[3], false, inheritMode, props); + }; + } + + return props; + }, + + getRuleProperties: function(context, rule, inheritMode) + { + var props = this.parseCSSProps(rule.style, inheritMode); + + // TODO: xxxpedro port to firebug: variable leaked into global namespace + //var line = domUtils.getRuleLine(rule); + var line; + var ruleId = rule.selectorText+"/"+line; + this.addOldProperties(context, ruleId, inheritMode, props); + sortProperties(props); + + return props; + }, + + addOldProperties: function(context, ruleId, inheritMode, props) + { + if (context.selectorMap && context.selectorMap.hasOwnProperty(ruleId) ) + { + var moreProps = context.selectorMap[ruleId]; + for (var i = 0; i < moreProps.length; ++i) + { + var prop = moreProps[i]; + this.addProperty(prop.name, prop.value, prop.important, true, inheritMode, props); + } + } + }, + + addProperty: function(name, value, important, disabled, inheritMode, props) + { + name = name.toLowerCase(); + + if (inheritMode && !inheritedStyleNames[name]) + return; + + name = this.translateName(name, value); + if (name) + { + value = stripUnits(rgbToHex(value)); + important = important ? " !important" : ""; + + var prop = {name: name, value: value, important: important, disabled: disabled}; + props.push(prop); + } + }, + + translateName: function(name, value) + { + // Don't show these proprietary Mozilla properties + if ((value == "-moz-initial" + && (name == "-moz-background-clip" || name == "-moz-background-origin" + || name == "-moz-background-inline-policy")) + || (value == "physical" + && (name == "margin-left-ltr-source" || name == "margin-left-rtl-source" + || name == "margin-right-ltr-source" || name == "margin-right-rtl-source")) + || (value == "physical" + && (name == "padding-left-ltr-source" || name == "padding-left-rtl-source" + || name == "padding-right-ltr-source" || name == "padding-right-rtl-source"))) + return null; + + // Translate these back to the form the user probably expects + if (name == "margin-left-value") + return "margin-left"; + else if (name == "margin-right-value") + return "margin-right"; + else if (name == "margin-top-value") + return "margin-top"; + else if (name == "margin-bottom-value") + return "margin-bottom"; + else if (name == "padding-left-value") + return "padding-left"; + else if (name == "padding-right-value") + return "padding-right"; + else if (name == "padding-top-value") + return "padding-top"; + else if (name == "padding-bottom-value") + return "padding-bottom"; + // XXXjoe What about border! + else + return name; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + editElementStyle: function() + { + ///var rulesBox = this.panelNode.getElementsByClassName("cssElementRuleContainer")[0]; + var rulesBox = $$(".cssElementRuleContainer", this.panelNode)[0]; + var styleRuleBox = rulesBox && Firebug.getElementByRepObject(rulesBox, this.selection); + if (!styleRuleBox) + { + var rule = {rule: this.selection, inherited: false, selector: "element.style", props: []}; + if (!rulesBox) + { + // The element did not have any displayed styles. We need to create the whole tree and remove + // the no styles message + styleRuleBox = this.template.cascadedTag.replace({ + rules: [rule], inherited: [], inheritLabel: "Inherited from" // $STR("InheritedFrom") + }, this.panelNode); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("cssElementRuleContainer")[0]; + styleRuleBox = $$(".cssElementRuleContainer", styleRuleBox)[0]; + } + else + styleRuleBox = this.template.ruleTag.insertBefore({rule: rule}, rulesBox); + + ///styleRuleBox = styleRuleBox.getElementsByClassName("insertInto")[0]; + styleRuleBox = $$(".insertInto", styleRuleBox)[0]; + } + + Firebug.Editor.insertRowForObject(styleRuleBox); + }, + + insertPropertyRow: function(row) + { + Firebug.Editor.insertRowForObject(row); + }, + + insertRule: function(row) + { + var location = getAncestorByClass(row, "cssRule"); + if (!location) + { + location = getChildByClass(this.panelNode, "cssSheet"); + Firebug.Editor.insertRowForObject(location); + } + else + { + Firebug.Editor.insertRow(location, "before"); + } + }, + + editPropertyRow: function(row) + { + var propValueBox = getChildByClass(row, "cssPropValue"); + Firebug.Editor.startEditing(propValueBox); + }, + + deletePropertyRow: function(row) + { + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + Firebug.CSSModule.removeProperty(rule, propName); + + // Remove the property from the selector map, if it was disabled + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if ( this.context.selectorMap && this.context.selectorMap.hasOwnProperty(ruleId) ) + { + var map = this.context.selectorMap[ruleId]; + for (var i = 0; i < map.length; ++i) + { + if (map[i].name == propName) + { + map.splice(i, 1); + break; + } + } + } + if (this.name == "stylesheet") + dispatch([Firebug.A11yModel], 'onInlineEditorClose', [this, row.firstChild, true]); + row.parentNode.removeChild(row); + + this.markChange(this.name == "stylesheet"); + }, + + disablePropertyRow: function(row) + { + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(row); + var propName = getChildByClass(row, "cssPropName")[textContent]; + + if (!this.context.selectorMap) + this.context.selectorMap = {}; + + // XXXjoe Generate unique key for elements too + var ruleId = Firebug.getRepNode(row).getAttribute("ruleId"); + if (!(this.context.selectorMap.hasOwnProperty(ruleId))) + this.context.selectorMap[ruleId] = []; + + var map = this.context.selectorMap[ruleId]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + if (hasClass(row, "disabledStyle")) + { + Firebug.CSSModule.removeProperty(rule, propName); + + map.push({"name": propName, "value": parsedValue.value, + "important": parsedValue.priority}); + } + else + { + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + + var index = findPropByName(map, propName); + map.splice(index, 1); + } + + this.markChange(this.name == "stylesheet"); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onMouseDown: function(event) + { + //console.log("onMouseDown", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + // XXjoe Hack to only allow clicking on the checkbox + if (!isLeftClick(event) || offset > 20) + return; + + var target = event.target || event.srcElement; + if (hasClass(target, "textEditor")) + return; + + var row = getAncestorByClass(target, "cssProp"); + if (row && hasClass(row, "editGroup")) + { + this.disablePropertyRow(row); + cancelEvent(event); + } + }, + + onDoubleClick: function(event) + { + //console.log("onDoubleClick", event.target || event.srcElement, event); + + // xxxpedro adjusting coordinates because the panel isn't a window yet + var offset = event.clientX - this.panelNode.parentNode.offsetLeft; + + if (!isLeftClick(event) || offset <= 20) + return; + + var target = event.target || event.srcElement; + + //console.log("ok", target, hasClass(target, "textEditorInner"), !isLeftClick(event), offset <= 20); + + // if the inline editor was clicked, don't insert a new rule + if (hasClass(target, "textEditorInner")) + return; + + var row = getAncestorByClass(target, "cssRule"); + if (row && !getAncestorByClass(target, "cssPropName") + && !getAncestorByClass(target, "cssPropValue")) + { + this.insertPropertyRow(row); + cancelEvent(event); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "stylesheet", + title: "CSS", + parentPanel: null, + searchable: true, + dependents: ["css", "stylesheet", "dom", "domSide", "layout"], + + options: + { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onMouseDown = bind(this.onMouseDown, this); + this.onDoubleClick = bind(this.onDoubleClick, this); + + if (this.name == "stylesheet") + { + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var selectNode = this.selectNode = createElement("select"); + + processAllStyleSheets(doc, function(doc, styleSheet) + { + var key = StyleSheetCache.key(styleSheet); + var fileName = getFileName(styleSheet.href) || getFileName(doc.location.href); + var option = createElement("option", {value: key}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }); + + this.toolButtonsNode.appendChild(selectNode); + } + /**/ + }, + + onChangeSelect: function(event) + { + event = event || window.event; + var target = event.srcElement || event.currentTarget; + var key = target.value; + var styleSheet = StyleSheetCache.get(key); + + this.updateLocation(styleSheet); + }, + + initialize: function() + { + Firebug.Panel.initialize.apply(this, arguments); + + //if (!domUtils) + //{ + // try { + // domUtils = CCSV("@mozilla.org/inspector/dom-utils;1", "inIDOMUtils"); + // } catch (exc) { + // if (FBTrace.DBG_ERRORS) + // FBTrace.sysout("@mozilla.org/inspector/dom-utils;1 FAILED to load: "+exc, exc); + // } + //} + + //TODO: xxxpedro + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + this.initializeNode(); + + if (this.name == "stylesheet") + { + var styleSheets = Firebug.browser.document.styleSheets; + + if (styleSheets.length > 0) + { + addEvent(this.selectNode, "change", this.onChangeSelect); + + this.updateLocation(styleSheets[0]); + } + } + + //Firebug.SourceBoxPanel.initialize.apply(this, arguments); + }, + + shutdown: function() + { + // must destroy the editor when we leave the panel to avoid problems (Issue 2981) + Firebug.Editor.stopEditing(); + + if (this.name == "stylesheet") + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + } + + this.destroyNode(); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + destroy: function(state) + { + //state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop; + + //persistObjects(this, state); + + // xxxpedro we are stopping the editor in the shutdown method already + //Firebug.Editor.stopEditing(); + Firebug.Panel.destroy.apply(this, arguments); + }, + + initializeNode: function(oldPanelNode) + { + addEvent(this.panelNode, "mousedown", this.onMouseDown); + addEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.initializeNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'css']); + }, + + destroyNode: function() + { + removeEvent(this.panelNode, "mousedown", this.onMouseDown); + removeEvent(this.panelNode, "dblclick", this.onDoubleClick); + //Firebug.SourceBoxPanel.destroyNode.apply(this, arguments); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'css']); + }, + + ishow: function(state) + { + Firebug.Inspector.stopInspecting(true); + + this.showToolbarButtons("fbCSSButtons", true); + + if (this.context.loaded && !this.location) // wait for loadedContext to restore the panel + { + restoreObjects(this, state); + + if (!this.location) + this.location = this.getDefaultLocation(); + + if (state && state.scrollTop) + this.panelNode.scrollTop = state.scrollTop; + } + }, + + ihide: function() + { + this.showToolbarButtons("fbCSSButtons", false); + + this.lastScrollTop = this.panelNode.scrollTop; + }, + + supportsObject: function(object) + { + if (object instanceof CSSStyleSheet) + return 1; + else if (object instanceof CSSStyleRule) + return 2; + else if (object instanceof CSSStyleDeclaration) + return 2; + else if (object instanceof SourceLink && object.type == "css" && reCSS.test(object.href)) + return 2; + else + return 0; + }, + + updateLocation: function(styleSheet) + { + if (!styleSheet) + return; + if (styleSheet.editStyleSheet) + styleSheet = styleSheet.editStyleSheet.sheet; + + // if it is a restricted stylesheet, show the warning message and abort the update process + if (styleSheet.restricted) + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, this.panelNode); + + // TODO: xxxpedro remove when there the external resource problem is fixed + externalStyleSheetWarning.tag.append({ + object: "The stylesheet could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22" + }, this.panelNode); + + return; + } + + var rules = this.getStyleSheetRules(this.context, styleSheet); + + var result; + if (rules.length) + result = this.template.tag.replace({rules: rules}, this.panelNode); + else + result = FirebugReps.Warning.tag.replace({object: "EmptyStyleSheet"}, this.panelNode); + + // TODO: xxxpedro need to fix showToolbarButtons function + //this.showToolbarButtons("fbCSSButtons", !isSystemStyleSheet(this.location)); + + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, this.panelNode]); + }, + + updateSelection: function(object) + { + this.selection = null; + + if (object instanceof CSSStyleDeclaration) { + object = object.parentRule; + } + + if (object instanceof CSSStyleRule) + { + this.navigate(object.parentStyleSheet); + this.highlightRule(object); + } + else if (object instanceof CSSStyleSheet) + { + this.navigate(object); + } + else if (object instanceof SourceLink) + { + try + { + var sourceLink = object; + + var sourceFile = getSourceFileByHref(sourceLink.href, this.context); + if (sourceFile) + { + clearNode(this.panelNode); // replace rendered stylesheets + this.showSourceFile(sourceFile); + + var lineNo = object.line; + if (lineNo) + this.scrollToLine(lineNo, this.jumpHighlightFactory(lineNo, this.context)); + } + else // XXXjjb we should not be taking this path + { + var stylesheet = getStyleSheetByHref(sourceLink.href, this.context); + if (stylesheet) + this.navigate(stylesheet); + else + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href, sourceLink); + } + } + } + catch(exc) { + if (FBTrace.DBG_CSS) + FBTrace.sysout("css.upDateSelection FAILS "+exc, exc); + } + } + }, + + updateOption: function(name, value) + { + if (name == "expandShorthandProps") + this.refresh(); + }, + + getLocationList: function() + { + var styleSheets = getAllStyleSheets(this.context); + return styleSheets; + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") }, + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ]; + }, + + getContextMenuItems: function(style, target) + { + var items = []; + + if (this.infoTipType == "color") + { + items.push( + {label: "CopyColor", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) } + ); + } + else if (this.infoTipType == "image") + { + items.push( + {label: "CopyImageLocation", + command: bindFixed(copyToClipboard, FBL, this.infoTipObject) }, + {label: "OpenImageInNewTab", + command: bindFixed(openNewTab, FBL, this.infoTipObject) } + ); + } + + ///if (this.selection instanceof Element) + if (isElement(this.selection)) + { + items.push( + //"-", + {label: "EditStyle", + command: bindFixed(this.editElementStyle, this) } + ); + } + else if (!isSystemStyleSheet(this.selection)) + { + items.push( + //"-", + {label: "NewRule", + command: bindFixed(this.insertRule, this, target) } + ); + } + + var cssRule = getAncestorByClass(target, "cssRule"); + if (cssRule && hasClass(cssRule, "cssEditableRule")) + { + items.push( + "-", + {label: "NewProp", + command: bindFixed(this.insertPropertyRow, this, target) } + ); + + var propRow = getAncestorByClass(target, "cssProp"); + if (propRow) + { + var propName = getChildByClass(propRow, "cssPropName")[textContent]; + var isDisabled = hasClass(propRow, "disabledStyle"); + + items.push( + {label: $STRF("EditProp", [propName]), nol10n: true, + command: bindFixed(this.editPropertyRow, this, propRow) }, + {label: $STRF("DeleteProp", [propName]), nol10n: true, + command: bindFixed(this.deletePropertyRow, this, propRow) }, + {label: $STRF("DisableProp", [propName]), nol10n: true, + type: "checkbox", checked: isDisabled, + command: bindFixed(this.disablePropertyRow, this, propRow) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bind(this.refresh, this) } + ); + + return items; + }, + + browseObject: function(object) + { + if (this.infoTipType == "image") + { + openNewTab(this.infoTipObject); + return true; + } + }, + + showInfoTip: function(infoTip, target, x, y) + { + var propValue = getAncestorByClass(target, "cssPropValue"); + if (propValue) + { + var offset = getClientOffset(propValue); + var offsetX = x-offset.x; + + var text = propValue[textContent]; + var charWidth = propValue.offsetWidth/text.length; + var charOffset = Math.floor(offsetX/charWidth); + + var cssValue = parseCSSValue(text, charOffset); + if (cssValue) + { + if (cssValue.value == this.infoTipValue) + return true; + + this.infoTipValue = cssValue.value; + + if (cssValue.type == "rgb" || (!cssValue.type && isColorKeyword(cssValue.value))) + { + this.infoTipType = "color"; + this.infoTipObject = cssValue.value; + + return Firebug.InfoTip.populateColorInfoTip(infoTip, cssValue.value); + } + else if (cssValue.type == "url") + { + ///var propNameNode = target.parentNode.getElementsByClassName("cssPropName").item(0); + var propNameNode = getElementByClass(target.parentNode, "cssPropName"); + if (propNameNode && isImageRule(propNameNode[textContent])) + { + var rule = Firebug.getRepObject(target); + var baseURL = this.getStylesheetURL(rule); + var relURL = parseURLValue(cssValue.value); + var absURL = isDataURL(relURL) ? relURL:absoluteURL(relURL, baseURL); + var repeat = parseRepeatValue(text); + + this.infoTipType = "image"; + this.infoTipObject = absURL; + + return Firebug.InfoTip.populateImageInfoTip(infoTip, absURL, repeat); + } + } + } + } + + delete this.infoTipType; + delete this.infoTipValue; + delete this.infoTipObject; + }, + + getEditor: function(target, value) + { + if (target == this.panelNode + || hasClass(target, "cssSelector") || hasClass(target, "cssRule") + || hasClass(target, "cssSheet")) + { + if (!this.ruleEditor) + this.ruleEditor = new CSSRuleEditor(this.document); + + return this.ruleEditor; + } + else + { + if (!this.editor) + this.editor = new CSSEditor(this.document); + + return this.editor; + } + }, + + getDefaultLocation: function() + { + try + { + var styleSheets = this.context.window.document.styleSheets; + if (styleSheets.length) + { + var sheet = styleSheets[0]; + return (Firebug.filterSystemURLs && isSystemURL(getURLForStyleSheet(sheet))) ? null : sheet; + } + } + catch (exc) + { + if (FBTrace.DBG_LOCATIONS) + FBTrace.sysout("css.getDefaultLocation FAILS "+exc, exc); + } + }, + + getObjectDescription: function(styleSheet) + { + var url = getURLForStyleSheet(styleSheet); + var instance = getInstanceForStyleSheet(styleSheet); + + var baseDescription = splitURLBase(url); + if (instance) { + baseDescription.name = baseDescription.name + " #" + (instance + 1); + } + return baseDescription; + }, + + search: function(text, reverse) + { + var curDoc = this.searchCurrentDoc(!Firebug.searchGlobal, text, reverse); + if (!curDoc && Firebug.searchGlobal) + { + return this.searchOtherDocs(text, reverse); + } + return curDoc; + }, + + searchOtherDocs: function(text, reverse) + { + var scanRE = Firebug.Search.getTestingRegex(text); + function scanDoc(styleSheet) { + // we don't care about reverse here as we are just looking for existence, + // if we do have a result we will handle the reverse logic on display + for (var i = 0; i < styleSheet.cssRules.length; i++) + { + if (scanRE.test(styleSheet.cssRules[i].cssText)) + { + return true; + } + } + } + + if (this.navigateToNextDocument(scanDoc, reverse)) + { + return this.searchCurrentDoc(true, text, reverse); + } + }, + + searchCurrentDoc: function(wrapSearch, text, reverse) + { + if (!text) + { + delete this.currentSearch; + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + { + row = this.currentSearch.findNext(wrapSearch, false, reverse, Firebug.Search.isCaseSensitive(text)); + } + else + { + if (this.editing) + { + this.currentSearch = new TextSearch(this.stylesheetEditor.box); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + scrollSelectionIntoView(this); + return true; + } + else + return false; + } + else + { + function findRow(node) { return node.nodeType == 1 ? node : node.parentNode; } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text)); + } + } + + if (row) + { + this.document.defaultView.getSelection().selectAllChildren(row); + scrollIntoCenterView(row, this.panelNode); + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, null]); + return false; + } + }, + + getSearchOptionsMenuItems: function() + { + return [ + Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive"), + Firebug.Search.searchOptionMenu("search.Multiple_Files", "searchGlobal") + ]; + } +}); +/**/ +// ************************************************************************************************ + +function CSSElementPanel() {} + +CSSElementPanel.prototype = extend(Firebug.CSSStyleSheetPanel.prototype, +{ + template: domplate( + { + cascadedTag: + DIV({"class": "a11yCSSView", role : 'presentation'}, + DIV({role : 'list', 'aria-label' : $STR('aria.labels.style rules') }, + FOR("rule", "$rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ), + DIV({role : "list", 'aria-label' :$STR('aria.labels.inherited style rules')}, + FOR("section", "$inherited", + H1({"class": "cssInheritHeader groupHeader focusRow", role : 'listitem' }, + SPAN({"class": "cssInheritLabel"}, "$inheritLabel"), + TAG(FirebugReps.Element.shortTag, {object: "$section.element"}) + ), + DIV({role : 'group'}, + FOR("rule", "$section.rules", + TAG("$ruleTag", {rule: "$rule"}) + ) + ) + ) + ) + ), + + ruleTag: + isIE ? + // IE needs the sourceLink first, otherwise it will be rendered outside the panel + DIV({"class": "cssElementRuleContainer"}, + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}), + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}) + ) + : + // other browsers need the sourceLink last, otherwise it will cause an extra space + // before the rule representation + DIV({"class": "cssElementRuleContainer"}, + TAG(CSSStyleRuleTag.tag, {rule: "$rule"}), + TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateCascadeView: function(element) + { + //dispatch([Firebug.A11yModel], 'onBeforeCSSRulesAdded', [this]); + var rules = [], sections = [], usedProps = {}; + this.getInheritedRules(element, sections, usedProps); + this.getElementRules(element, rules, usedProps); + + if (rules.length || sections.length) + { + var inheritLabel = "Inherited from"; // $STR("InheritedFrom"); + var result = this.template.cascadedTag.replace({rules: rules, inherited: sections, + inheritLabel: inheritLabel}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + else + { + var result = FirebugReps.Warning.tag.replace({object: "EmptyElementCSS"}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + } + + // TODO: xxxpedro remove when there the external resource problem is fixed + if (externalStyleSheetURLs.length > 0) + externalStyleSheetWarning.tag.append({ + object: "The results here may be inaccurate because some " + + "stylesheets could not be loaded due to access restrictions. ", + link: "more...", + href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22" + }, this.panelNode); + }, + + getStylesheetURL: function(rule) + { + // if the parentStyleSheet.href is null, CSS std says its inline style. + // TODO: xxxpedro IE doesn't have rule.parentStyleSheet so we must fall back to the doc.location + if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href) + return rule.parentStyleSheet.href; + else + return this.selection.ownerDocument.location.href; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getInheritedRules: function(element, sections, usedProps) + { + var parent = element.parentNode; + if (parent && parent.nodeType == 1) + { + this.getInheritedRules(parent, sections, usedProps); + + var rules = []; + this.getElementRules(parent, rules, usedProps, true); + + if (rules.length) + sections.splice(0, 0, {element: parent, rules: rules}); + } + }, + + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + + // TODO: xxxpedro remove document specificity issue + //var eid = ElementCache(element); + //inspectedRules = ElementCSSRulesMap[eid]; + + inspectedRules = getElementCSSRules(element); + + if (inspectedRules) + { + for (var i = 0, length=inspectedRules.length; i < length; ++i) + { + var ruleId = inspectedRules[i]; + var ruleData = CSSRuleMap[ruleId]; + var rule = ruleData.rule; + + var ssid = ruleData.styleSheetId; + var parentStyleSheet = StyleSheetCache.get(ssid); + + var href = parentStyleSheet.externalURL ? parentStyleSheet.externalURL : parentStyleSheet.href; // Null means inline + + var instance = null; + //var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = false; + //var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + // + //var line = domUtils.getRuleLine(rule); + var line; + + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: ruleData.selector, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /* + getElementRules: function(element, rules, usedProps, inheritMode) + { + var inspectedRules, displayedRules = {}; + try + { + inspectedRules = domUtils ? domUtils.getCSSStyleRules(element) : null; + } catch (exc) {} + + if (inspectedRules) + { + for (var i = 0; i < inspectedRules.Count(); ++i) + { + var rule = QI(inspectedRules.GetElementAt(i), nsIDOMCSSStyleRule); + + var href = rule.parentStyleSheet.href; // Null means inline + + var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument); + + var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet); + if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules + continue; + if (!href) + href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452 + + var props = this.getRuleProperties(this.context, rule, inheritMode); + if (inheritMode && !props.length) + continue; + + var line = domUtils.getRuleLine(rule); + var ruleId = rule.selectorText+"/"+line; + var sourceLink = new SourceLink(href, line, "css", rule, instance); + + this.markOverridenProps(props, usedProps, inheritMode); + + rules.splice(0, 0, {rule: rule, id: ruleId, + selector: rule.selectorText, sourceLink: sourceLink, + props: props, inherited: inheritMode, + isSystemSheet: isSystemSheet}); + } + } + + if (element.style) + this.getStyleProperties(element, rules, usedProps, inheritMode); + + if (FBTrace.DBG_CSS) + FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules); + }, + /**/ + markOverridenProps: function(props, usedProps, inheritMode) + { + for (var i = 0; i < props.length; ++i) + { + var prop = props[i]; + if ( usedProps.hasOwnProperty(prop.name) ) + { + var deadProps = usedProps[prop.name]; // all previous occurrences of this property + for (var j = 0; j < deadProps.length; ++j) + { + var deadProp = deadProps[j]; + if (!deadProp.disabled && !deadProp.wasInherited && deadProp.important && !prop.important) + prop.overridden = true; // new occurrence overridden + else if (!prop.disabled) + deadProp.overridden = true; // previous occurrences overridden + } + } + else + usedProps[prop.name] = []; + + prop.wasInherited = inheritMode ? true : false; + usedProps[prop.name].push(prop); // all occurrences of a property seen so far, by name + } + }, + + getStyleProperties: function(element, rules, usedProps, inheritMode) + { + var props = this.parseCSSProps(element.style, inheritMode); + this.addOldProperties(this.context, getElementXPath(element), inheritMode, props); + + sortProperties(props); + this.markOverridenProps(props, usedProps, inheritMode); + + if (props.length) + rules.splice(0, 0, + {rule: element, id: getElementXPath(element), + selector: "element.style", props: props, inherited: inheritMode}); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "css", + title: "Style", + parentPanel: "HTML", + order: 0, + + initialize: function() + { + this.context = Firebug.chrome; // TODO: xxxpedro css2 + this.document = Firebug.chrome.document; // TODO: xxxpedro css2 + + Firebug.CSSStyleSheetPanel.prototype.initialize.apply(this, arguments); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + + //this.updateCascadeView(document.getElementsByTagName("h1")[0]); + //this.updateCascadeView(document.getElementById("build")); + + /* + this.onStateChange = bindFixed(this.contentStateCheck, this); + this.onHoverChange = bindFixed(this.contentStateCheck, this, STATE_HOVER); + this.onActiveChange = bindFixed(this.contentStateCheck, this, STATE_ACTIVE); + /**/ + }, + + ishow: function(state) + { + }, + + watchWindow: function(win) + { + if (domUtils) + { + // Normally these would not be required, but in order to update after the state is set + // using the options menu we need to monitor these global events as well + var doc = win.document; + ///addEvent(doc, "mouseover", this.onHoverChange); + ///addEvent(doc, "mousedown", this.onActiveChange); + } + }, + unwatchWindow: function(win) + { + var doc = win.document; + ///removeEvent(doc, "mouseover", this.onHoverChange); + ///removeEvent(doc, "mousedown", this.onActiveChange); + + if (isAncestor(this.stateChangeEl, doc)) + { + this.removeStateChangeHandlers(); + } + }, + + supportsObject: function(object) + { + return object instanceof Element ? 1 : 0; + }, + + updateView: function(element) + { + this.updateCascadeView(element); + if (domUtils) + { + this.contentState = safeGetContentState(element); + this.addStateChangeHandlers(element); + } + }, + + updateSelection: function(element) + { + if ( !instanceOf(element , "Element") ) // html supports SourceLink + return; + + if (sothinkInstalled) + { + FirebugReps.Warning.tag.replace({object: "SothinkWarning"}, this.panelNode); + return; + } + + /* + if (!domUtils) + { + FirebugReps.Warning.tag.replace({object: "DOMInspectorWarning"}, this.panelNode); + return; + } + /**/ + + if (!element) + return; + + this.updateView(element); + }, + + updateOption: function(name, value) + { + if (name == "showUserAgentCSS" || name == "expandShorthandProps") + this.refresh(); + }, + + getOptionsMenuItems: function() + { + var ret = [ + {label: "Show User Agent CSS", type: "checkbox", checked: Firebug.showUserAgentCSS, + command: bindFixed(Firebug.togglePref, Firebug, "showUserAgentCSS") }, + {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps, + command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") } + ]; + if (domUtils && this.selection) + { + var state = safeGetContentState(this.selection); + + ret.push("-"); + ret.push({label: ":active", type: "checkbox", checked: state & STATE_ACTIVE, + command: bindFixed(this.updateContentState, this, STATE_ACTIVE, state & STATE_ACTIVE)}); + ret.push({label: ":hover", type: "checkbox", checked: state & STATE_HOVER, + command: bindFixed(this.updateContentState, this, STATE_HOVER, state & STATE_HOVER)}); + } + return ret; + }, + + updateContentState: function(state, remove) + { + domUtils.setContentState(remove ? this.selection.ownerDocument.documentElement : this.selection, state); + this.refresh(); + }, + + addStateChangeHandlers: function(el) + { + this.removeStateChangeHandlers(); + + /* + addEvent(el, "focus", this.onStateChange); + addEvent(el, "blur", this.onStateChange); + addEvent(el, "mouseup", this.onStateChange); + addEvent(el, "mousedown", this.onStateChange); + addEvent(el, "mouseover", this.onStateChange); + addEvent(el, "mouseout", this.onStateChange); + /**/ + + this.stateChangeEl = el; + }, + + removeStateChangeHandlers: function() + { + var sel = this.stateChangeEl; + if (sel) + { + /* + removeEvent(sel, "focus", this.onStateChange); + removeEvent(sel, "blur", this.onStateChange); + removeEvent(sel, "mouseup", this.onStateChange); + removeEvent(sel, "mousedown", this.onStateChange); + removeEvent(sel, "mouseover", this.onStateChange); + removeEvent(sel, "mouseout", this.onStateChange); + /**/ + } + }, + + contentStateCheck: function(state) + { + if (!state || this.contentState & state) + { + var timeoutRunner = bindFixed(function() + { + var newState = safeGetContentState(this.selection); + if (newState != this.contentState) + { + this.context.invalidatePanels(this.name); + } + }, this); + + // Delay exec until after the event has processed and the state has been updated + setTimeout(timeoutRunner, 0); + } + } +}); + +function safeGetContentState(selection) +{ + try + { + return domUtils.getContentState(selection); + } + catch (e) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("css.safeGetContentState; EXCEPTION", e); + } +} + +// ************************************************************************************************ + +function CSSComputedElementPanel() {} + +CSSComputedElementPanel.prototype = extend(CSSElementPanel.prototype, +{ + template: domplate( + { + computedTag: + DIV({"class": "a11yCSSView", role : "list", "aria-label" : $STR('aria.labels.computed styles')}, + FOR("group", "$groups", + H1({"class": "cssInheritHeader groupHeader focusRow", role : "listitem"}, + SPAN({"class": "cssInheritLabel"}, "$group.title") + ), + TABLE({width: "100%", role : 'group'}, + TBODY({role : 'presentation'}, + FOR("prop", "$group.props", + TR({"class": 'focusRow computedStyleRow', role : 'listitem'}, + TD({"class": "stylePropName", role : 'presentation'}, "$prop.name"), + TD({"class": "stylePropValue", role : 'presentation'}, "$prop.value") + ) + ) + ) + ) + ) + ) + }), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + updateComputedView: function(element) + { + var win = isIE ? + element.ownerDocument.parentWindow : + element.ownerDocument.defaultView; + + var style = isIE ? + element.currentStyle : + win.getComputedStyle(element, ""); + + var groups = []; + + for (var groupName in styleGroups) + { + // TODO: xxxpedro i18n $STR + //var title = $STR("StyleGroup-" + groupName); + var title = styleGroupTitles[groupName]; + var group = {title: title, props: []}; + groups.push(group); + + var props = styleGroups[groupName]; + for (var i = 0; i < props.length; ++i) + { + var propName = props[i]; + var propValue = style.getPropertyValue ? + style.getPropertyValue(propName) : + ""+style[toCamelCase(propName)]; + + if (propValue === undefined || propValue === null) + continue; + + propValue = stripUnits(rgbToHex(propValue)); + if (propValue) + group.props.push({name: propName, value: propValue}); + } + } + + var result = this.template.computedTag.replace({groups: groups}, this.panelNode); + //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "computed", + title: "Computed", + parentPanel: "HTML", + order: 1, + + updateView: function(element) + { + this.updateComputedView(element); + }, + + getOptionsMenuItems: function() + { + return [ + {label: "Refresh", command: bind(this.refresh, this) } + ]; + } +}); + +// ************************************************************************************************ +// CSSEditor + +function CSSEditor(doc) +{ + this.initializeInline(doc); +} + +CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var rule = Firebug.getRepObject(target); + var emptyProp = + { + // TODO: xxxpedro - uses charCode(255) to force the element being rendered, + // allowing webkit to get the correct position of the property name "span", + // when inserting a new CSS rule? + name: "", + value: "", + important: "" + }; + + if (insertWhere == "before") + return CSSPropTag.tag.insertBefore({prop: emptyProp, rule: rule}, target); + else + return CSSPropTag.tag.insertAfter({prop: emptyProp, rule: rule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + // We need to check the value first in order to avoid a problem in IE8 + // See Issue 3038: Empty (null) styles when adding CSS styles in Firebug Lite + if (!value) return; + + target.innerHTML = escapeForCss(value); + + var row = getAncestorByClass(target, "cssProp"); + if (hasClass(row, "disabledStyle")) + toggleClass(row, "disabledStyle"); + + var rule = Firebug.getRepObject(target); + + if (hasClass(target, "cssPropName")) + { + if (value && previousValue != value) // name of property has changed. + { + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + var parsedValue = parsePriority(propValue); + + if (propValue && propValue != "undefined") { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSEditor.saveEdit : "+previousValue+"->"+value+" = "+propValue+"\n"); + if (previousValue) + Firebug.CSSModule.removeProperty(rule, previousValue); + Firebug.CSSModule.setProperty(rule, value, parsedValue.value, parsedValue.priority); + } + } + else if (!value) // name of the property has been deleted, so remove the property. + Firebug.CSSModule.removeProperty(rule, previousValue); + } + else if (getAncestorByClass(target, "cssPropValue")) + { + var propName = getChildByClass(row, "cssPropName")[textContent]; + var propValue = getChildByClass(row, "cssPropValue")[textContent]; + + if (FBTrace.DBG_CSS) + { + FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName +" = "+propValue+"\n"); + // FBTrace.sysout("CSSEditor.saveEdit BEFORE style:",style); + } + + if (value && value != "null") + { + var parsedValue = parsePriority(value); + Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority); + } + else if (previousValue && previousValue != "null") + Firebug.CSSModule.removeProperty(rule, propName); + } + + this.panel.markChange(this.panel.name == "stylesheet"); + }, + + advanceToNext: function(target, charCode) + { + if (charCode == 58 /*":"*/ && hasClass(target, "cssPropName")) + return true; + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + getAutoCompleteRange: function(value, offset) + { + if (hasClass(this.target, "cssPropName")) + return {start: 0, end: value.length-1}; + else + return parseCSSValue(value, offset); + }, + + getAutoCompleteList: function(preExpr, expr, postExpr) + { + if (hasClass(this.target, "cssPropName")) + { + return getCSSPropertyNames(); + } + else + { + var row = getAncestorByClass(this.target, "cssProp"); + var propName = getChildByClass(row, "cssPropName")[textContent]; + return getCSSKeywordsByProperty(propName); + } + } +}); + +//************************************************************************************************ +//CSSRuleEditor + +function CSSRuleEditor(doc) +{ + this.initializeInline(doc); + this.completeAsYouType = false; +} +CSSRuleEditor.uniquifier = 0; +CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype, +{ + insertNewRow: function(target, insertWhere) + { + var emptyRule = { + selector: "", + id: "", + props: [], + isSelectorEditable: true + }; + + if (insertWhere == "before") + return CSSStyleRuleTag.tag.insertBefore({rule: emptyRule}, target); + else + return CSSStyleRuleTag.tag.insertAfter({rule: emptyRule}, target); + }, + + saveEdit: function(target, value, previousValue) + { + if (FBTrace.DBG_CSS) + FBTrace.sysout("CSSRuleEditor.saveEdit: '" + value + "' '" + previousValue + "'", target); + + target.innerHTML = escapeForCss(value); + + if (value === previousValue) return; + + var row = getAncestorByClass(target, "cssRule"); + var styleSheet = this.panel.location; + styleSheet = styleSheet.editStyleSheet ? styleSheet.editStyleSheet.sheet : styleSheet; + + var cssRules = styleSheet.cssRules; + var rule = Firebug.getRepObject(target), oldRule = rule; + var ruleIndex = cssRules.length; + if (rule || Firebug.getRepObject(row.nextSibling)) + { + var searchRule = rule || Firebug.getRepObject(row.nextSibling); + for (ruleIndex=0; ruleIndex b.name ? 1 : -1; + }); +} + +function getTopmostRuleLine(panelNode) +{ + for (var child = panelNode.firstChild; child; child = child.nextSibling) + { + if (child.offsetTop+child.offsetHeight > panelNode.scrollTop) + { + var rule = child.repObject; + if (rule) + return { + line: domUtils.getRuleLine(rule), + offset: panelNode.scrollTop-child.offsetTop + }; + } + } + return 0; +} + +function getStyleSheetCSS(sheet, context) +{ + if (sheet.ownerNode instanceof HTMLStyleElement) + return sheet.ownerNode.innerHTML; + else + return context.sourceCache.load(sheet.href).join(""); +} + +function getStyleSheetOwnerNode(sheet) { + for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet); + + return sheet.ownerNode; +} + +function scrollSelectionIntoView(panel) +{ + var selCon = getSelectionController(panel); + selCon.scrollSelectionIntoView( + nsISelectionController.SELECTION_NORMAL, + nsISelectionController.SELECTION_FOCUS_REGION, true); +} + +function getSelectionController(panel) +{ + var browser = Firebug.chrome.getPanelBrowser(panel); + return browser.docShell.QueryInterface(nsIInterfaceRequestor) + .getInterface(nsISelectionDisplay) + .QueryInterface(nsISelectionController); +} + +// ************************************************************************************************ + +Firebug.registerModule(Firebug.CSSModule); +Firebug.registerPanel(Firebug.CSSStyleSheetPanel); +Firebug.registerPanel(CSSElementPanel); +Firebug.registerPanel(CSSComputedElementPanel); + +// ************************************************************************************************ + +}}); + + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Script Module + +Firebug.Script = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Script") : null; + }, + + selectSourceCode: function(index) + { + this.getPanel().selectSourceCode(index); + } +}); + +Firebug.registerModule(Firebug.Script); + + +// ************************************************************************************************ +// Script Panel + +function ScriptPanel(){}; + +ScriptPanel.prototype = extend(Firebug.Panel, +{ + name: "Script", + title: "Script", + + selectIndex: 0, // index of the current selectNode's option + sourceIndex: -1, // index of the script node, based in doc.getElementsByTagName("script") + + options: { + hasToolButtons: true + }, + + create: function() + { + Firebug.Panel.create.apply(this, arguments); + + this.onChangeSelect = bind(this.onChangeSelect, this); + + var doc = Firebug.browser.document; + var scripts = doc.getElementsByTagName("script"); + var selectNode = this.selectNode = createElement("select"); + + for(var i=0, script; script=scripts[i]; i++) + { + // Don't show Firebug Lite source code in the list of options + if (Firebug.ignoreFirebugElements && script.getAttribute("firebugIgnore")) + continue; + + var fileName = getFileName(script.src) || getFileName(doc.location.href); + var option = createElement("option", {value:i}); + + option.appendChild(Firebug.chrome.document.createTextNode(fileName)); + selectNode.appendChild(option); + }; + + this.toolButtonsNode.appendChild(selectNode); + }, + + initialize: function() + { + // we must render the code first, so the persistent state can be restore + this.selectSourceCode(this.selectIndex); + + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.selectNode, "change", this.onChangeSelect); + }, + + shutdown: function() + { + removeEvent(this.selectNode, "change", this.onChangeSelect); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + detach: function(oldChrome, newChrome) + { + Firebug.Panel.detach.apply(this, arguments); + + var oldPanel = oldChrome.getPanel("Script"); + var index = oldPanel.selectIndex; + + this.selectNode.selectedIndex = index; + this.selectIndex = index; + this.sourceIndex = -1; + }, + + onChangeSelect: function(event) + { + var select = this.selectNode; + + this.selectIndex = select.selectedIndex; + + var option = select.options[select.selectedIndex]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + selectSourceCode: function(index) + { + var select = this.selectNode; + select.selectedIndex = index; + + var option = select.options[index]; + if (!option) + return; + + var selectedSourceIndex = parseInt(option.value); + + this.renderSourceCode(selectedSourceIndex); + }, + + renderSourceCode: function(index) + { + if (this.sourceIndex != index) + { + var renderProcess = function renderProcess(src) + { + var html = [], + hl = 0; + + src = isIE && !isExternal ? + src+'\n' : // IE put an extra line when reading source of local resources + '\n'+src; + + // find the number of lines of code + src = src.replace(/\n\r|\r\n/g, "\n"); + var match = src.match(/[\n]/g); + var lines=match ? match.length : 0; + + // render the full source code + line numbers html + html[hl++] = '
      ';
      +                html[hl++] = escapeHTML(src);
      +                html[hl++] = '
      '; + + // render the line number divs + for(var l=1, lines; l<=lines; l++) + { + html[hl++] = '
      '; + html[hl++] = l; + html[hl++] = '
      '; + } + + html[hl++] = '
      '; + + updatePanel(html); + }; + + var updatePanel = function(html) + { + self.panelNode.innerHTML = html.join(""); + + // IE needs this timeout, otherwise the panel won't scroll + setTimeout(function(){ + self.synchronizeUI(); + },0); + }; + + var onFailure = function() + { + FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, self.panelNode); + }; + + var self = this; + + var doc = Firebug.browser.document; + var script = doc.getElementsByTagName("script")[index]; + var url = getScriptURL(script); + var isExternal = url && url != doc.location.href; + + try + { + if (isExternal) + { + Ajax.request({url: url, onSuccess: renderProcess, onFailure: onFailure}); + } + else + { + var src = script.innerHTML; + renderProcess(src); + } + } + catch(e) + { + onFailure(); + } + + this.sourceIndex = index; + } + } +}); + +Firebug.registerPanel(ScriptPanel); + + +// ************************************************************************************************ + + +var getScriptURL = function getScriptURL(script) +{ + var reFile = /([^\/\?#]+)(#.+)?$/; + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = Firebug.browser.document; + + var file = reFile.exec(script.src); + + if (file) + { + var fileName = file[1]; + var fileOptions = file[2]; + + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; + + } + // relative path + else + { + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(doc.location.href)[1]; + + // "../some/path" + if (backDir) + { + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; + } + + else if(src.indexOf("/") != -1) + { + // "./some/path" + if(/^\.\/./.test(src)) + { + path += src.substring(2); + } + // "/some/path" + else if(/^\/./.test(src)) + { + var domain = /^(\w+:\/\/[^\/]+)/.exec(path); + path = domain[1] + src; + } + // "some/path" + else + { + path += src; + } + } + } + } + + var m = path && path.match(/([^\/]+)\/$/) || null; + + if (path && m) + { + return path + fileName; + } +}; + +var getFileName = function getFileName(path) +{ + if (!path) return ""; + + var match = path && path.match(/[^\/]+(\?.*)?(#.*)?$/); + + return match && match[0] || path; +}; + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var ElementCache = Firebug.Lite.Cache.Element; + +var insertSliceSize = 18; +var insertInterval = 40; + +var ignoreVars = +{ + "__firebug__": 1, + "eval": 1, + + // We are forced to ignore Java-related variables, because + // trying to access them causes browser freeze + "java": 1, + "sun": 1, + "Packages": 1, + "JavaArray": 1, + "JavaMember": 1, + "JavaObject": 1, + "JavaClass": 1, + "JavaPackage": 1, + "_firebug": 1, + "_FirebugConsole": 1, + "_FirebugCommandLine": 1 +}; + +if (Firebug.ignoreFirebugElements) + ignoreVars[Firebug.Lite.Cache.ID] = 1; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +var memberPanelRep = + isIE6 ? + {"class": "memberLabel $member.type\\Label", href: "javacript:void(0)"} + : + {"class": "memberLabel $member.type\\Label"}; + +var RowTag = + TR({"class": "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren", role : 'presentation', + level: "$member.level"}, + TD({"class": "memberLabelCell", style: "padding-left: $member.indent\\px", role : 'presentation'}, + A(memberPanelRep, + SPAN({}, "$member.name") + ) + ), + TD({"class": "memberValueCell", role : 'presentation'}, + TAG("$member.tag", {object: "$member.value"}) + ) + ); + +var WatchRowTag = + TR({"class": "watchNewRow", level: 0}, + TD({"class": "watchEditCell", colspan: 2}, + DIV({"class": "watchEditBox a11yFocusNoTab", role: "button", 'tabindex' : '0', + 'aria-label' : $STR('press enter to add new watch expression')}, + $STR("NewWatch") + ) + ) + ); + +var SizerRow = + TR({role : 'presentation'}, + TD({width: "30%"}), + TD({width: "70%"}) + ); + +var domTableClass = isIElt8 ? "domTable domTableIE" : "domTable"; +var DirTablePlate = domplate(Firebug.Rep, +{ + tag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, onclick: "$onClick", role :"tree"}, + TBODY({role: 'presentation'}, + SizerRow, + FOR("member", "$object|memberIterator", RowTag) + ) + ), + + watchTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow, + WatchRowTag + ) + ), + + tableTag: + TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, + _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'}, + TBODY({role : 'presentation'}, + SizerRow + ) + ), + + rowTag: + FOR("member", "$members", RowTag), + + memberIterator: function(object, level) + { + return getMembers(object, level); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + if (!isLeftClick(event)) + return; + + var target = event.target || event.srcElement; + + var row = getAncestorByClass(target, "memberRow"); + var label = getAncestorByClass(target, "memberLabel"); + if (label && hasClass(row, "hasChildren")) + { + var row = label.parentNode.parentNode; + this.toggleRow(row); + } + else + { + var object = Firebug.getRepObject(target); + if (typeof(object) == "function") + { + Firebug.chrome.select(object, "script"); + cancelEvent(event); + } + else if (event.detail == 2 && !object) + { + var panel = row.parentNode.parentNode.domPanel; + if (panel) + { + var rowValue = panel.getRowPropertyValue(row); + if (typeof(rowValue) == "boolean") + panel.setPropertyValue(row, !rowValue); + else + panel.editProperty(row); + + cancelEvent(event); + } + } + } + + return false; + }, + + toggleRow: function(row) + { + var level = parseInt(row.getAttribute("level")); + var toggles = row.parentNode.parentNode.toggles; + + if (hasClass(row, "opened")) + { + removeClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Remove the path from the toggle tree + for (var i = 0; i < path.length; ++i) + { + if (i == path.length-1) + delete toggles[path[i]]; + else + toggles = toggles[path[i]]; + } + } + + var rowTag = this.rowTag; + var tbody = row.parentNode; + + setTimeout(function() + { + for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling) + { + if (parseInt(firstRow.getAttribute("level")) <= level) + break; + + tbody.removeChild(firstRow); + } + }, row.insertTimeout ? row.insertTimeout : 0); + } + else + { + setClass(row, "opened"); + + if (toggles) + { + var path = getPath(row); + + // Mark the path in the toggle tree + for (var i = 0; i < path.length; ++i) + { + var name = path[i]; + if (toggles.hasOwnProperty(name)) + toggles = toggles[name]; + else + toggles = toggles[name] = {}; + } + } + + var value = row.lastChild.firstChild.repObject; + var members = getMembers(value, level+1); + + var rowTag = this.rowTag; + var lastRow = row; + + var delay = 0; + //var setSize = members.length; + //var rowCount = 1; + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + setTimeout(function() + { + if (lastRow.parentNode) + { + var result = rowTag.insertRows({members: slice}, lastRow); + lastRow = result[1]; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [null, result, rowCount, setSize]); + //rowCount += insertSliceSize; + } + if (isLast) + row.removeAttribute("insertTimeout"); + }, delay); + } + + delay += insertInterval; + } + + row.insertTimeout = delay; + } + } +}); + + + +// ************************************************************************************************ + +Firebug.DOMBasePanel = function() {} + +Firebug.DOMBasePanel.prototype = extend(Firebug.Panel, +{ + tag: DirTablePlate.tableTag, + + getRealObject: function(object) + { + // TODO: Move this to some global location + // TODO: Unwrapping should be centralized rather than sprinkling it around ad hoc. + // TODO: We might be able to make this check more authoritative with QueryInterface. + if (!object) return object; + if (object.wrappedJSObject) return object.wrappedJSObject; + return object; + }, + + rebuild: function(update, scrollTop) + { + //dispatch([Firebug.A11yModel], 'onBeforeDomUpdateSelection', [this]); + var members = getMembers(this.selection); + expandMembers(members, this.toggles, 0, 0); + + this.showMembers(members, update, scrollTop); + + //TODO: xxxpedro statusbar + if (!this.parentPanel) + updateStatusBar(this); + }, + + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + while (members.length) + { + with({slice: members.splice(0, insertSliceSize), isLast: !members.length}) + { + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!tbody.lastChild) return; + + result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //rowCount += insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop) + panelNode.scrollTop = priorScrollTop; + + + // enable to measure rendering performance + //if (isLast) alert(new Date().getTime() - renderStart + "ms"); + + + }, delay)); + + delay += insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + + /* + // new + showMembers: function(members, update, scrollTop) + { + // If we are still in the midst of inserting rows, cancel all pending + // insertions here - this is a big speedup when stepping in the debugger + if (this.timeouts) + { + for (var i = 0; i < this.timeouts.length; ++i) + this.context.clearTimeout(this.timeouts[i]); + delete this.timeouts; + } + + if (!members.length) + return this.showEmptyMembers(); + + var panelNode = this.panelNode; + var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop; + + // If we are asked to "update" the current view, then build the new table + // offscreen and swap it in when it's done + var offscreen = update && panelNode.firstChild; + var dest = offscreen ? panelNode.ownerDocument : panelNode; + + var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest); + var tbody = table.lastChild; + var rowTag = DirTablePlate.rowTag; + + // Insert the first slice immediately + //var slice = members.splice(0, insertSliceSize); + //var result = rowTag.insertRows({members: slice}, tbody.lastChild); + + //var setSize = members.length; + //var rowCount = 1; + + var panel = this; + var result; + + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + var timeouts = []; + + var delay = 0; + var _insertSliceSize = insertSliceSize; + var _insertInterval = insertInterval; + + // enable to measure rendering performance + var renderStart = new Date().getTime(); + var lastSkip = renderStart, now; + + while (members.length) + { + with({slice: members.splice(0, _insertSliceSize), isLast: !members.length}) + { + var _tbody = tbody; + var _rowTag = rowTag; + var _panelNode = panelNode; + var _priorScrollTop = priorScrollTop; + + timeouts.push(this.context.setTimeout(function() + { + // TODO: xxxpedro can this be a timing error related to the + // "iteration number" approach insted of "duration time"? + // avoid error in IE8 + if (!_tbody.lastChild) return; + + result = _rowTag.insertRows({members: slice}, _tbody.lastChild); + + //rowCount += _insertSliceSize; + //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]); + + if ((_panelNode.scrollHeight + _panelNode.offsetHeight) >= _priorScrollTop) + _panelNode.scrollTop = _priorScrollTop; + + + // enable to measure rendering performance + //alert("gap: " + (new Date().getTime() - lastSkip)); + //lastSkip = new Date().getTime(); + + //if (isLast) alert("new: " + (new Date().getTime() - renderStart) + "ms"); + + }, delay)); + + delay += _insertInterval; + } + } + + if (offscreen) + { + timeouts.push(this.context.setTimeout(function() + { + if (panelNode.firstChild) + panelNode.replaceChild(table, panelNode.firstChild); + else + panelNode.appendChild(table); + + // Scroll back to where we were before + panelNode.scrollTop = priorScrollTop; + }, delay)); + } + else + { + timeouts.push(this.context.setTimeout(function() + { + panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop; + }, delay)); + } + this.timeouts = timeouts; + }, + /**/ + + showEmptyMembers: function() + { + FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode); + }, + + findPathObject: function(object) + { + var pathIndex = -1; + for (var i = 0; i < this.objectPath.length; ++i) + { + // IE needs === instead of == or otherwise some objects will + // be considered equal to different objects, returning the + // wrong index of the objectPath array + if (this.getPathObject(i) === object) + return i; + } + + return -1; + }, + + getPathObject: function(index) + { + var object = this.objectPath[index]; + + if (object instanceof Property) + return object.getObject(); + else + return object; + }, + + getRowObject: function(row) + { + var object = getRowOwnerObject(row); + return object ? object : this.selection; + }, + + getRowPropertyValue: function(row) + { + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object) + { + var propName = getRowName(row); + + if (object instanceof jsdIStackFrame) + return Firebug.Debugger.evaluate(propName, this.context); + else + return object[propName]; + } + }, + /* + copyProperty: function(row) + { + var value = this.getRowPropertyValue(row); + copyToClipboard(value); + }, + + editProperty: function(row, editValue) + { + if (hasClass(row, "watchNewRow")) + { + if (this.context.stopped) + Firebug.Editor.startEditing(row, ""); + else if (Firebug.Console.isAlwaysEnabled()) // not stopped in debugger, need command line + { + if (Firebug.CommandLine.onCommandLineFocus()) + Firebug.Editor.startEditing(row, ""); + else + row.innerHTML = $STR("warning.Command line blocked?"); + } + else + row.innerHTML = $STR("warning.Console must be enabled"); + } + else if (hasClass(row, "watchRow")) + Firebug.Editor.startEditing(row, getRowName(row)); + else + { + var object = this.getRowObject(row); + this.context.thisValue = object; + + if (!editValue) + { + var propValue = this.getRowPropertyValue(row); + + var type = typeof(propValue); + if (type == "undefined" || type == "number" || type == "boolean") + editValue = propValue; + else if (type == "string") + editValue = "\"" + escapeJS(propValue) + "\""; + else if (propValue == null) + editValue = "null"; + else if (object instanceof Window || object instanceof jsdIStackFrame) + editValue = getRowName(row); + else + editValue = "this." + getRowName(row); + } + + + Firebug.Editor.startEditing(row, editValue); + } + }, + + deleteProperty: function(row) + { + if (hasClass(row, "watchRow")) + this.deleteWatch(row); + else + { + var object = getRowOwnerObject(row); + if (!object) + object = this.selection; + object = this.getRealObject(object); + + if (object) + { + var name = getRowName(row); + try + { + delete object[name]; + } + catch (exc) + { + return; + } + + this.rebuild(true); + this.markChange(); + } + } + }, + + setPropertyValue: function(row, value) // value must be string + { + if(FBTrace.DBG_DOM) + { + FBTrace.sysout("row: "+row); + FBTrace.sysout("value: "+value+" type "+typeof(value), value); + } + + var name = getRowName(row); + if (name == "this") + return; + + var object = this.getRowObject(row); + object = this.getRealObject(object); + if (object && !(object instanceof jsdIStackFrame)) + { + // unwrappedJSObject.property = unwrappedJSObject + Firebug.CommandLine.evaluate(value, this.context, object, this.context.getGlobalScope(), + function success(result, context) + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate success object["+name+"]="+result+" type "+typeof(result), result); + object[name] = result; + }, + function failed(exc, context) + { + try + { + if (FBTrace.DBG_DOM) + FBTrace.sysout("setPropertyValue evaluate failed with exc:"+exc+" object["+name+"]="+value+" type "+typeof(value), exc); + // If the value doesn't parse, then just store it as a string. Some users will + // not realize they're supposed to enter a JavaScript expression and just type + // literal text + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + ); + } + else if (this.context.stopped) + { + try + { + Firebug.CommandLine.evaluate(name+"="+value, this.context); + } + catch (exc) + { + try + { + // See catch block above... + object[name] = String(value); // unwrappedJSobject.property = string + } + catch (exc) + { + return; + } + } + } + + this.rebuild(true); + this.markChange(); + }, + + highlightRow: function(row) + { + if (this.highlightedRow) + cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context); + + this.highlightedRow = row; + + if (row) + setClassTimed(row, "jumpHighlight", this.context); + },/**/ + + onMouseMove: function(event) + { + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink-element"); + object = object ? object.repObject : null; + + if(object && instanceOf(object, "Element") && object.nodeType == 1) + { + if(object != lastHighlightedObject) + { + Firebug.Inspector.drawBoxModel(object); + object = lastHighlightedObject; + } + } + else + Firebug.Inspector.hideBoxModel(); + + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + create: function() + { + // TODO: xxxpedro + this.context = Firebug.browser; + + this.objectPath = []; + this.propertyPath = []; + this.viewPath = []; + this.pathIndex = -1; + this.toggles = {}; + + Firebug.Panel.create.apply(this, arguments); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + addEvent(this.panelNode, "mousemove", this.onMouseMove); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "mousemove", this.onMouseMove); + + Firebug.Panel.shutdown.apply(this, arguments); + }, + + /* + destroy: function(state) + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + + if (this.pathIndex) + state.pathIndex = this.pathIndex; + if (this.viewPath) + state.viewPath = this.viewPath; + if (this.propertyPath) + state.propertyPath = this.propertyPath; + + if (this.propertyPath.length > 0 && !this.propertyPath[1]) + state.firstSelection = persistObject(this.getPathObject(1), this.context); + + Firebug.Panel.destroy.apply(this, arguments); + }, + /**/ + + ishow: function(state) + { + if (this.context.loaded && !this.selection) + { + if (!state) + { + this.select(null); + return; + } + if (state.viewPath) + this.viewPath = state.viewPath; + if (state.propertyPath) + this.propertyPath = state.propertyPath; + + var defaultObject = this.getDefaultSelection(this.context); + var selectObject = defaultObject; + + if (state.firstSelection) + { + var restored = state.firstSelection(this.context); + if (restored) + { + selectObject = restored; + this.objectPath = [defaultObject, restored]; + } + else + this.objectPath = [defaultObject]; + } + else + this.objectPath = [defaultObject]; + + if (this.propertyPath.length > 1) + { + for (var i = 1; i < this.propertyPath.length; ++i) + { + var name = this.propertyPath[i]; + if (!name) + continue; + + var object = selectObject; + try + { + selectObject = object[name]; + } + catch (exc) + { + selectObject = null; + } + + if (selectObject) + { + this.objectPath.push(new Property(object, name)); + } + else + { + // If we can't access a property, just stop + this.viewPath.splice(i); + this.propertyPath.splice(i); + this.objectPath.splice(i); + selectObject = this.getPathObject(this.objectPath.length-1); + break; + } + } + } + + var selection = state.pathIndex <= this.objectPath.length-1 + ? this.getPathObject(state.pathIndex) + : this.getPathObject(this.objectPath.length-1); + + this.select(selection); + } + }, + /* + hide: function() + { + var view = this.viewPath[this.pathIndex]; + if (view && this.panelNode.scrollTop) + view.scrollTop = this.panelNode.scrollTop; + }, + /**/ + + supportsObject: function(object) + { + if (object == null) + return 1000; + + if (typeof(object) == "undefined") + return 1000; + else if (object instanceof SourceLink) + return 0; + else + return 1; // just agree to support everything but not agressively. + }, + + refresh: function() + { + this.rebuild(true); + }, + + updateSelection: function(object) + { + var previousIndex = this.pathIndex; + var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex]; + + var newPath = this.pathToAppend; + delete this.pathToAppend; + + var pathIndex = this.findPathObject(object); + if (newPath || pathIndex == -1) + { + this.toggles = {}; + + if (newPath) + { + // Remove everything after the point where we are inserting, so we + // essentially replace it with the new path + if (previousView) + { + if (this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + var start = previousIndex + 1, + // Opera needs the length argument in splice(), otherwise + // it will consider that only one element should be removed + length = this.objectPath.length - start; + + this.objectPath.splice(start, length); + this.propertyPath.splice(start, length); + this.viewPath.splice(start, length); + } + + var value = this.getPathObject(previousIndex); + if (!value) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection no pathObject for "+previousIndex+"\n"); + return; + } + + for (var i = 0, length = newPath.length; i < length; ++i) + { + var name = newPath[i]; + var object = value; + try + { + value = value[name]; + } + catch(exc) + { + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("dom.updateSelection FAILS at path_i="+i+" for name:"+name+"\n"); + return; + } + + ++this.pathIndex; + this.objectPath.push(new Property(object, name)); + this.propertyPath.push(name); + this.viewPath.push({toggles: this.toggles, scrollTop: 0}); + } + } + else + { + this.toggles = {}; + + var win = Firebug.browser.window; + //var win = this.context.getGlobalScope(); + if (object === win) + { + this.pathIndex = 0; + this.objectPath = [win]; + this.propertyPath = [null]; + this.viewPath = [{toggles: this.toggles, scrollTop: 0}]; + } + else + { + this.pathIndex = 1; + this.objectPath = [win, object]; + this.propertyPath = [null, null]; + this.viewPath = [ + {toggles: {}, scrollTop: 0}, + {toggles: this.toggles, scrollTop: 0} + ]; + } + } + + this.panelNode.scrollTop = 0; + this.rebuild(); + } + else + { + this.pathIndex = pathIndex; + + var view = this.viewPath[pathIndex]; + this.toggles = view.toggles; + + // Persist the current scroll location + if (previousView && this.panelNode.scrollTop) + previousView.scrollTop = this.panelNode.scrollTop; + + this.rebuild(false, view.scrollTop); + } + }, + + getObjectPath: function(object) + { + return this.objectPath; + }, + + getDefaultSelection: function() + { + return Firebug.browser.window; + //return this.context.getGlobalScope(); + }/*, + + updateOption: function(name, value) + { + const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1, + showDOMFuncs: 1, showDOMConstants: 1}; + if ( optionMap.hasOwnProperty(name) ) + this.rebuild(true); + }, + + getOptionsMenuItems: function() + { + return [ + optionMenu("ShowUserProps", "showUserProps"), + optionMenu("ShowUserFuncs", "showUserFuncs"), + optionMenu("ShowDOMProps", "showDOMProps"), + optionMenu("ShowDOMFuncs", "showDOMFuncs"), + optionMenu("ShowDOMConstants", "showDOMConstants"), + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ]; + }, + + getContextMenuItems: function(object, target) + { + var row = getAncestorByClass(target, "memberRow"); + + var items = []; + + if (row) + { + var rowName = getRowName(row); + var rowObject = this.getRowObject(row); + var rowValue = this.getRowPropertyValue(row); + + var isWatch = hasClass(row, "watchRow"); + var isStackFrame = rowObject instanceof jsdIStackFrame; + + if (typeof(rowValue) == "string" || typeof(rowValue) == "number") + { + // Functions already have a copy item in their context menu + items.push( + "-", + {label: "CopyValue", + command: bindFixed(this.copyProperty, this, row) } + ); + } + + items.push( + "-", + {label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"), + command: bindFixed(this.editProperty, this, row) } + ); + + if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName))) + { + items.push( + {label: isWatch ? "DeleteWatch" : "DeleteProperty", + command: bindFixed(this.deleteProperty, this, row) } + ); + } + } + + items.push( + "-", + {label: "Refresh", command: bindFixed(this.rebuild, this, true) } + ); + + return items; + }, + + getEditor: function(target, value) + { + if (!this.editor) + this.editor = new DOMEditor(this.document); + + return this.editor; + }/**/ +}); + +// ************************************************************************************************ + +// TODO: xxxpedro statusbar +var updateStatusBar = function(panel) +{ + var path = panel.propertyPath; + var index = panel.pathIndex; + + var r = []; + + for (var i=0, l=path.length; i'); + r.push(i==0 ? "window" : path[i] || "Object"); + r.push('
      '); + + if(i < l-1) + r.push('>'); + } + panel.statusBarNode.innerHTML = r.join(""); +}; + + +var DOMMainPanel = Firebug.DOMPanel = function () {}; + +Firebug.DOMPanel.DirTable = DirTablePlate; + +DOMMainPanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + onClickStatusBar: function(event) + { + var target = event.srcElement || event.target; + var element = getAncestorByClass(target, "fbHover"); + + if(element) + { + var pathIndex = element.getAttribute("pathIndex"); + + if(pathIndex) + { + this.select(this.getPathObject(pathIndex)); + } + } + }, + + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + this.select(target.repObject, true); + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOM", + title: "DOM", + searchable: true, + statusSeparator: ">", + + options: { + hasToolButtons: true, + hasStatusBar: true + }, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + + //TODO: xxxpedro + this.onClickStatusBar = bind(this.onClickStatusBar, this); + + this.panelNode.style.padding = "0 1px"; + }, + + initialize: function(oldPanelNode) + { + //this.panelNode.addEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'console']); + + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro dom + this.ishow(); + + //TODO: xxxpedro + addEvent(this.statusBarNode, "click", this.onClickStatusBar); + }, + + shutdown: function() + { + //this.panelNode.removeEventListener("click", this.onClick, false); + //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'console']); + + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }/*, + + search: function(text, reverse) + { + if (!text) + { + delete this.currentSearch; + this.highlightRow(null); + return false; + } + + var row; + if (this.currentSearch && text == this.currentSearch.text) + row = this.currentSearch.findNext(true, undefined, reverse, Firebug.searchCaseSensitive); + else + { + function findRow(node) { return getAncestorByClass(node, "memberRow"); } + this.currentSearch = new TextSearch(this.panelNode, findRow); + row = this.currentSearch.find(text, reverse, Firebug.searchCaseSensitive); + } + + if (row) + { + var sel = this.document.defaultView.getSelection(); + sel.removeAllRanges(); + sel.addRange(this.currentSearch.range); + + scrollIntoCenterView(row, this.panelNode); + + this.highlightRow(row); + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, row]); + return true; + } + else + { + dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, null]); + return false; + } + }/**/ +}); + +Firebug.registerPanel(DOMMainPanel); + + +// ************************************************************************************************ + + + +// ************************************************************************************************ +// Local Helpers + +var getMembers = function getMembers(object, level) // we expect object to be user-level object wrapped in security blanket +{ + if (!level) + level = 0; + + var ordinals = [], userProps = [], userClasses = [], userFuncs = [], + domProps = [], domFuncs = [], domConstants = []; + + try + { + var domMembers = getDOMMembers(object); + //var domMembers = {}; // TODO: xxxpedro + //var domConstantMap = {}; // TODO: xxxpedro + + if (object.wrappedJSObject) + var insecureObject = object.wrappedJSObject; + else + var insecureObject = object; + + // IE function prototype is not listed in (for..in) + if (isIE && isFunction(object)) + addMember("user", userProps, "prototype", object.prototype, level); + + for (var name in insecureObject) // enumeration is safe + { + if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined. + continue; + + var val; + try + { + val = insecureObject[name]; // getter is safe + } + catch (exc) + { + // Sometimes we get exceptions trying to access certain members + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers cannot access "+name, exc); + } + + var ordinal = parseInt(name); + if (ordinal || ordinal == 0) + { + addMember("ordinal", ordinals, name, val, level); + } + else if (isFunction(val)) + { + if (isClassFunction(val) && !(name in domMembers)) + addMember("userClass", userClasses, name, val, level); + else if (name in domMembers) + addMember("domFunction", domFuncs, name, val, level, domMembers[name]); + else + addMember("userFunction", userFuncs, name, val, level); + } + else + { + //TODO: xxxpedro + /* + var getterFunction = insecureObject.__lookupGetter__(name), + setterFunction = insecureObject.__lookupSetter__(name), + prefix = ""; + + if(getterFunction && !setterFunction) + prefix = "get "; + /**/ + + var prefix = ""; + + if (name in domMembers && !(name in domConstantMap)) + addMember("dom", domProps, (prefix+name), val, level, domMembers[name]); + else if (name in domConstantMap) + addMember("dom", domConstants, (prefix+name), val, level); + else + addMember("user", userProps, (prefix+name), val, level); + } + } + } + catch (exc) + { + // Sometimes we get exceptions just from trying to iterate the members + // of certain objects, like StorageList, but don't let that gum up the works + throw exc; + if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM) + FBTrace.sysout("dom.getMembers FAILS: ", exc); + //throw exc; + } + + function sortName(a, b) { return a.name > b.name ? 1 : -1; } + function sortOrder(a, b) { return a.order > b.order ? 1 : -1; } + + var members = []; + + members.push.apply(members, ordinals); + + Firebug.showUserProps = true; // TODO: xxxpedro + Firebug.showUserFuncs = true; // TODO: xxxpedro + Firebug.showDOMProps = true; + Firebug.showDOMFuncs = true; + Firebug.showDOMConstants = true; + + if (Firebug.showUserProps) + { + userProps.sort(sortName); + members.push.apply(members, userProps); + } + + if (Firebug.showUserFuncs) + { + userClasses.sort(sortName); + members.push.apply(members, userClasses); + + userFuncs.sort(sortName); + members.push.apply(members, userFuncs); + } + + if (Firebug.showDOMProps) + { + domProps.sort(sortName); + members.push.apply(members, domProps); + } + + if (Firebug.showDOMFuncs) + { + domFuncs.sort(sortName); + members.push.apply(members, domFuncs); + } + + if (Firebug.showDOMConstants) + members.push.apply(members, domConstants); + + return members; +} + +function expandMembers(members, toggles, offset, level) // recursion starts with offset=0, level=0 +{ + var expanded = 0; + for (var i = offset; i < members.length; ++i) + { + var member = members[i]; + if (member.level > level) + break; + + if ( toggles.hasOwnProperty(member.name) ) + { + member.open = "opened"; // member.level <= level && member.name in toggles. + + var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1 + + var args = [i+1, 0]; + args.push.apply(args, newMembers); + members.splice.apply(members, args); + + /* + if (FBTrace.DBG_DOM) + { + FBTrace.sysout("expandMembers member.name", member.name); + FBTrace.sysout("expandMembers toggles", toggles); + FBTrace.sysout("expandMembers toggles[member.name]", toggles[member.name]); + FBTrace.sysout("dom.expandedMembers level: "+level+" member", member); + } + /**/ + + expanded += newMembers.length; + i += newMembers.length + expandMembers(members, toggles[member.name], i+1, level+1); + } + } + + return expanded; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +function isClassFunction(fn) +{ + try + { + for (var name in fn.prototype) + return true; + } catch (exc) {} + return false; +} + +var hasProperties = function hasProperties(ob) +{ + try + { + for (var name in ob) + return true; + } catch (exc) {} + + // IE function prototype is not listed in (for..in) + if (isFunction(ob)) return true; + + return false; +} + +FBL.ErrorCopy = function(message) +{ + this.message = message; +}; + +var addMember = function addMember(type, props, name, value, level, order) +{ + var rep = Firebug.getRep(value); // do this first in case a call to instanceof reveals contents + var tag = rep.shortTag ? rep.shortTag : rep.tag; + + var ErrorCopy = function(){}; //TODO: xxxpedro + + var valueType = typeof(value); + var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) && + (isFunction(value) || (valueType == "object" && value != null) + || (valueType == "string" && value.length > Firebug.stringCropLength)); + + props.push({ + name: name, + value: value, + type: type, + rowClass: "memberRow-"+type, + open: "", + order: order, + level: level, + indent: level*16, + hasChildren: hasChildren, + tag: tag + }); +} + +var getWatchRowIndex = function getWatchRowIndex(row) +{ + var index = -1; + for (; row && hasClass(row, "watchRow"); row = row.previousSibling) + ++index; + return index; +} + +var getRowName = function getRowName(row) +{ + var node = row.firstChild; + return node.textContent ? node.textContent : node.innerText; +} + +var getRowValue = function getRowValue(row) +{ + return row.lastChild.firstChild.repObject; +} + +var getRowOwnerObject = function getRowOwnerObject(row) +{ + var parentRow = getParentRow(row); + if (parentRow) + return getRowValue(parentRow); +} + +var getParentRow = function getParentRow(row) +{ + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + return row; + } +} + +var getPath = function getPath(row) +{ + var name = getRowName(row); + var path = [name]; + + var level = parseInt(row.getAttribute("level"))-1; + for (row = row.previousSibling; row; row = row.previousSibling) + { + if (parseInt(row.getAttribute("level")) == level) + { + var name = getRowName(row); + path.splice(0, 0, name); + + --level; + } + } + + return path; +} + +// ************************************************************************************************ + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +// ************************************************************************************************ +// DOM Module + +Firebug.DOM = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("DOM") : null; + } +}); + +Firebug.registerModule(Firebug.DOM); + + +// ************************************************************************************************ +// DOM Panel + +var lastHighlightedObject; + +function DOMSidePanel(){}; + +DOMSidePanel.prototype = extend(Firebug.DOMBasePanel.prototype, +{ + selectRow: function(row, target) + { + if (!target) + target = row.lastChild.firstChild; + + if (!target || !target.repObject) + return; + + this.pathToAppend = getPath(row); + + // If the object is inside an array, look up its index + var valueBox = row.lastChild.firstChild; + if (hasClass(valueBox, "objectBox-array")) + { + var arrayIndex = FirebugReps.Arr.getItemIndex(target); + this.pathToAppend.push(arrayIndex); + } + + // Make sure we get a fresh status path for the object, since otherwise + // it might find the object in the existing path and not refresh it + //Firebug.chrome.clearStatusPath(); + + var object = target.repObject; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + onClick: function(event) + { + /* + var target = event.srcElement || event.target; + + var object = getAncestorByClass(target, "objectLink"); + object = object ? object.repObject : null; + + if(!object) return; + + if (instanceOf(object, "Element")) + { + Firebug.HTML.selectTreeNode(ElementCache(object)); + } + else + { + Firebug.chrome.selectPanel("DOM"); + Firebug.chrome.getPanel("DOM").select(object, true); + } + /**/ + + + var target = event.srcElement || event.target; + var repNode = Firebug.getRepNode(target); + if (repNode) + { + var row = getAncestorByClass(target, "memberRow"); + if (row) + { + this.selectRow(row, repNode); + cancelEvent(event); + } + } + /**/ + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // extends Panel + + name: "DOMSidePanel", + parentPanel: "HTML", + title: "DOM", + + options: { + hasToolButtons: true + }, + + isInitialized: false, + + create: function() + { + Firebug.DOMBasePanel.prototype.create.apply(this, arguments); + + this.onClick = bind(this.onClick, this); + }, + + initialize: function(){ + Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments); + + addEvent(this.panelNode, "click", this.onClick); + + // TODO: xxxpedro css2 + var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId); + if (selection) + this.select(selection, true); + }, + + shutdown: function() + { + removeEvent(this.panelNode, "click", this.onClick); + + Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments); + }, + + reattach: function(oldChrome) + { + //this.isInitialized = oldChrome.getPanel("DOM").isInitialized; + this.toggles = oldChrome.getPanel("DOMSidePanel").toggles; + } + +}); + +Firebug.registerPanel(DOMSidePanel); + + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.FBTrace = {}; + +(function() { +// ************************************************************************************************ + +var traceOptions = { + DBG_TIMESTAMP: 1, + DBG_INITIALIZE: 1, + DBG_CHROME: 1, + DBG_ERRORS: 1, + DBG_DISPATCH: 1, + DBG_CSS: 1 +}; + +this.module = null; + +this.initialize = function() +{ + if (!this.messageQueue) + this.messageQueue = []; + + for (var name in traceOptions) + this[name] = traceOptions[name]; +}; + +// ************************************************************************************************ +// FBTrace API + +this.sysout = function() +{ + return this.logFormatted(arguments, ""); +}; + +this.dumpProperties = function(title, object) +{ + return this.logFormatted("dumpProperties() not supported.", "warning"); +}; + +this.dumpStack = function() +{ + return this.logFormatted("dumpStack() not supported.", "warning"); +}; + +this.flush = function(module) +{ + this.module = module; + + var queue = this.messageQueue; + this.messageQueue = []; + + for (var i = 0; i < queue.length; ++i) + this.writeMessage(queue[i][0], queue[i][1], queue[i][2]); +}; + +this.getPanel = function() +{ + return this.module ? this.module.getPanel() : null; +}; + +//************************************************************************************************* + +this.logFormatted = function(objects, className) +{ + var html = this.DBG_TIMESTAMP ? [getTimestamp(), " | "] : []; + var length = objects.length; + + for (var i = 0; i < length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + + if (i == 0) + { + html.push(""); + appendText(object, html); + html.push(""); + } + else + appendText(object, html); + } + + return this.logRow(html, className); +}; + +this.logRow = function(message, className) +{ + var panel = this.getPanel(); + + if (panel && panel.panelNode) + this.writeMessage(message, className); + else + { + this.messageQueue.push([message, className]); + } + + return this.LOG_COMMAND; +}; + +this.writeMessage = function(message, className) +{ + var container = this.getPanel().containerNode; + var isScrolledToBottom = + container.scrollTop + container.offsetHeight >= container.scrollHeight; + + this.writeRow.call(this, message, className); + + if (isScrolledToBottom) + container.scrollTop = container.scrollHeight - container.offsetHeight; +}; + +this.appendRow = function(row) +{ + var container = this.getPanel().panelNode; + container.appendChild(row); +}; + +this.writeRow = function(message, className) +{ + var row = this.getPanel().panelNode.ownerDocument.createElement("div"); + row.className = "logRow" + (className ? " logRow-"+className : ""); + row.innerHTML = message.join(""); + this.appendRow(row); +}; + +//************************************************************************************************* + +function appendText(object, html) +{ + html.push(escapeHTML(objectToString(object))); +}; + +function getTimestamp() +{ + var now = new Date(); + var ms = "" + (now.getMilliseconds() / 1000).toFixed(3); + ms = ms.substr(2); + + return now.toLocaleTimeString() + "." + ms; +}; + +//************************************************************************************************* + +var HTMLtoEntity = +{ + "<": "<", + ">": ">", + "&": "&", + "'": "'", + '"': """ +}; + +function replaceChars(ch) +{ + return HTMLtoEntity[ch]; +}; + +function escapeHTML(value) +{ + return (value+"").replace(/[<>&"']/g, replaceChars); +}; + +//************************************************************************************************* + +function objectToString(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +}; + +// ************************************************************************************************ +}).apply(FBL.FBTrace); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// If application isn't in trace mode, the FBTrace panel won't be loaded +if (!Env.Options.enableTrace) return; + +// ************************************************************************************************ +// FBTrace Module + +Firebug.Trace = extend(Firebug.Module, +{ + getPanel: function() + { + return Firebug.chrome ? Firebug.chrome.getPanel("Trace") : null; + }, + + clear: function() + { + this.getPanel().panelNode.innerHTML = ""; + } +}); + +Firebug.registerModule(Firebug.Trace); + + +// ************************************************************************************************ +// FBTrace Panel + +function TracePanel(){}; + +TracePanel.prototype = extend(Firebug.Panel, +{ + name: "Trace", + title: "Trace", + + options: { + hasToolButtons: true, + innerHTMLSync: true + }, + + create: function(){ + Firebug.Panel.create.apply(this, arguments); + + this.clearButton = new Button({ + caption: "Clear", + title: "Clear FBTrace logs", + owner: Firebug.Trace, + onClick: Firebug.Trace.clear + }); + }, + + initialize: function(){ + Firebug.Panel.initialize.apply(this, arguments); + + this.clearButton.initialize(); + } + +}); + +Firebug.registerPanel(TracePanel); + +// ************************************************************************************************ +}}); + +/* See license.txt for terms of usage */ + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +// ************************************************************************************************ +// Globals + +var modules = []; +var panelTypes = []; +var panelTypeMap = {}; + +var parentPanelMap = {}; + + +var registerModule = Firebug.registerModule; +var registerPanel = Firebug.registerPanel; + +// ************************************************************************************************ +append(Firebug, +{ + extend: function(fn) + { + if (Firebug.chrome && Firebug.chrome.addPanel) + { + var namespace = ns(fn); + fn.call(namespace, FBL); + } + else + { + setTimeout(function(){Firebug.extend(fn);},100); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration + + registerModule: function() + { + registerModule.apply(Firebug, arguments); + + modules.push.apply(modules, arguments); + + dispatch(modules, "initialize", []); + + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, + + registerPanel: function() + { + registerPanel.apply(Firebug, arguments); + + panelTypes.push.apply(panelTypes, arguments); + + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + // TODO: xxxpedro investigate why Dev Panel throws an error + if (panelType.prototype.name == "Dev") continue; + + panelTypeMap[panelType.prototype.name] = arguments[i]; + + var parentPanelName = panelType.prototype.parentPanel; + if (parentPanelName) + { + parentPanelMap[parentPanelName] = 1; + } + else + { + var panelName = panelType.prototype.name; + var chrome = Firebug.chrome; + chrome.addPanel(panelName); + + // tab click handler + var onTabClick = function onTabClick() + { + chrome.selectPanel(panelName); + return false; + }; + + chrome.addController([chrome.panelMap[panelName].tabNode, "mousedown", onTabClick]); + } + } + + if (FBTrace.DBG_INITIALIZE) + for (var i = 0; i < arguments.length; ++i) + FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); + } + +}); + + + + +// ************************************************************************************************ +}}); + +FBL.ns(function() { with (FBL) { +// ************************************************************************************************ + +FirebugChrome.Skin = +{ + CSS: '.collapsed{display:none;}[collapsed="true"]{display:none;}#fbCSS{padding:0 !important;}.cssPropDisable{float:left;display:block;width:2em;cursor:default;}.infoTip{z-index:2147483647;position:fixed;padding:2px 3px;border:1px solid #CBE087;background:LightYellow;font-family:Monaco,monospace;color:#000000;display:none;white-space:nowrap;pointer-events:none;}.infoTip[active="true"]{display:block;}.infoTipLoading{width:16px;height:16px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif) no-repeat;}.infoTipImageBox{font-size:11px;min-width:100px;text-align:center;}.infoTipCaption{font-size:11px;font:Monaco,monospace;}.infoTipLoading > .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) no-repeat !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;}#fbPanelBarBox{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}', + HTML: '
       
       
      >>>
      2 errors' +}; + +// ************************************************************************************************ +}}); + +// ************************************************************************************************ +FBL.initialize(); +// ************************************************************************************************ + +})(); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite.js b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite.js new file mode 100755 index 0000000..f9f8484 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/build/firebug-lite.js @@ -0,0 +1,7886 @@ +(function(){ +/************************************************************** + * + * Firebug Lite 1.3.2 + * + * Copyright (c) 2007, Parakey Inc. + * Released under BSD license. + * More information: http://getfirebug.com/firebuglite + * + **************************************************************/ +/* + * CSS selectors powered by: + * + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +var FBL={}; +(function(){var productionDir="http://getfirebug.com/releases/lite/"; +var bookmarkletVersion=4; +var reNotWhitespace=/[^\s]/; +var reSplitFile=/:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; +this.reJavascript=/\s*javascript:\s*(.*)/; +this.reChrome=/chrome:\/\/([^\/]*)\//; +this.reFile=/file:\/\/([^\/]*)\//; +var userAgent=navigator.userAgent.toLowerCase(); +this.isFirefox=/firefox/.test(userAgent); +this.isOpera=/opera/.test(userAgent); +this.isSafari=/webkit/.test(userAgent); +this.isIE=/msie/.test(userAgent)&&!/opera/.test(userAgent); +this.isIE6=/msie 6/i.test(navigator.appVersion); +this.browserVersion=(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1]; +this.isIElt8=this.isIE&&(this.browserVersion-0<8); +this.NS=null; +this.pixelsPerInch=null; +var namespaces=[]; +this.ns=function(fn){var ns={}; +namespaces.push(fn,ns); +return ns +}; +var FBTrace=null; +this.initialize=function(){if(window.firebug&&firebug.firebuglite||window.console&&console.firebuglite){return +}if(FBL.FBTrace){FBTrace=FBL.FBTrace +}else{FBTrace=FBL.FBTrace={} +}FBL.Ajax.initialize(); +var isChromeContext=window.Firebug&&typeof window.Firebug.SharedEnv=="object"; +if(isChromeContext){sharedEnv=window.Firebug.SharedEnv; +delete window.Firebug.SharedEnv; +FBL.Env=sharedEnv; +FBL.Env.isChromeContext=true; +FBTrace.messageQueue=FBL.Env.traceMessageQueue +}else{FBL.NS=document.documentElement.namespaceURI; +FBL.Env.browser=window; +FBL.Env.destroy=destroyEnvironment; +if(document.documentElement.getAttribute("debug")=="true"){FBL.Env.Options.startOpened=true +}findLocation(); +var prefs=eval("("+FBL.readCookie("FirebugLite")+")"); +if(prefs){FBL.Env.Options.startOpened=prefs.startOpened; +FBL.Env.Options.enableTrace=prefs.enableTrace; +FBL.Env.Options.enablePersistent=prefs.enablePersistent; +FBL.Env.Options.disableXHRListener=prefs.disableXHRListener +}if(FBL.isFirefox&&typeof FBL.Env.browser.console=="object"&&FBL.Env.browser.console.firebug&&FBL.Env.Options.disableWhenFirebugActive){return +}}if(FBL.Env.isDebugMode){FBL.Env.browser.FBL=FBL +}this.isQuiksMode=FBL.Env.browser.document.compatMode=="BackCompat"; +this.isIEQuiksMode=this.isIE&&this.isQuiksMode; +this.isIEStantandMode=this.isIE&&!this.isQuiksMode; +this.noFixedPosition=this.isIE6||this.isIEQuiksMode; +if(FBL.Env.Options.enableTrace){FBTrace.initialize() +}if(FBTrace.DBG_INITIALIZE&&isChromeContext){FBTrace.sysout("FBL.initialize - persistent application","initialize chrome context") +}if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("FBL.initialize",namespaces.length/2+" namespaces BEGIN") +}for(var i=0; +i0){path=reLastDir.exec(path)[1] +}path+=backDir[2] +}else{if(src.indexOf("/")!=-1){if(/^\.\/./.test(src)){path+=src.substring(2) +}else{if(/^\/./.test(src)){var domain=/^(\w+:\/\/[^\/]+)/.exec(path); +path=domain[1]+src +}else{path+=src +}}}}}}FBL.Env.isChromeExtension=script&&script.getAttribute("extension")=="Chrome"; +if(FBL.Env.isChromeExtension){path=productionDir; +FBL.Env.bookmarkletOutdated=false; +script={innerHTML:"{showIconWhenHidden:false}"} +}var m=path&&path.match(/([^\/]+)\/$/)||null; +if(path&&m){var Env=FBL.Env; +Env.useLocalSkin=path.indexOf(location.protocol+"//"+location.host+"/")==0; +if(fileName=="firebug-lite-dev.js"){Env.isDevelopmentMode=true; +Env.isDebugMode=true +}else{if(fileName=="firebug-lite-debug.js"){Env.isDebugMode=true +}}if(Env.browser.document.documentElement.getAttribute("debug")=="true"){Env.Options.startOpened=true +}if(fileOptions){var options=fileOptions.split(","); +for(var i=0,length=options.length; +i1){for(var i=0; +i":return">"; +case"&":return"&"; +case"'":return"'"; +case'"':return""" +}return"?" +}return String(value).replace(/[<>&"']/g,replaceChars) +}this.escapeHTML=escapeHTML; +this.cropString=function(text,limit){text=text+""; +if(!limit){var halfLimit=50 +}else{var halfLimit=limit/2 +}if(text.length>limit){return this.escapeNewLines(text.substr(0,halfLimit)+"..."+text.substr(text.length-halfLimit)) +}else{return this.escapeNewLines(text) +}}; +this.isWhitespace=function(text){return !reNotWhitespace.exec(text) +}; +this.splitLines=function(text){var reSplitLines2=/.*(:?\r\n|\n|\r)?/mg; +var lines; +if(text.match){lines=text.match(reSplitLines2) +}else{var str=text+""; +lines=str.match(reSplitLines2) +}lines.pop(); +return lines +}; +this.safeToString=function(ob){if(this.isIE){return ob+"" +}try{if(ob&&"toString" in ob&&typeof ob.toString=="function"){return ob.toString() +}}catch(exc){return ob+"" +}}; +this.hasProperties=function(ob){try{for(var name in ob){return true +}}catch(exc){}return false +}; +var reTrim=/^\s+|\s+$/g; +this.trim=function(s){return s.replace(reTrim,"") +}; +this.emptyFn=function(){}; +this.isVisible=function(elt){return this.getStyle(elt,"visibility")!="hidden"&&(elt.offsetWidth>0||elt.offsetHeight>0||elt.tagName in invisibleTags||elt.namespaceURI=="http://www.w3.org/2000/svg"||elt.namespaceURI=="http://www.w3.org/1998/Math/MathML") +}; +this.collapse=function(elt,collapsed){if(this.isIElt8){if(collapsed){this.setClass(elt,"collapsed") +}else{this.removeClass(elt,"collapsed") +}}else{elt.setAttribute("collapsed",collapsed?"true":"false") +}}; +this.obscure=function(elt,obscured){if(obscured){this.setClass(elt,"obscured") +}else{this.removeClass(elt,"obscured") +}}; +this.hide=function(elt,hidden){elt.style.visibility=hidden?"hidden":"visible" +}; +this.clearNode=function(node){var nodeName=" "+node.nodeName.toLowerCase()+" "; +var ignoreTags=" table tbody thead tfoot th tr td "; +if(this.isIE&&ignoreTags.indexOf(nodeName)!=-1){this.eraseNode(node) +}else{node.innerHTML="" +}}; +this.eraseNode=function(node){while(node.lastChild){node.removeChild(node.lastChild) +}}; +this.iterateWindows=function(win,handler){if(!win||!win.document){return +}handler(win); +if(win==top||!win.frames){return +}for(var i=0; +iscrollParent.offsetHeight){return scrollParent +}}}; +this.isScrolledToBottom=function(element){var onBottom=(element.scrollTop+element.offsetHeight)==element.scrollHeight; +if(FBTrace.DBG_CONSOLE){FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight+" onBottom:"+onBottom) +}return onBottom +}; +this.scrollToBottom=function(element){element.scrollTop=element.scrollHeight; +if(FBTrace.DBG_CONSOLE){FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); +if(element.scrollHeight==element.offsetHeight){FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element,element) +}}return(element.scrollTop==element.scrollHeight) +}; +this.move=function(element,x,y){element.style.left=x+"px"; +element.style.top=y+"px" +}; +this.resize=function(element,w,h){element.style.width=w+"px"; +element.style.height=h+"px" +}; +this.linesIntoCenterView=function(element,scrollBox){if(!scrollBox){scrollBox=this.getOverflowParent(element) +}if(!scrollBox){return +}var offset=this.getClientOffset(element); +var topSpace=offset.y-scrollBox.scrollTop; +var bottomSpace=(scrollBox.scrollTop+scrollBox.clientHeight)-(offset.y+element.offsetHeight); +if(topSpace<0||bottomSpace<0){var split=(scrollBox.clientHeight/2); +var centerY=offset.y-split; +scrollBox.scrollTop=centerY; +topSpace=split; +bottomSpace=split-element.offsetHeight +}return{before:Math.round((topSpace/element.offsetHeight)+0.5),after:Math.round((bottomSpace/element.offsetHeight)+0.5)} +}; +this.scrollIntoCenterView=function(element,scrollBox,notX,notY){if(!element){return +}if(!scrollBox){scrollBox=this.getOverflowParent(element) +}if(!scrollBox){return +}var offset=this.getClientOffset(element); +if(!notY){var topSpace=offset.y-scrollBox.scrollTop; +var bottomSpace=(scrollBox.scrollTop+scrollBox.clientHeight)-(offset.y+element.offsetHeight); +if(topSpace<0||bottomSpace<0){var centerY=offset.y-(scrollBox.clientHeight/2); +scrollBox.scrollTop=centerY +}}if(!notX){var leftSpace=offset.x-scrollBox.scrollLeft; +var rightSpace=(scrollBox.scrollLeft+scrollBox.clientWidth)-(offset.x+element.clientWidth); +if(leftSpace<0||rightSpace<0){var centerX=offset.x-(scrollBox.clientWidth/2); +scrollBox.scrollLeft=centerX +}}if(FBTrace.DBG_SOURCEFILES){FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML) +}}; +var cssKeywordMap=null; +var cssPropNames=null; +var cssColorNames=null; +var imageRules=null; +this.getCSSKeywordsByProperty=function(propName){if(!cssKeywordMap){cssKeywordMap={}; +for(var name in this.cssInfo){var list=[]; +var types=this.cssInfo[name]; +for(var i=0; +i"); +var pureText=true; +for(var child=element.firstChild; +child; +child=child.nextSibling){pureText=pureText&&(child.nodeType==Node.TEXT_NODE) +}if(pureText){html.push(escapeForHtmlEditor(elt.textContent)) +}else{for(var child=elt.firstChild; +child; +child=child.nextSibling){toHTML(child) +}}html.push("") +}else{if(isElementSVG(elt)||isElementMathML(elt)){html.push("/>") +}else{if(self.isSelfClosing(elt)){html.push((isElementXHTML(elt))?"/>":">") +}else{html.push(">") +}}}}else{if(elt.nodeType==Node.TEXT_NODE){html.push(escapeForTextNode(elt.textContent)) +}else{if(elt.nodeType==Node.CDATA_SECTION_NODE){html.push("") +}else{if(elt.nodeType==Node.COMMENT_NODE){html.push("") +}}}}}var html=[]; +toHTML(element); +return html.join("") +}; +this.getElementXML=function(element){function toXML(elt){if(elt.nodeType==Node.ELEMENT_NODE){if(unwrapObject(elt).firebugIgnore){return +}xml.push("<",elt.nodeName.toLowerCase()); +for(var i=0; +i"); +for(var child=elt.firstChild; +child; +child=child.nextSibling){toXML(child) +}xml.push("") +}else{xml.push("/>") +}}else{if(elt.nodeType==Node.TEXT_NODE){xml.push(elt.nodeValue) +}else{if(elt.nodeType==Node.CDATA_SECTION_NODE){xml.push("") +}else{if(elt.nodeType==Node.COMMENT_NODE){xml.push("") +}}}}}var xml=[]; +toXML(element); +return xml.join("") +}; +this.hasClass=function(node,name){if(arguments.length==2){return(" "+node.className+" ").indexOf(" "+name+" ")!=-1 +}if(!node||node.nodeType!=1){return false +}else{for(var i=1; +i=0){var size=name.length; +node.className=node.className.substr(0,index-1)+node.className.substr(index+size) +}}}; +this.toggleClass=function(elt,name){if((" "+elt.className+" ").indexOf(" "+name+" ")!=-1){this.removeClass(elt,name) +}else{this.setClass(elt,name) +}}; +this.setClassTimed=function(elt,name,context,timeout){if(!timeout){timeout=1300 +}if(elt.__setClassTimeout){context.clearTimeout(elt.__setClassTimeout) +}else{this.setClass(elt,name) +}elt.__setClassTimeout=context.setTimeout(function(){delete elt.__setClassTimeout; +FBL.removeClass(elt,name) +},timeout) +}; +this.cancelClassTimed=function(elt,name,context){if(elt.__setClassTimeout){FBL.removeClass(elt,name); +context.clearTimeout(elt.__setClassTimeout); +delete elt.__setClassTimeout +}}; +this.$=function(id,doc){if(doc){return doc.getElementById(id) +}else{return FBL.Firebug.chrome.document.getElementById(id) +}}; +this.$$=function(selector,doc){if(doc||!FBL.Firebug.chrome){return FBL.Firebug.Selector(selector,doc) +}else{return FBL.Firebug.Selector(selector,FBL.Firebug.chrome.document) +}}; +this.getChildByClass=function(node){for(var i=1; +i1&&doc.styleSheets[1].href=="chrome://browser/skin/feeds/subscribe.css")){return true +}return FBL.isSystemURL(win.location.href) +}catch(exc){ERROR("tabWatcher.isSystemPage document not ready:"+exc); +return false +}}; +this.isSystemStyleSheet=function(sheet){var href=sheet&&sheet.href; +return href&&FBL.isSystemURL(href) +}; +this.getURIHost=function(uri){try{if(uri){return uri.host +}else{return"" +}}catch(exc){return"" +}}; +this.isLocalURL=function(url){if(url.substr(0,5)=="file:"){return true +}else{if(url.substr(0,8)=="wyciwyg:"){return true +}else{return false +}}}; +this.isDataURL=function(url){return(url&&url.substr(0,5)=="data:") +}; +this.getLocalPath=function(url){if(this.isLocalURL(url)){var fileHandler=ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); +var file=fileHandler.getFileFromURLSpec(url); +return file.path +}}; +this.getURLFromLocalFile=function(file){var fileHandler=ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); +var URL=fileHandler.getURLSpecFromFile(file); +return URL +}; +this.getDataURLForContent=function(content,url){var uri="data:text/html;"; +uri+="fileName="+encodeURIComponent(url)+","; +uri+=encodeURIComponent(content); +return uri +},this.getDomain=function(url){var m=/[^:]+:\/{1,3}([^\/]+)/.exec(url); +return m?m[1]:"" +}; +this.getURLPath=function(url){var m=/[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); +return m?m[1]:"" +}; +this.getPrettyDomain=function(url){var m=/[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); +return m?m[2]:"" +}; +this.absoluteURL=function(url,baseURL){return this.absoluteURLWithDots(url,baseURL).replace("/./","/","g") +}; +this.absoluteURLWithDots=function(url,baseURL){if(url[0]=="?"){return baseURL+url +}var reURL=/(([^:]+:)\/{1,2}[^\/]*)(.*?)$/; +var m=reURL.exec(url); +if(m){return url +}var m=reURL.exec(baseURL); +if(!m){return"" +}var head=m[1]; +var tail=m[3]; +if(url.substr(0,2)=="//"){return m[2]+url +}else{if(url[0]=="/"){return head+url +}else{if(tail[tail.length-1]=="/"){return baseURL+url +}else{var parts=tail.split("/"); +return head+parts.slice(0,parts.length-1).join("/")+"/"+url +}}}}; +this.normalizeURL=function(url){if(!url){return"" +}if(url.length<255){url=url.replace(/[^\/]+\/\.\.\//,"","g"); +url=url.replace(/#.*/,""); +url=url.replace(/file:\/([^\/])/g,"file:///$1"); +if(url.indexOf("chrome:")==0){var m=reChromeCase.exec(url); +if(m){url="chrome://"+m[1].toLowerCase()+"/"+m[2] +}}}return url +}; +this.denormalizeURL=function(url){return url.replace(/file:\/\/\//g,"file:/") +}; +this.parseURLParams=function(url){var q=url?url.indexOf("?"):-1; +if(q==-1){return[] +}var search=url.substr(q+1); +var h=search.lastIndexOf("#"); +if(h!=-1){search=search.substr(0,h) +}if(!search){return[] +}return this.parseURLEncodedText(search) +}; +this.parseURLEncodedText=function(text){var maxValueLength=25000; +var params=[]; +text=text.replace(/\+/g," "); +var args=text.split("&"); +for(var i=0; +imaxValueLength){parts[1]=this.$STR("LargeData") +}params.push({name:decodeURIComponent(parts[0]),value:decodeURIComponent(parts[1])}) +}else{params.push({name:decodeURIComponent(parts[0]),value:""}) +}}catch(e){if(FBTrace.DBG_ERRORS){FBTrace.sysout("parseURLEncodedText EXCEPTION ",e); +FBTrace.sysout("parseURLEncodedText EXCEPTION URI",args[i]) +}}}params.sort(function(a,b){return a.name<=b.name?-1:1 +}); +return params +}; +this.parseURLParamsArray=function(url){var q=url?url.indexOf("?"):-1; +if(q==-1){return[] +}var search=url.substr(q+1); +var h=search.lastIndexOf("#"); +if(h!=-1){search=search.substr(0,h) +}if(!search){return[] +}return this.parseURLEncodedTextArray(search) +}; +this.parseURLEncodedTextArray=function(text){var maxValueLength=25000; +var params=[]; +text=text.replace(/\+/g," "); +var args=text.split("&"); +for(var i=0; +imaxValueLength){parts[1]=this.$STR("LargeData") +}params.push({name:decodeURIComponent(parts[0]),value:[decodeURIComponent(parts[1])]}) +}else{params.push({name:decodeURIComponent(parts[0]),value:[""]}) +}}catch(e){if(FBTrace.DBG_ERRORS){FBTrace.sysout("parseURLEncodedText EXCEPTION ",e); +FBTrace.sysout("parseURLEncodedText EXCEPTION URI",args[i]) +}}}params.sort(function(a,b){return a.name<=b.name?-1:1 +}); +return params +}; +this.reEncodeURL=function(file,text){var lines=text.split("\n"); +var params=this.parseURLEncodedText(lines[lines.length-1]); +var args=[]; +for(var i=0; +i0){setTimeout(this.sendRequest,10) +}}},getResponse:function(options){var t=this.transport,type=options.dataType; +if(t.status!=200){return t.statusText +}else{if(type=="text"){return t.responseText +}else{if(type=="html"){return t.responseText +}else{if(type=="xml"){return t.responseXML +}else{if(type=="json"){return eval("("+t.responseText+")") +}}}}}},getState:function(){return this.states[this.transport.readyState] +}}; +this.createCookie=function(name,value,days){if("cookie" in document){if(days){var date=new Date(); +date.setTime(date.getTime()+(days*24*60*60*1000)); +var expires="; expires="+date.toGMTString() +}else{var expires="" +}document.cookie=name+"="+value+expires+"; path=/" +}}; +this.readCookie=function(name){if("cookie" in document){var nameEQ=name+"="; +var ca=document.cookie.split(";"); +for(var i=0; +iobjects.length){format=""; +objIndex=-1; +parts.length=0; +break +}}}var result=[]; +for(var i=0; +i'; +var tabNode=this.tabNode=createElement("a",{id:panelId+"Tab",className:"fbTab fbHover",innerHTML:tabHTML}); +if(isIE6){tabNode.href="javascript:void(0)" +}var panelBarNode=this.parentPanel?Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode:this.panelBarNode; +panelBarNode.appendChild(tabNode); +tabNode.style.display="block"; +if(options.hasToolButtons){this.toolButtonsNode=createElement("span",{id:panelId+"Buttons",className:"fbToolbarButtons"}); +$("fbToolbarButtons").appendChild(this.toolButtonsNode) +}if(options.hasStatusBar){this.statusBarBox=$("fbStatusBarBox"); +this.statusBarNode=createElement("span",{id:panelId+"StatusBar",className:"fbToolbarButtons fbStatusBar"}); +this.statusBarBox.appendChild(this.statusBarNode) +}}this.containerNode=this.panelNode.parentNode; +if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("Firebug.Panel.create",this.name) +}this.onContextMenu=bind(this.onContextMenu,this) +},destroy:function(state){if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("Firebug.Panel.destroy",this.name) +}if(this.hasSidePanel){this.sidePanelBar.destroy(); +this.sidePanelBar=null +}this.options=null; +this.name=null; +this.parentPanel=null; +this.tabNode=null; +this.panelNode=null; +this.containerNode=null; +this.toolButtonsNode=null; +this.statusBarBox=null; +this.statusBarNode=null +},initialize:function(){if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("Firebug.Panel.initialize",this.name) +}if(this.hasSidePanel){this.sidePanelBar.initialize() +}var options=this.options=extend(Firebug.Panel.options,this.options); +var panelId="fb"+this.name; +this.panelNode=$(panelId); +this.tabNode=$(panelId+"Tab"); +this.tabNode.style.display="block"; +if(options.hasStatusBar){this.statusBarBox=$("fbStatusBarBox"); +this.statusBarNode=$(panelId+"StatusBar") +}if(options.hasToolButtons){this.toolButtonsNode=$(panelId+"Buttons") +}this.containerNode=this.panelNode.parentNode; +this.containerNode.scrollTop=this.lastScrollTop; +addEvent(this.containerNode,"contextmenu",this.onContextMenu); +Firebug.chrome.currentPanel=Firebug.chrome.selectedPanel&&Firebug.chrome.selectedPanel.sidePanelBar?Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel:Firebug.chrome.selectedPanel; +Firebug.showInfoTips=true; +Firebug.InfoTip.initializeBrowser(Firebug.chrome) +},shutdown:function(){if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("Firebug.Panel.shutdown",this.name) +}Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); +if(Firebug.chrome.largeCommandLineVisible){Firebug.chrome.hideLargeCommandLine() +}if(this.hasSidePanel){}this.lastScrollTop=this.containerNode.scrollTop; +removeEvent(this.containerNode,"contextmenu",this.onContextMenu) +},detach:function(oldChrome,newChrome){if(oldChrome.selectedPanel.name==this.name){this.lastScrollTop=oldChrome.selectedPanel.containerNode.scrollTop +}},reattach:function(doc){if(this.options.innerHTMLSync){this.synchronizeUI() +}},synchronizeUI:function(){this.containerNode.scrollTop=this.lastScrollTop||0 +},show:function(state){var options=this.options; +if(options.hasStatusBar){this.statusBarBox.style.display="inline"; +this.statusBarNode.style.display="inline" +}if(options.hasToolButtons){this.toolButtonsNode.style.display="inline" +}this.panelNode.style.display="block"; +this.visible=true; +if(!this.parentPanel){Firebug.chrome.layout(this) +}},hide:function(state){var options=this.options; +if(options.hasStatusBar){this.statusBarBox.style.display="none"; +this.statusBarNode.style.display="none" +}if(options.hasToolButtons){this.toolButtonsNode.style.display="none" +}this.panelNode.style.display="none"; +this.visible=false +},watchWindow:function(win){},unwatchWindow:function(win){},updateOption:function(name,value){},showToolbarButtons:function(buttonsId,show){try{if(!this.context.browser){if(FBTrace.DBG_ERRORS){FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:",this) +}return +}var buttons=this.context.browser.chrome.$(buttonsId); +if(buttons){collapse(buttons,show?"false":"true") +}}catch(exc){if(FBTrace.DBG_ERRORS){FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS",exc); +if(!this.context.browser){FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser") +}}}},supportsObject:function(object){return 0 +},hasObject:function(object){return false +},select:function(object,forceUpdate){if(!object){object=this.getDefaultSelection(this.context) +}if(FBTrace.DBG_PANELS){FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection) +}if(forceUpdate||object!=this.selection){this.selection=object; +this.updateSelection(object) +}},updateSelection:function(object){},markChange:function(skipSelf){if(this.dependents){if(skipSelf){for(var i=0; +ilocB.path){return 1 +}if(locA.pathlocB.name){return 1 +}if(locA.namewidth||el.scrollHeight>height)){width=el.scrollWidth; +height=el.scrollHeight +}return{width:width,height:height} +},getWindowScrollPosition:function(){var top=0,left=0,el; +if(typeof this.window.pageYOffset=="number"){top=this.window.pageYOffset; +left=this.window.pageXOffset +}else{if((el=this.document.body)&&(el.scrollTop||el.scrollLeft)){top=el.scrollTop; +left=el.scrollLeft +}else{if((el=this.document.documentElement)&&(el.scrollTop||el.scrollLeft)){top=el.scrollTop; +left=el.scrollLeft +}}}return{top:top,left:left} +},getElementFromPoint:function(x,y){if(shouldFixElementFromPoint){var scroll=this.getWindowScrollPosition(); +return this.document.elementFromPoint(x+scroll.left,y+scroll.top) +}else{return this.document.elementFromPoint(x,y) +}},getElementPosition:function(el){var left=0; +var top=0; +do{left+=el.offsetLeft; +top+=el.offsetTop +}while(el=el.offsetParent); +return{left:left,top:top} +},getElementBox:function(el){var result={}; +if(el.getBoundingClientRect){var rect=el.getBoundingClientRect(); +var offset=isIE?this.document.body.clientTop||this.document.documentElement.clientTop:0; +var scroll=this.getWindowScrollPosition(); +result.top=Math.round(rect.top-offset+scroll.top); +result.left=Math.round(rect.left-offset+scroll.left); +result.height=Math.round(rect.bottom-rect.top); +result.width=Math.round(rect.right-rect.left) +}else{var position=this.getElementPosition(el); +result.top=position.top; +result.left=position.left; +result.height=el.offsetHeight; +result.width=el.offsetWidth +}return result +},getMeasurement:function(el,name){var result={value:0,unit:"px"}; +var cssValue=this.getStyle(el,name); +if(!cssValue){return result +}if(cssValue.toLowerCase()=="auto"){return result +}var reMeasure=/(\d+\.?\d*)(.*)/; +var m=cssValue.match(reMeasure); +if(m){result.value=m[1]-0; +result.unit=m[2].toLowerCase() +}return result +},getMeasurementInPixels:function(el,name){if(!el){return null +}var m=this.getMeasurement(el,name); +var value=m.value; +var unit=m.unit; +if(unit=="px"){return value +}else{if(unit=="pt"){return this.pointsToPixels(name,value) +}}if(unit=="em"){return this.emToPixels(el,value) +}else{if(unit=="%"){return this.percentToPixels(el,value) +}}},getMeasurementBox1:function(el,name){var sufixes=["Top","Left","Bottom","Right"]; +var result=[]; +for(var i=0,sufix; +sufix=sufixes[i]; +i++){result[i]=Math.round(this.getMeasurementInPixels(el,name+sufix)) +}return{top:result[0],left:result[1],bottom:result[2],right:result[3]} +},getMeasurementBox:function(el,name){var result=[]; +var sufixes=name=="border"?["TopWidth","LeftWidth","BottomWidth","RightWidth"]:["Top","Left","Bottom","Right"]; +if(isIE){var propName,cssValue; +var autoMargin=null; +for(var i=0,sufix; +sufix=sufixes[i]; +i++){propName=name+sufix; +cssValue=el.currentStyle[propName]||el.style[propName]; +if(cssValue=="auto"){if(!autoMargin){autoMargin=this.getCSSAutoMarginBox(el) +}result[i]=autoMargin[sufix.toLowerCase()] +}else{result[i]=this.getMeasurementInPixels(el,propName) +}}}else{for(var i=0,sufix; +sufix=sufixes[i]; +i++){result[i]=this.getMeasurementInPixels(el,name+sufix) +}}return{top:result[0],left:result[1],bottom:result[2],right:result[3]} +},getCSSAutoMarginBox:function(el){if(isIE&&" meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ")!=-1){return{top:0,left:0,bottom:0,right:0} +}if(isIE&&" h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ")==-1){return{top:0,left:0,bottom:0,right:0} +}var offsetTop=0; +if(false&&isIEStantandMode){var scrollSize=Firebug.browser.getWindowScrollSize(); +offsetTop=scrollSize.height +}var box=this.document.createElement("div"); +box.style.cssText="margin:0; padding:1px; border: 0; visibility: hidden;"; +var clone=el.cloneNode(false); +var text=this.document.createTextNode(" "); +clone.appendChild(text); +box.appendChild(clone); +this.document.body.appendChild(box); +var marginTop=clone.offsetTop-box.offsetTop-1; +var marginBottom=box.offsetHeight-clone.offsetHeight-2-marginTop; +var marginLeft=clone.offsetLeft-box.offsetLeft-1; +var marginRight=box.offsetWidth-clone.offsetWidth-2-marginLeft; +this.document.body.removeChild(box); +return{top:marginTop+offsetTop,left:marginLeft,bottom:marginBottom-offsetTop,right:marginRight} +},getFontSizeInPixels:function(el){var size=this.getMeasurement(el,"fontSize"); +if(size.unit=="px"){return size.value +}var computeDirtyFontSize=function(el,calibration){var div=this.document.createElement("div"); +var divStyle=offscreenStyle; +if(calibration){divStyle+=" font-size:"+calibration+"px;" +}div.style.cssText=divStyle; +div.innerHTML="A"; +el.appendChild(div); +var value=div.offsetHeight; +el.removeChild(div); +return value +}; +var rate=200/225; +var value=computeDirtyFontSize(el); +return value*rate +},pointsToPixels:function(name,value,returnFloat){var axis=/Top$|Bottom$/.test(name)?"y":"x"; +var result=value*pixelsPerInch[axis]/72; +return returnFloat?result:Math.round(result) +},emToPixels:function(el,value){if(!el){return null +}var fontSize=this.getFontSizeInPixels(el); +return Math.round(value*fontSize) +},exToPixels:function(el,value){if(!el){return null +}var div=this.document.createElement("div"); +div.style.cssText=offscreenStyle+"width:"+value+"ex;"; +el.appendChild(div); +var value=div.offsetWidth; +el.removeChild(div); +return value +},percentToPixels:function(el,value){if(!el){return null +}var div=this.document.createElement("div"); +div.style.cssText=offscreenStyle+"width:"+value+"%;"; +el.appendChild(div); +var value=div.offsetWidth; +el.removeChild(div); +return value +},getStyle:isIE?function(el,name){return el.currentStyle[name]||el.style[name]||undefined +}:function(el,name){return this.document.defaultView.getComputedStyle(el,null)[name]||el.style[name]||undefined +}} +}}); +FBL.ns(function(){with(FBL){var WindowDefaultOptions={type:"frame",id:"FirebugUI",height:250},commandLine,fbTop,fbContent,fbContentStyle,fbBottom,fbBtnInspect,fbToolbar,fbPanelBox1,fbPanelBox1Style,fbPanelBox2,fbPanelBox2Style,fbPanelBar2Box,fbPanelBar2BoxStyle,fbHSplitter,fbVSplitter,fbVSplitterStyle,fbPanel1,fbPanel1Style,fbPanel2,fbPanel2Style,fbConsole,fbConsoleStyle,fbHTML,fbCommandLine,fbLargeCommandLine,fbLargeCommandButtons,topHeight,topPartialHeight,chromeRedrawSkipRate=isIE?75:isOpera?80:75,lastSelectedPanelName,focusCommandLineState=0,lastFocusedPanelName,lastHSplitterMouseMove=0,onHSplitterMouseMoveBuffer=null,onHSplitterMouseMoveTimer=null,lastVSplitterMouseMove=0; +FBL.FirebugChrome={isOpen:false,height:250,sidePanelWidth:350,selectedPanelName:"Console",selectedHTMLElementId:null,chromeMap:{},htmlSelectionStack:[],consoleMessageQueue:[],create:function(){if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("FirebugChrome.create","creating chrome window") +}createChromeWindow() +},initialize:function(){if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("FirebugChrome.initialize","initializing chrome window") +}if(Env.chrome.type=="frame"||Env.chrome.type=="div"){ChromeMini.create(Env.chrome) +}var chrome=Firebug.chrome=new Chrome(Env.chrome); +FirebugChrome.chromeMap[chrome.type]=chrome; +addGlobalEvent("keydown",onGlobalKeyDown); +if(Env.Options.enablePersistent&&chrome.type=="popup"){var frame=FirebugChrome.chromeMap.frame; +if(frame){frame.close() +}chrome.initialize() +}},clone:function(FBChrome){for(var name in FBChrome){var prop=FBChrome[name]; +if(FBChrome.hasOwnProperty(name)&&!isFunction(prop)){this[name]=prop +}}}}; +var createChromeWindow=function(options){options=extend(WindowDefaultOptions,options||{}); +var chrome={},context=options.context||Env.browser,type=chrome.type=Env.Options.enablePersistent?"popup":options.type,isChromeFrame=type=="frame",useLocalSkin=Env.useLocalSkin,url=useLocalSkin?Env.Location.skin:"about:blank",body=context.document.getElementsByTagName("body")[0],formatNode=function(node){if(!Env.isDebugMode){node.firebugIgnore=true +}node.style.border="0"; +node.style.visibility="hidden"; +node.style.zIndex="2147483647"; +node.style.position=noFixedPosition?"absolute":"fixed"; +node.style.width="100%"; +node.style.left="0"; +node.style.bottom=noFixedPosition?"-1px":"0"; +node.style.height=options.height+"px"; +if(isFirefox){node.style.display="none" +}},createChromeDiv=function(){var node=chrome.node=createGlobalElement("div"),style=createGlobalElement("style"),css=FirebugChrome.Skin.CSS,rules=".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}"+css+".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}"; +style.type="text/css"; +if(style.styleSheet){style.styleSheet.cssText=rules +}else{style.appendChild(context.document.createTextNode(rules)) +}document.getElementsByTagName("head")[0].appendChild(style); +node.className="fbBody"; +node.style.overflow="hidden"; +node.innerHTML=getChromeDivTemplate(); +if(isIE){setTimeout(function(){node.firstChild.style.height="1px"; +node.firstChild.style.position="static" +},0) +}formatNode(node); +body.appendChild(node); +chrome.window=window; +chrome.document=document; +onChromeLoad(chrome) +}; +try{if(type=="div"){createChromeDiv(); +return +}else{if(isChromeFrame){var node=chrome.node=createGlobalElement("iframe"); +node.setAttribute("src",url); +node.setAttribute("frameBorder","0"); +formatNode(node); +body.appendChild(node); +node.id=options.id +}else{var height=FirebugChrome.height||options.height,options=["true,top=",Math.max(screen.availHeight-height-61,0),",left=0,height=",height,",width=",screen.availWidth-10,",resizable"].join(""),node=chrome.node=context.window.open(url,"popup",options); +if(node){try{node.focus() +}catch(E){alert("Firebug Error: Firebug popup was blocked."); +return +}}else{alert("Firebug Error: Firebug popup was blocked."); +return +}}}if(!useLocalSkin){var tpl=getChromeTemplate(!isChromeFrame),doc=isChromeFrame?node.contentWindow.document:node.document; +doc.write(tpl); +doc.close() +}var win,waitDelay=useLocalSkin?isChromeFrame?200:300:100,waitForWindow=function(){if(isChromeFrame&&(win=node.contentWindow)&&node.contentWindow.document.getElementById("fbCommandLine")||!isChromeFrame&&(win=node.window)&&node.document&&node.document.getElementById("fbCommandLine")){chrome.window=win.window; +chrome.document=win.document; +setTimeout(function(){onChromeLoad(chrome) +},0) +}else{setTimeout(waitForWindow,waitDelay) +}}; +waitForWindow() +}catch(e){var msg=e.message||e; +if(/access/i.test(msg)){if(isChromeFrame){body.removeChild(node) +}else{if(type=="popup"){node.close() +}}createChromeDiv() +}else{alert("Firebug Error: Firebug GUI could not be created.") +}}}; +var onChromeLoad=function onChromeLoad(chrome){Env.chrome=chrome; +if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("Chrome onChromeLoad","chrome window loaded") +}if(Env.Options.enablePersistent){Env.FirebugChrome=FirebugChrome; +chrome.window.Firebug=chrome.window.Firebug||{}; +chrome.window.Firebug.SharedEnv=Env; +if(Env.isDevelopmentMode){Env.browser.window.FBDev.loadChromeApplication(chrome) +}else{var doc=chrome.document; +var script=doc.createElement("script"); +script.src=Env.Location.app+"#remote,persist"; +doc.getElementsByTagName("head")[0].appendChild(script) +}}else{if(chrome.type=="frame"||chrome.type=="div"){setTimeout(function(){FBL.Firebug.initialize() +},0) +}else{if(chrome.type=="popup"){var oldChrome=FirebugChrome.chromeMap.frame; +var newChrome=new Chrome(chrome); +dispatch(newChrome.panelMap,"detach",[oldChrome,newChrome]); +if(oldChrome){oldChrome.close() +}newChrome.reattach(oldChrome,newChrome) +}}}}; +var getChromeDivTemplate=function(){return FirebugChrome.Skin.HTML +}; +var getChromeTemplate=function(isPopup){var tpl=FirebugChrome.Skin; +var r=[],i=-1; +r[++i]=''; +r[++i]=""; +r[++i]=Firebug.version; +r[++i]=""; +r[++i]=''; +r[++i]=tpl.HTML; +r[++i]=""; +return r.join("") +}; +var Chrome=function Chrome(chrome){var type=chrome.type; +var Base=type=="frame"||type=="div"?ChromeFrameBase:ChromePopupBase; +append(this,Base); +append(this,chrome); +append(this,new Context(chrome.window)); +FirebugChrome.chromeMap[type]=this; +Firebug.chrome=this; +Env.chrome=chrome.window; +this.commandLineVisible=false; +this.sidePanelVisible=false; +this.create(); +return this +}; +var ChromeBase={}; +append(ChromeBase,Controller); +append(ChromeBase,PanelBar); +append(ChromeBase,{node:null,type:null,document:null,window:null,sidePanelVisible:false,commandLineVisible:false,largeCommandLineVisible:false,inspectButton:null,create:function(){PanelBar.create.call(this); +if(Firebug.Inspector){this.inspectButton=new Button({type:"toggle",element:$("fbChrome_btInspect"),owner:Firebug.Inspector,onPress:Firebug.Inspector.startInspecting,onUnpress:Firebug.Inspector.stopInspecting}) +}},destroy:function(){if(Firebug.Inspector){this.inspectButton.destroy() +}PanelBar.destroy.call(this); +this.shutdown() +},testMenu:function(){var firebugMenu=new Menu({id:"fbFirebugMenu",items:[{label:"Open Firebug",type:"shortcut",key:isFirefox?"Shift+F12":"F12",checked:true,command:"toggleChrome"},{label:"Open Firebug in New Window",type:"shortcut",key:isFirefox?"Ctrl+Shift+F12":"Ctrl+F12",command:"openPopup"},{label:"Inspect Element",type:"shortcut",key:"Ctrl+Shift+C",command:"toggleInspect"},{label:"Command Line",type:"shortcut",key:"Ctrl+Shift+L",command:"focusCommandLine"},"-",{label:"Options",type:"group",child:"fbFirebugOptionsMenu"},"-",{label:"Firebug Lite Website...",command:"visitWebsite"},{label:"Discussion Group...",command:"visitDiscussionGroup"},{label:"Issue Tracker...",command:"visitIssueTracker"}],onHide:function(){iconButton.restore() +},toggleChrome:function(){Firebug.chrome.toggle() +},openPopup:function(){Firebug.chrome.toggle(true,true) +},toggleInspect:function(){Firebug.Inspector.toggleInspect() +},focusCommandLine:function(){Firebug.chrome.focusCommandLine() +},visitWebsite:function(){this.visit("http://getfirebug.com/lite.html") +},visitDiscussionGroup:function(){this.visit("http://groups.google.com/group/firebug") +},visitIssueTracker:function(){this.visit("http://code.google.com/p/fbug/issues/list") +},visit:function(url){window.open(url) +}}); +var firebugOptionsMenu={id:"fbFirebugOptionsMenu",getItems:function(){var cookiesDisabled=!Firebug.saveCookies; +return[{label:"Save Options in Cookies",type:"checkbox",value:"saveCookies",checked:Firebug.saveCookies,command:"saveOptions"},"-",{label:"Start Opened",type:"checkbox",value:"startOpened",checked:Firebug.startOpened,disabled:cookiesDisabled},{label:"Start in New Window",type:"checkbox",value:"startInNewWindow",checked:Firebug.startInNewWindow,disabled:cookiesDisabled},{label:"Show Icon When Hidden",type:"checkbox",value:"showIconWhenHidden",checked:Firebug.showIconWhenHidden,disabled:cookiesDisabled},{label:"Override Console Object",type:"checkbox",value:"overrideConsole",checked:Firebug.overrideConsole,disabled:cookiesDisabled},{label:"Ignore Firebug Elements",type:"checkbox",value:"ignoreFirebugElements",checked:Firebug.ignoreFirebugElements,disabled:cookiesDisabled},{label:"Disable When Firebug Active",type:"checkbox",value:"disableWhenFirebugActive",checked:Firebug.disableWhenFirebugActive,disabled:cookiesDisabled},{label:"Disable XHR Listener",type:"checkbox",value:"disableXHRListener",checked:Firebug.disableXHRListener,disabled:cookiesDisabled},{label:"Enable Trace Mode",type:"checkbox",value:"enableTrace",checked:Firebug.enableTrace,disabled:cookiesDisabled},{label:"Enable Persistent Mode (experimental)",type:"checkbox",value:"enablePersistent",checked:Firebug.enablePersistent,disabled:cookiesDisabled},"-",{label:"Reset All Firebug Options",command:"restorePrefs",disabled:cookiesDisabled}] +},onCheck:function(target,value,checked){Firebug.setPref(value,checked) +},saveOptions:function(target){var saveEnabled=target.getAttribute("checked"); +if(!saveEnabled){this.restorePrefs() +}this.updateMenu(target); +return false +},restorePrefs:function(target){Firebug.restorePrefs(); +if(Firebug.saveCookies){Firebug.savePrefs() +}else{Firebug.erasePrefs() +}if(target){this.updateMenu(target) +}return false +},updateMenu:function(target){var options=getElementsByClass(target.parentNode,"fbMenuOption"); +var firstOption=options[0]; +var enabled=Firebug.saveCookies; +if(enabled){Menu.check(firstOption) +}else{Menu.uncheck(firstOption) +}if(enabled){Menu.check(options[0]) +}else{Menu.uncheck(options[0]) +}for(var i=1,length=options.length; +ichromeRedrawSkipRate){lastHSplitterMouseMove=new Date().getTime(); +handleHSplitterMouseMove() +}else{if(!onHSplitterMouseMoveTimer){onHSplitterMouseMoveTimer=setTimeout(handleHSplitterMouseMove,chromeRedrawSkipRate) +}}cancelEvent(event,true); +return false +}; +var handleHSplitterMouseMove=function(){if(onHSplitterMouseMoveTimer){clearTimeout(onHSplitterMouseMoveTimer); +onHSplitterMouseMoveTimer=null +}var clientY=onHSplitterMouseMoveBuffer; +var windowSize=Firebug.browser.getWindowSize(); +var scrollSize=Firebug.browser.getWindowScrollSize(); +var commandLineHeight=Firebug.chrome.commandLineVisible?fbCommandLine.offsetHeight:0; +var fixedHeight=topHeight+commandLineHeight; +var chromeNode=Firebug.chrome.node; +var scrollbarSize=!isIE&&(scrollSize.width>windowSize.width)?17:0; +var height=windowSize.height; +var chromeHeight=Math.max(height-clientY+5-scrollbarSize,fixedHeight); +chromeHeight=Math.min(chromeHeight,windowSize.height-scrollbarSize); +FirebugChrome.height=chromeHeight; +chromeNode.style.height=chromeHeight+"px"; +if(noFixedPosition){Firebug.chrome.fixIEPosition() +}Firebug.chrome.draw() +}; +var onHSplitterMouseUp=function onHSplitterMouseUp(event){removeGlobalEvent("mousemove",onHSplitterMouseMove); +removeGlobalEvent("mouseup",onHSplitterMouseUp); +if(isIE){removeEvent(Firebug.browser.document.documentElement,"mouseleave",onHSplitterMouseUp) +}fbHSplitter.className=""; +Firebug.chrome.draw(); +return false +}; +var onVSplitterMouseDown=function onVSplitterMouseDown(event){addGlobalEvent("mousemove",onVSplitterMouseMove); +addGlobalEvent("mouseup",onVSplitterMouseUp); +return false +}; +var onVSplitterMouseMove=function onVSplitterMouseMove(event){if(new Date().getTime()-lastVSplitterMouseMove>chromeRedrawSkipRate){var target=event.target||event.srcElement; +if(target&&target.ownerDocument){var clientX=event.clientX; +var win=document.all?event.srcElement.ownerDocument.parentWindow:event.target.ownerDocument.defaultView; +if(win!=win.parent){clientX+=win.frameElement?win.frameElement.offsetLeft:0 +}var size=Firebug.chrome.getSize(); +var x=Math.max(size.width-clientX+3,6); +FirebugChrome.sidePanelWidth=x; +Firebug.chrome.draw() +}lastVSplitterMouseMove=new Date().getTime() +}cancelEvent(event,true); +return false +}; +var onVSplitterMouseUp=function onVSplitterMouseUp(event){removeGlobalEvent("mousemove",onVSplitterMouseMove); +removeGlobalEvent("mouseup",onVSplitterMouseUp); +Firebug.chrome.draw() +} +}}); +FBL.ns(function(){with(FBL){Firebug.Lite={} +}}); +FBL.ns(function(){with(FBL){Firebug.Lite.Browser=function(window){this.contentWindow=window; +this.contentDocument=window.document; +this.currentURI={spec:window.location.href} +}; +Firebug.Lite.Browser.prototype={toString:function(){return"Firebug.Lite.Browser" +}} +}}); +FBL.ns(function(){with(FBL){Firebug.Lite.Cache={ID:"firebug"+new Date().getTime()}; +var cacheUID=0; +var createCache=function(){var map={}; +var CID=Firebug.Lite.Cache.ID; +var supportsDeleteExpando=!document.all; +var cacheFunction=function(element){return cacheAPI.set(element) +}; +var cacheAPI={get:function(key){return map.hasOwnProperty(key)?map[key]:null +},set:function(element){var id=element[CID]; +if(!id){id=++cacheUID; +element[CID]=id +}if(!map.hasOwnProperty(id)){map[id]=element +}return id +},unset:function(element){var id=element[CID]; +if(supportsDeleteExpando){delete element[CID] +}else{if(element.removeAttribute){element.removeAttribute(CID) +}}delete map[id] +},key:function(element){return element[CID] +},has:function(element){return map.hasOwnProperty(element[CID]) +},clear:function(){for(var id in map){var element=map[id]; +cacheAPI.unset(element) +}}}; +FBL.append(cacheFunction,cacheAPI); +return cacheFunction +}; +Firebug.Lite.Cache.StyleSheet=createCache(); +Firebug.Lite.Cache.Element=createCache() +}}); +FBL.ns(function(){with(FBL){Firebug.Lite.Proxy={_callbacks:{},load:function(url){var resourceDomain=getDomain(url); +var isLocalResource=!resourceDomain||resourceDomain==Firebug.context.window.location.host; +return isLocalResource?fetchResource(url):fetchProxyResource(url) +},loadJSONP:function(url,callback){var script=createGlobalElement("script"),doc=Firebug.context.document,uid=""+new Date().getTime(),callbackName="callback=Firebug.Lite.Proxy._callbacks."+uid,jsonpURL=url.indexOf("?")!=-1?url+"&"+callbackName:url+"?"+callbackName; +Firebug.Lite.Proxy._callbacks[uid]=function(data){if(callback){callback(data) +}script.parentNode.removeChild(script); +delete Firebug.Lite.Proxy._callbacks[uid] +}; +script.src=jsonpURL; +if(doc.documentElement){doc.documentElement.appendChild(script) +}},YQL:function(url,callback){var yql="http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22"+encodeURIComponent(url)+"%22&format=xml"; +this.loadJSONP(yql,function(data){var source=data.results[0]; +var match=/\s+

      ([\s\S]+)<\/p>\s+<\/body>$/.exec(source); +if(match){source=match[1] +}console.log(source) +}) +}}; +var fetchResource=function(url){var xhr=FBL.Ajax.getXHRObject(); +xhr.open("get",url,false); +xhr.send(); +return xhr.responseText +}; +var fetchProxyResource=function(url){var proxyURL=Env.Location.baseDir+"plugin/proxy/proxy.php?url="+encodeURIComponent(url); +var response=fetchResource(proxyURL); +try{var data=eval("("+response+")") +}catch(E){return"ERROR: Firebug Lite Proxy plugin returned an invalid response." +}return data?data.contents:"" +} +}}); +FBL.ns(function(){with(FBL){Firebug.Lite.Script=function(window){this.fileName=null; +this.isValid=null; +this.baseLineNumber=null; +this.lineExtent=null; +this.tag=null; +this.functionName=null; +this.functionSource=null +}; +Firebug.Lite.Script.prototype={isLineExecutable:function(){},pcToLine:function(){},lineToPc:function(){},toString:function(){return"Firebug.Lite.Script" +}} +}}); +FBL.ns(function(){with(FBL){Firebug.Lite.Style={} +}}); +FBL.ns(function(){with(FBL){var chunker=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,done=0,toString=Object.prototype.toString,hasDuplicate=false,baseHasDuplicate=true; +[0,0].sort(function(){baseHasDuplicate=false; +return 0 +}); +var Sizzle=function(selector,context,results,seed){results=results||[]; +var origContext=context=context||document; +if(context.nodeType!==1&&context.nodeType!==9){return[] +}if(!selector||typeof selector!=="string"){return results +}var parts=[],m,set,checkSet,check,mode,extra,prune=true,contextXML=isXML(context),soFar=selector; +while((chunker.exec(""),m=chunker.exec(soFar))!==null){soFar=m[3]; +parts.push(m[1]); +if(m[2]){extra=m[3]; +break +}}if(parts.length>1&&origPOS.exec(selector)){if(parts.length===2&&Expr.relative[parts[0]]){set=posProcess(parts[0]+parts[1],context) +}else{set=Expr.relative[parts[0]]?[context]:Sizzle(parts.shift(),context); +while(parts.length){selector=parts.shift(); +if(Expr.relative[selector]){selector+=parts.shift() +}set=posProcess(selector,set) +}}}else{if(!seed&&parts.length>1&&context.nodeType===9&&!contextXML&&Expr.match.ID.test(parts[0])&&!Expr.match.ID.test(parts[parts.length-1])){var ret=Sizzle.find(parts.shift(),context,contextXML); +context=ret.expr?Sizzle.filter(ret.expr,ret.set)[0]:ret.set[0] +}if(context){var ret=seed?{expr:parts.pop(),set:makeArray(seed)}:Sizzle.find(parts.pop(),parts.length===1&&(parts[0]==="~"||parts[0]==="+")&&context.parentNode?context.parentNode:context,contextXML); +set=ret.expr?Sizzle.filter(ret.expr,ret.set):ret.set; +if(parts.length>0){checkSet=makeArray(set) +}else{prune=false +}while(parts.length){var cur=parts.pop(),pop=cur; +if(!Expr.relative[cur]){cur="" +}else{pop=parts.pop() +}if(pop==null){pop=context +}Expr.relative[cur](checkSet,pop,contextXML) +}}else{checkSet=parts=[] +}}if(!checkSet){checkSet=set +}if(!checkSet){throw"Syntax error, unrecognized expression: "+(cur||selector) +}if(toString.call(checkSet)==="[object Array]"){if(!prune){results.push.apply(results,checkSet) +}else{if(context&&context.nodeType===1){for(var i=0; +checkSet[i]!=null; +i++){if(checkSet[i]&&(checkSet[i]===true||checkSet[i].nodeType===1&&contains(context,checkSet[i]))){results.push(set[i]) +}}}else{for(var i=0; +checkSet[i]!=null; +i++){if(checkSet[i]&&checkSet[i].nodeType===1){results.push(set[i]) +}}}}}else{makeArray(checkSet,results) +}if(extra){Sizzle(extra,origContext,results,seed); +Sizzle.uniqueSort(results) +}return results +}; +Sizzle.uniqueSort=function(results){if(sortOrder){hasDuplicate=baseHasDuplicate; +results.sort(sortOrder); +if(hasDuplicate){for(var i=1; +i":function(checkSet,part,isXML){var isPartStr=typeof part==="string"; +if(isPartStr&&!/\W/.test(part)){part=isXML?part:part.toUpperCase(); +for(var i=0,l=checkSet.length; +i=0)){if(!inplace){result.push(elem) +}}else{if(inplace){curLoop[i]=false +}}}}return false +},ID:function(match){return match[1].replace(/\\/g,"") +},TAG:function(match,curLoop){for(var i=0; +curLoop[i]===false; +i++){}return curLoop[i]&&isXML(curLoop[i])?match[1]:match[1].toUpperCase() +},CHILD:function(match){if(match[1]=="nth"){var test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(match[2]=="even"&&"2n"||match[2]=="odd"&&"2n+1"||!/\D/.test(match[2])&&"0n+"+match[2]||match[2]); +match[2]=(test[1]+(test[2]||1))-0; +match[3]=test[3]-0 +}match[0]=done++; +return match +},ATTR:function(match,curLoop,inplace,result,not,isXML){var name=match[1].replace(/\\/g,""); +if(!isXML&&Expr.attrMap[name]){match[1]=Expr.attrMap[name] +}if(match[2]==="~="){match[4]=" "+match[4]+" " +}return match +},PSEUDO:function(match,curLoop,inplace,result,not){if(match[1]==="not"){if((chunker.exec(match[3])||"").length>1||/^\w/.test(match[3])){match[3]=Sizzle(match[3],null,null,curLoop) +}else{var ret=Sizzle.filter(match[3],curLoop,inplace,true^not); +if(!inplace){result.push.apply(result,ret) +}return false +}}else{if(Expr.match.POS.test(match[0])||Expr.match.CHILD.test(match[0])){return true +}}return match +},POS:function(match){match.unshift(true); +return match +}},filters:{enabled:function(elem){return elem.disabled===false&&elem.type!=="hidden" +},disabled:function(elem){return elem.disabled===true +},checked:function(elem){return elem.checked===true +},selected:function(elem){elem.parentNode.selectedIndex; +return elem.selected===true +},parent:function(elem){return !!elem.firstChild +},empty:function(elem){return !elem.firstChild +},has:function(elem,i,match){return !!Sizzle(match[3],elem).length +},header:function(elem){return/h\d/i.test(elem.nodeName) +},text:function(elem){return"text"===elem.type +},radio:function(elem){return"radio"===elem.type +},checkbox:function(elem){return"checkbox"===elem.type +},file:function(elem){return"file"===elem.type +},password:function(elem){return"password"===elem.type +},submit:function(elem){return"submit"===elem.type +},image:function(elem){return"image"===elem.type +},reset:function(elem){return"reset"===elem.type +},button:function(elem){return"button"===elem.type||elem.nodeName.toUpperCase()==="BUTTON" +},input:function(elem){return/input|select|textarea|button/i.test(elem.nodeName) +}},setFilters:{first:function(elem,i){return i===0 +},last:function(elem,i,match,array){return i===array.length-1 +},even:function(elem,i){return i%2===0 +},odd:function(elem,i){return i%2===1 +},lt:function(elem,i,match){return imatch[3]-0 +},nth:function(elem,i,match){return match[3]-0==i +},eq:function(elem,i,match){return match[3]-0==i +}},filter:{PSEUDO:function(elem,match,i,array){var name=match[1],filter=Expr.filters[name]; +if(filter){return filter(elem,i,match,array) +}else{if(name==="contains"){return(elem.textContent||elem.innerText||"").indexOf(match[3])>=0 +}else{if(name==="not"){var not=match[3]; +for(var i=0,l=not.length; +i=0) +}}},ID:function(elem,match){return elem.nodeType===1&&elem.getAttribute("id")===match +},TAG:function(elem,match){return(match==="*"&&elem.nodeType===1)||elem.nodeName===match +},CLASS:function(elem,match){return(" "+(elem.className||elem.getAttribute("class"))+" ").indexOf(match)>-1 +},ATTR:function(elem,match){var name=match[1],result=Expr.attrHandle[name]?Expr.attrHandle[name](elem):elem[name]!=null?elem[name]:elem.getAttribute(name),value=result+"",type=match[2],check=match[4]; +return result==null?type==="!=":type==="="?value===check:type==="*="?value.indexOf(check)>=0:type==="~="?(" "+value+" ").indexOf(check)>=0:!check?value&&result!==false:type==="!="?value!=check:type==="^="?value.indexOf(check)===0:type==="$="?value.substr(value.length-check.length)===check:type==="|="?value===check||value.substr(0,check.length+1)===check+"-":false +},POS:function(elem,match,i,array){var name=match[2],filter=Expr.setFilters[name]; +if(filter){return filter(elem,i,match,array) +}}}}; +var origPOS=Expr.match.POS; +for(var type in Expr.match){Expr.match[type]=new RegExp(Expr.match[type].source+/(?![^\[]*\])(?![^\(]*\))/.source); +Expr.leftMatch[type]=new RegExp(/(^(?:.|\r|\n)*?)/.source+Expr.match[type].source) +}var makeArray=function(array,results){array=Array.prototype.slice.call(array,0); +if(results){results.push.apply(results,array); +return results +}return array +}; +try{Array.prototype.slice.call(document.documentElement.childNodes,0) +}catch(e){makeArray=function(array,results){var ret=results||[]; +if(toString.call(array)==="[object Array]"){Array.prototype.push.apply(ret,array) +}else{if(typeof array.length==="number"){for(var i=0,l=array.length; +i"; +var root=document.documentElement; +root.insertBefore(form,root.firstChild); +if(!!document.getElementById(id)){Expr.find.ID=function(match,context,isXML){if(typeof context.getElementById!=="undefined"&&!isXML){var m=context.getElementById(match[1]); +return m?m.id===match[1]||typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id").nodeValue===match[1]?[m]:undefined:[] +}}; +Expr.filter.ID=function(elem,match){var node=typeof elem.getAttributeNode!=="undefined"&&elem.getAttributeNode("id"); +return elem.nodeType===1&&node&&node.nodeValue===match +} +}root.removeChild(form); +root=form=null +})(); +(function(){var div=document.createElement("div"); +div.appendChild(document.createComment("")); +if(div.getElementsByTagName("*").length>0){Expr.find.TAG=function(match,context){var results=context.getElementsByTagName(match[1]); +if(match[1]==="*"){var tmp=[]; +for(var i=0; +results[i]; +i++){if(results[i].nodeType===1){tmp.push(results[i]) +}}results=tmp +}return results +} +}div.innerHTML=""; +if(div.firstChild&&typeof div.firstChild.getAttribute!=="undefined"&&div.firstChild.getAttribute("href")!=="#"){Expr.attrHandle.href=function(elem){return elem.getAttribute("href",2) +} +}div=null +})(); +if(document.querySelectorAll){(function(){var oldSizzle=Sizzle,div=document.createElement("div"); +div.innerHTML="

      "; +if(div.querySelectorAll&&div.querySelectorAll(".TEST").length===0){return +}Sizzle=function(query,context,extra,seed){context=context||document; +if(!seed&&context.nodeType===9&&!isXML(context)){try{return makeArray(context.querySelectorAll(query),extra) +}catch(e){}}return oldSizzle(query,context,extra,seed) +}; +for(var prop in oldSizzle){Sizzle[prop]=oldSizzle[prop] +}div=null +})() +}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var div=document.createElement("div"); +div.innerHTML="
      "; +if(div.getElementsByClassName("e").length===0){return +}div.lastChild.className="e"; +if(div.getElementsByClassName("e").length===1){return +}Expr.order.splice(1,0,"CLASS"); +Expr.find.CLASS=function(match,context,isXML){if(typeof context.getElementsByClassName!=="undefined"&&!isXML){return context.getElementsByClassName(match[1]) +}}; +div=null +})() +}function dirNodeCheck(dir,cur,doneName,checkSet,nodeCheck,isXML){var sibDir=dir=="previousSibling"&&!isXML; +for(var i=0,l=checkSet.length; +i0){match=elem; +break +}}}elem=elem[dir] +}checkSet[i]=match +}}}var contains=document.compareDocumentPosition?function(a,b){return a.compareDocumentPosition(b)&16 +}:function(a,b){return a!==b&&(a.contains?a.contains(b):true) +}; +var isXML=function(elem){return elem.nodeType===9&&elem.documentElement.nodeName!=="HTML"||!!elem.ownerDocument&&elem.ownerDocument.documentElement.nodeName!=="HTML" +}; +var posProcess=function(selector,context){var tmpSet=[],later="",match,root=context.nodeType?[context]:context; +while((match=Expr.match.PSEUDO.exec(selector))){later+=match[0]; +selector=selector.replace(Expr.match.PSEUDO,"") +}selector=Expr.relative[selector]?selector+"*":selector; +for(var i=0,l=root.length; +i":return">"; +case"&":return"&"; +case"'":return"'"; +case'"':return""" +}return"?" +}return String(value).replace(/[<>&"']/g,replaceChars) +}function __loop__(iter,outputs,fn){var iterOuts=[]; +outputs.push(iterOuts); +if(iter instanceof Array){iter=new ArrayIterator(iter) +}try{while(1){var value=iter.next(); +var itemOuts=[0,0]; +iterOuts.push(itemOuts); +fn.apply(this,[value,itemOuts]) +}}catch(exc){if(exc!=StopIteration){throw exc +}}}var js=fnBlock.join(""); +var r=null; +eval(js); +this.renderMarkup=r +},getVarNames:function(args){if(this.vars){args.push.apply(args,this.vars) +}for(var i=0; +i"'); +this.generateChildMarkup(topBlock,topOuts,blocks,info); +topBlock.push(',""') +},generateChildMarkup:function(topBlock,topOuts,blocks,info){for(var i=0; +i=array.length){throw StopIteration +}return array[index] +} +}function StopIteration(){}FBL.$break=function(){throw StopIteration +}; +var Renderer={renderHTML:function(args,outputs,self){var code=[]; +var markupArgs=[code,this.tag.context,args,outputs]; +markupArgs.push.apply(markupArgs,this.tag.markupArgs); +this.tag.renderMarkup.apply(self?self:this.tag.subject,markupArgs); +return code.join("") +},insertRows:function(args,before,self){this.tag.compile(); +var outputs=[]; +var html=this.renderHTML(args,outputs,self); +var doc=before.ownerDocument; +var div=doc.createElement("div"); +div.innerHTML=""+html+"
      "; +var tbody=div.firstChild.firstChild; +var parent=before.tagName=="TR"?before.parentNode:before; +var after=before.tagName=="TR"?before.nextSibling:null; +var firstRow=tbody.firstChild,lastRow; +while(tbody.firstChild){lastRow=tbody.firstChild; +if(after){parent.insertBefore(lastRow,after) +}else{parent.appendChild(lastRow) +}}var offset=0; +if(before.tagName=="TR"){var node=firstRow.parentNode.firstChild; +for(; +node&&node!=firstRow; +node=node.nextSibling){++offset +}}var domArgs=[firstRow,this.tag.context,offset]; +domArgs.push.apply(domArgs,this.tag.domArgs); +domArgs.push.apply(domArgs,outputs); +this.tag.renderDOM.apply(self?self:this.tag.subject,domArgs); +return[firstRow,lastRow] +},insertBefore:function(args,before,self){return this.insertNode(args,before.ownerDocument,before,false,self) +},insertAfter:function(args,after,self){return this.insertNode(args,after.ownerDocument,after,true,self) +},insertNode:function(args,doc,element,isAfter,self){if(!args){args={} +}this.tag.compile(); +var outputs=[]; +var html=this.renderHTML(args,outputs,self); +var doc=element.ownerDocument; +if(!womb||womb.ownerDocument!=doc){womb=doc.createElement("div") +}womb.innerHTML=html; +var root=womb.firstChild; +if(isAfter){while(womb.firstChild){if(element.nextSibling){element.parentNode.insertBefore(womb.firstChild,element.nextSibling) +}else{element.parentNode.appendChild(womb.firstChild) +}}}else{while(womb.lastChild){element.parentNode.insertBefore(womb.lastChild,element) +}}var domArgs=[root,this.tag.context,0]; +domArgs.push.apply(domArgs,this.tag.domArgs); +domArgs.push.apply(domArgs,outputs); +this.tag.renderDOM.apply(self?self:this.tag.subject,domArgs); +return root +},replace:function(args,parent,self){this.tag.compile(); +var outputs=[]; +var html=this.renderHTML(args,outputs,self); +var root; +if(parent.nodeType==1){parent.innerHTML=html; +root=parent.firstChild +}else{if(!parent||parent.nodeType!=9){parent=document +}if(!womb||womb.ownerDocument!=parent){womb=parent.createElement("div") +}womb.innerHTML=html; +root=womb.firstChild +}var domArgs=[root,this.tag.context,0]; +domArgs.push.apply(domArgs,this.tag.domArgs); +domArgs.push.apply(domArgs,outputs); +this.tag.renderDOM.apply(self?self:this.tag.subject,domArgs); +return root +},append:function(args,parent,self){this.tag.compile(); +var outputs=[]; +var html=this.renderHTML(args,outputs,self); +if(!womb||womb.ownerDocument!=parent.ownerDocument){womb=parent.ownerDocument.createElement("div") +}womb.innerHTML=html; +var root=womb.firstChild; +while(womb.firstChild){parent.appendChild(womb.firstChild) +}womb=null; +var domArgs=[root,this.tag.context,0]; +domArgs.push.apply(domArgs,this.tag.domArgs); +domArgs.push.apply(domArgs,outputs); +this.tag.renderDOM.apply(self?self:this.tag.subject,domArgs); +return root +}}; +function defineTags(){for(var i=0; +inumPropertiesShown){break +}}if(numProperties>numPropertiesShown){props.push({object:"...",tag:FirebugReps.Caption.tag,name:"",equal:"",delim:""}) +}else{if(props.length>0){props[props.length-1].delim="" +}}}catch(exc){}return props +},fb_1_6_propIterator:function(object,max){max=max||3; +if(!object){return[] +}var props=[]; +var len=0,count=0; +try{for(var name in object){var value; +try{value=object[name] +}catch(exc){continue +}var t=typeof(value); +if(t=="boolean"||t=="number"||(t=="string"&&value)||(t=="object"&&value&&value.toString)){var rep=Firebug.getRep(value); +var tag=rep.shortTag||rep.tag; +if(t=="object"){value=rep.getTitle(value); +tag=rep.titleTag +}count++; +if(count<=max){props.push({tag:tag,name:name,object:value,equal:"=",delim:", "}) +}else{break +}}}if(count>max){props[Math.max(1,max-1)]={object:"more...",tag:FirebugReps.Caption.tag,name:"",equal:"",delim:""} +}else{if(props.length>0){props[props.length-1].delim="" +}}}catch(exc){}return props +},className:"object",supportsObject:function(object,type){return true +}}); +this.Arr=domplate(Firebug.Rep,{tag:OBJECTBOX({_repObject:"$object"},SPAN({"class":"arrayLeftBracket",role:"presentation"},"["),FOR("item","$object|arrayIterator",TAG("$item.tag",{object:"$item.object"}),SPAN({"class":"arrayComma",role:"presentation"},"$item.delim")),SPAN({"class":"arrayRightBracket",role:"presentation"},"]")),shortTag:OBJECTBOX({_repObject:"$object"},SPAN({"class":"arrayLeftBracket",role:"presentation"},"["),FOR("item","$object|shortArrayIterator",TAG("$item.tag",{object:"$item.object"}),SPAN({"class":"arrayComma",role:"presentation"},"$item.delim")),SPAN({"class":"arrayRightBracket"},"]")),arrayIterator:function(array){var items=[]; +for(var i=0; +i3){items.push({object:(array.length-3)+" more...",tag:FirebugReps.Caption.tag,delim:""}) +}return items +},shortPropIterator:this.Obj.propIterator,getItemIndex:function(child){var arrayIndex=0; +for(child=child.previousSibling; +child; +child=child.previousSibling){if(child.repObject){++arrayIndex +}}return arrayIndex +},className:"array",supportsObject:function(object){return this.isArray(object) +},isArray:function(obj){try{if(!obj){return false +}else{if(isIE&&!isFunction(obj)&&typeof obj=="object"&&isFinite(obj.length)&&obj.nodeType!=8){return true +}else{if(isFinite(obj.length)&&isFunction(obj.splice)){return true +}else{if(isFinite(obj.length)&&isFunction(obj.callee)){return true +}else{if(instanceOf(obj,"HTMLCollection")){return true +}else{if(instanceOf(obj,"NodeList")){return true +}else{return false +}}}}}}}catch(exc){if(FBTrace.DBG_ERRORS){FBTrace.sysout("isArray FAILS:",exc); +FBTrace.sysout("isArray Fails on obj",obj) +}}return false +},getTitle:function(object,context){return"["+object.length+"]" +}}); +this.Property=domplate(Firebug.Rep,{supportsObject:function(object){return object instanceof Property +},getRealObject:function(prop,context){return prop.object[prop.name] +},getTitle:function(prop,context){return prop.name +}}); +this.NetFile=domplate(this.Obj,{supportsObject:function(object){return object instanceof Firebug.NetFile +},browseObject:function(file,context){openNewTab(file.href); +return true +},getRealObject:function(file,context){return null +}}); +this.Except=domplate(Firebug.Rep,{tag:OBJECTBOX({_repObject:"$object"},"$object.message"),className:"exception",supportsObject:function(object){return object instanceof ErrorCopy +}}); +this.Element=domplate(Firebug.Rep,{tag:OBJECTLINK("<",SPAN({"class":"nodeTag"},"$object.nodeName|toLowerCase"),FOR("attr","$object|attrIterator"," $attr.nodeName="",SPAN({"class":"nodeValue"},"$attr.nodeValue"),"""),">"),shortTag:OBJECTLINK(SPAN({"class":"$object|getVisible"},SPAN({"class":"selectorTag"},"$object|getSelectorTag"),SPAN({"class":"selectorId"},"$object|getSelectorId"),SPAN({"class":"selectorClass"},"$object|getSelectorClass"),SPAN({"class":"selectorValue"},"$object|getValue"))),getVisible:function(elt){return isVisible(elt)?"":"selectorHidden" +},getSelectorTag:function(elt){return elt.nodeName.toLowerCase() +},getSelectorId:function(elt){return elt.id?"#"+elt.id:"" +},getSelectorClass:function(elt){return elt.className?"."+elt.className.split(" ")[0]:"" +},getValue:function(elt){return""; +var value; +if(elt instanceof HTMLImageElement){value=getFileName(elt.src) +}else{if(elt instanceof HTMLAnchorElement){value=getFileName(elt.href) +}else{if(elt instanceof HTMLInputElement){value=elt.value +}else{if(elt instanceof HTMLFormElement){value=getFileName(elt.action) +}else{if(elt instanceof HTMLScriptElement){value=getFileName(elt.src) +}}}}}return value?" "+cropString(value,20):"" +},attrIterator:function(elt){var attrs=[]; +var idAttr,classAttr; +if(elt.attributes){for(var i=0; +i0 +},hasErrorBreak:function(error){return fbs.hasErrorBreakpoint(error.href,error.lineNo) +},getMessage:function(message){var re=/\[Exception... "(.*?)" nsresult:/; +var m=re.exec(message); +return m?m[1]:message +},getLine:function(error){if(error.category=="js"){if(error.source){return cropString(error.source,80) +}else{if(error.href&&error.href.indexOf("XPCSafeJSObjectWrapper")==-1){return cropString(error.getSourceLine(),80) +}}}},getSourceLink:function(error){var ext=error.category=="css"?"css":"js"; +return error.lineNo?new SourceLink(error.href,error.lineNo,ext):null +},getSourceType:function(error){if(error.source){return"syntax" +}else{if(error.lineNo==1&&getFileExtension(error.href)!="js"){return"none" +}else{if(error.category=="css"){return"none" +}else{if(!error.href||!error.lineNo){return"none" +}else{return"exec" +}}}}},onToggleError:function(event){var target=event.currentTarget; +if(hasClass(event.target,"errorBreak")){this.breakOnThisError(target.repObject) +}else{if(hasClass(event.target,"errorSource")){var panel=Firebug.getElementPanel(event.target); +this.inspectObject(target.repObject,panel.context) +}else{if(hasClass(event.target,"errorTitle")){var traceBox=target.childNodes[1]; +toggleClass(target,"opened"); +event.target.setAttribute("aria-checked",hasClass(target,"opened")); +if(hasClass(target,"opened")){if(target.stackTrace){var node=FirebugReps.StackTrace.tag.append({object:target.stackTrace},traceBox) +}if(Firebug.A11yModel.enabled){var panel=Firebug.getElementPanel(event.target); +dispatch([Firebug.A11yModel],"onLogRowContentCreated",[panel,traceBox]) +}}else{clearNode(traceBox) +}}}}},copyError:function(error){var message=[this.getMessage(error.message),error.href,"Line "+error.lineNo]; +copyToClipboard(message.join("\n")) +},breakOnThisError:function(error){if(this.hasErrorBreak(error)){Firebug.Debugger.clearErrorBreakpoint(error.href,error.lineNo) +}else{Firebug.Debugger.setErrorBreakpoint(error.href,error.lineNo) +}},className:"errorMessage",inspectable:false,supportsObject:function(object){return object instanceof ErrorMessage +},inspectObject:function(error,context){var sourceLink=this.getSourceLink(error); +FirebugReps.SourceLink.inspectObject(sourceLink,context) +},getContextMenuItems:function(error,target,context){var breakOnThisError=this.hasErrorBreak(error); +var items=[{label:"CopyError",command:bindFixed(this.copyError,this,error)}]; +if(error.category=="css"){items.push("-",{label:"BreakOnThisError",type:"checkbox",checked:breakOnThisError,command:bindFixed(this.breakOnThisError,this,error)},optionMenu("BreakOnAllErrors","breakOnErrors")) +}return items +}}); +this.Assert=domplate(Firebug.Rep,{tag:DIV(DIV({"class":"errorTitle"}),DIV({"class":"assertDescription"})),className:"assert",inspectObject:function(error,context){var sourceLink=this.getSourceLink(error); +Firebug.chrome.select(sourceLink) +},getContextMenuItems:function(error,target,context){var breakOnThisError=this.hasErrorBreak(error); +return[{label:"CopyError",command:bindFixed(this.copyError,this,error)},"-",{label:"BreakOnThisError",type:"checkbox",checked:breakOnThisError,command:bindFixed(this.breakOnThisError,this,error)},{label:"BreakOnAllErrors",type:"checkbox",checked:Firebug.breakOnErrors,command:bindFixed(this.breakOnAllErrors,this,error)}] +}}); +this.SourceText=domplate(Firebug.Rep,{tag:DIV(FOR("line","$object|lineIterator",DIV({"class":"sourceRow",role:"presentation"},SPAN({"class":"sourceLine",role:"presentation"},"$line.lineNo"),SPAN({"class":"sourceRowText",role:"presentation"},"$line.text")))),lineIterator:function(sourceText){var maxLineNoChars=(sourceText.lines.length+"").length; +var list=[]; +for(var i=0; +i57)&&event.charCode!=45&&event.charCode!=46){FBL.cancelEvent(event) +}else{this.ignoreNextInput=event.keyCode==8 +}}}},onOverflow:function(){this.updateLayout(false,false,3) +},onKeyDown:function(event){if(event.keyCode>46||event.keyCode==32||event.keyCode==8){this.keyDownPressed=true +}},onInput:function(event){if(isIE){if(event.propertyName!="value"||!isVisible(this.input)||!this.keyDownPressed){return +}this.keyDownPressed=false +}var selectRangeCallback; +if(this.ignoreNextInput){this.ignoreNextInput=false; +this.getAutoCompleter().reset() +}else{if(this.completeAsYouType){selectRangeCallback=this.getAutoCompleter().complete(currentPanel.context,this.input,false) +}else{this.getAutoCompleter().reset() +}}Firebug.Editor.update(); +if(selectRangeCallback){if(isSafari){setTimeout(selectRangeCallback,0) +}else{selectRangeCallback() +}}},onContextMenu:function(event){cancelEvent(event); +var popup=$("fbInlineEditorPopup"); +FBL.eraseNode(popup); +var target=event.target||event.srcElement; +var menu=this.getContextMenuItems(target); +if(menu){for(var i=0; +ithis.textSize.height+3:this.noWrap&&approxTextWidth>maxWidth; +if(wrapped){var style=isIE?this.target.currentStyle:this.target.ownerDocument.defaultView.getComputedStyle(this.target,""); +targetMargin=parseInt(style.marginLeft)+parseInt(style.marginRight); +approxTextWidth=maxWidth-targetMargin; +this.input.style.width="100%"; +this.box.style.width=approxTextWidth+"px" +}else{var charWidth=this.measureInputText("m").width; +if(extraWidth){charWidth*=extraWidth +}var inputWidth=approxTextWidth+charWidth; +if(initial){if(isIE){var xDiff=13; +this.box.style.width=(inputWidth+xDiff)+"px" +}else{this.box.style.width="auto" +}}else{var xDiff=isIE?13:this.box.scrollWidth-this.input.offsetWidth; +this.box.style.width=(inputWidth+xDiff)+"px" +}this.input.style.width=inputWidth+"px" +}this.expander.style.width=approxTextWidth+"px"; +this.expander.style.height=Math.max(this.textSize.height-3,0)+"px" +}if(forceAll){scrollIntoCenterView(this.box,null,true) +}}}); +Firebug.AutoCompleter=function(getExprOffset,getRange,evaluator,selectMode,caseSensitive){var candidates=null; +var originalValue=null; +var originalOffset=-1; +var lastExpr=null; +var lastOffset=-1; +var exprOffset=0; +var lastIndex=0; +var preParsed=null; +var preExpr=null; +var postExpr=null; +this.revert=function(textBox){if(originalOffset!=-1){textBox.value=originalValue; +setSelectionRange(textBox,originalOffset,originalOffset); +this.reset(); +return true +}else{this.reset(); +return false +}}; +this.reset=function(){candidates=null; +originalValue=null; +originalOffset=-1; +lastExpr=null; +lastOffset=0; +exprOffset=0 +}; +this.complete=function(context,textBox,cycle,reverse){var value=textBox.value; +var offset=getInputSelectionStart(textBox); +if(isSafari&&!cycle&&offset>=0){offset++ +}if(!selectMode&&originalOffset!=-1){offset=originalOffset +}if(!candidates||!cycle||offset!=lastOffset){originalOffset=offset; +originalValue=value; +var parseStart=getExprOffset?getExprOffset(value,offset,context):0; +preParsed=value.substr(0,parseStart); +var parsed=value.substr(parseStart); +var range=getRange?getRange(parsed,offset-parseStart,context):null; +if(!range){range={start:0,end:parsed.length-1} +}var expr=parsed.substr(range.start,range.end-range.start+1); +preExpr=parsed.substr(0,range.start); +postExpr=parsed.substr(range.end+1); +exprOffset=parseStart+range.start; +if(!cycle){if(!expr){return +}else{if(lastExpr&&lastExpr.indexOf(expr)!=0){candidates=null +}else{if(lastExpr&&lastExpr.length>=expr.length){candidates=null; +lastExpr=expr; +return +}}}}lastExpr=expr; +lastOffset=offset; +var searchExpr; +if(expr&&offset!=parseStart+range.end+1){if(cycle){offset=range.start; +searchExpr=expr; +expr="" +}else{return +}}var values=evaluator(preExpr,expr,postExpr,context); +if(!values){return +}if(expr){candidates=[]; +if(caseSensitive){for(var i=0; +i=candidates.length){lastIndex=0 +}else{if(lastIndex<0){lastIndex=candidates.length-1 +}}var completion=candidates[lastIndex]; +var preCompletion=expr.substr(0,offset-exprOffset); +var postCompletion=completion.substr(offset-exprOffset); +textBox.value=preParsed+preExpr+preCompletion+postCompletion+postExpr; +var offsetEnd=preParsed.length+preExpr.length+completion.length; +return function(){if(selectMode){setSelectionRange(textBox,offset,offsetEnd) +}else{setSelectionRange(textBox,offsetEnd,offsetEnd) +}} +} +}; +var getDefaultEditor=function getDefaultEditor(panel){if(!defaultEditor){var doc=panel.document; +defaultEditor=new Firebug.InlineEditor(doc) +}return defaultEditor +}; +var getOutsider=function getOutsider(element,group,stepper){var parentGroup=getAncestorByClass(group.parentNode,"editGroup"); +var next; +do{next=stepper(next||element) +}while(isAncestor(next,group)||isGroupInsert(next,parentGroup)); +return next +}; +var isGroupInsert=function isGroupInsert(next,group){return(!group||isAncestor(next,group))&&(hasClass(next,"insertBefore")||hasClass(next,"insertAfter")) +}; +var getNextOutsider=function getNextOutsider(element,group){return getOutsider(element,group,bind(getNextByClass,FBL,"editable")) +}; +var getPreviousOutsider=function getPreviousOutsider(element,group){return getOutsider(element,group,bind(getPreviousByClass,FBL,"editable")) +}; +var getInlineParent=function getInlineParent(element){var lastInline=element; +for(; +element; +element=element.parentNode){var s=isIE?element.currentStyle:element.ownerDocument.defaultView.getComputedStyle(element,""); +if(s.display!="inline"){return lastInline +}else{lastInline=element +}}return null +}; +var insertTab=function insertTab(){insertTextIntoElement(currentEditor.input,Firebug.Editor.tabCharacter) +}; +Firebug.registerModule(Firebug.Editor) +}}); +FBL.ns(function(){with(FBL){var ElementCache=Firebug.Lite.Cache.Element; +var inspectorTS,inspectorTimer,isInspecting; +Firebug.Inspector={create:function(){offlineFragment=Env.browser.document.createDocumentFragment(); +createBoxModelInspector(); +createOutlineInspector() +},destroy:function(){destroyBoxModelInspector(); +destroyOutlineInspector(); +offlineFragment=null +},toggleInspect:function(){if(isInspecting){this.stopInspecting() +}else{Firebug.chrome.inspectButton.changeState("pressed"); +this.startInspecting() +}},startInspecting:function(){isInspecting=true; +Firebug.chrome.selectPanel("HTML"); +createInspectorFrame(); +var size=Firebug.browser.getWindowScrollSize(); +fbInspectFrame.style.width=size.width+"px"; +fbInspectFrame.style.height=size.height+"px"; +addEvent(fbInspectFrame,"mousemove",Firebug.Inspector.onInspecting); +addEvent(fbInspectFrame,"mousedown",Firebug.Inspector.onInspectingClick) +},stopInspecting:function(){isInspecting=false; +if(outlineVisible){this.hideOutline() +}removeEvent(fbInspectFrame,"mousemove",Firebug.Inspector.onInspecting); +removeEvent(fbInspectFrame,"mousedown",Firebug.Inspector.onInspectingClick); +destroyInspectorFrame(); +Firebug.chrome.inspectButton.restore(); +if(Firebug.chrome.type=="popup"){Firebug.chrome.node.focus() +}},onInspectingClick:function(e){fbInspectFrame.style.display="none"; +var targ=Firebug.browser.getElementFromPoint(e.clientX,e.clientY); +fbInspectFrame.style.display="block"; +var id=targ.id; +if(id&&/^fbOutline\w$/.test(id)){return +}if(id=="FirebugUI"){return +}while(targ.nodeType!=1){targ=targ.parentNode +}Firebug.Inspector.stopInspecting() +},onInspecting:function(e){if(new Date().getTime()-lastInspecting>30){fbInspectFrame.style.display="none"; +var targ=Firebug.browser.getElementFromPoint(e.clientX,e.clientY); +fbInspectFrame.style.display="block"; +var id=targ.id; +if(id&&/^fbOutline\w$/.test(id)){return +}if(id=="FirebugUI"){return +}while(targ.nodeType!=1){targ=targ.parentNode +}if(targ.nodeName.toLowerCase()=="body"){return +}Firebug.Inspector.drawOutline(targ); +if(ElementCache(targ)){var target=""+ElementCache.key(targ); +var lazySelect=function(){inspectorTS=new Date().getTime(); +Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)) +}; +if(inspectorTimer){clearTimeout(inspectorTimer); +inspectorTimer=null +}if(new Date().getTime()-inspectorTS>200){setTimeout(lazySelect,0) +}else{inspectorTimer=setTimeout(lazySelect,300) +}}lastInspecting=new Date().getTime() +}},onInspectingBody:function(e){if(new Date().getTime()-lastInspecting>30){var targ=e.target; +var id=targ.id; +if(id&&/^fbOutline\w$/.test(id)){return +}if(id=="FirebugUI"){return +}while(targ.nodeType!=1){targ=targ.parentNode +}if(targ.nodeName.toLowerCase()=="body"){return +}Firebug.Inspector.drawOutline(targ); +if(ElementCache.has(targ)){FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)) +}lastInspecting=new Date().getTime() +}},drawOutline:function(el){var border=2; +var scrollbarSize=17; +var windowSize=Firebug.browser.getWindowSize(); +var scrollSize=Firebug.browser.getWindowScrollSize(); +var scrollPosition=Firebug.browser.getWindowScrollPosition(); +var box=Firebug.browser.getElementBox(el); +var top=box.top; +var left=box.left; +var height=box.height; +var width=box.width; +var freeHorizontalSpace=scrollPosition.left+windowSize.width-left-width-(!isIE&&scrollSize.height>windowSize.height?scrollbarSize:0); +var freeVerticalSpace=scrollPosition.top+windowSize.height-top-height-(!isIE&&scrollSize.width>windowSize.width?scrollbarSize:0); +var numVerticalBorders=freeVerticalSpace>0?2:1; +var o=outlineElements; +var style; +style=o.fbOutlineT.style; +style.top=top-border+"px"; +style.left=left+"px"; +style.height=border+"px"; +style.width=width+"px"; +style=o.fbOutlineL.style; +style.top=top-border+"px"; +style.left=left-border+"px"; +style.height=height+numVerticalBorders*border+"px"; +style.width=border+"px"; +style=o.fbOutlineB.style; +if(freeVerticalSpace>0){style.top=top+height+"px"; +style.left=left+"px"; +style.width=width+"px" +}else{style.top=-2*border+"px"; +style.left=-2*border+"px"; +style.width=border+"px" +}style=o.fbOutlineR.style; +if(freeHorizontalSpace>0){style.top=top-border+"px"; +style.left=left+width+"px"; +style.height=height+numVerticalBorders*border+"px"; +style.width=(freeHorizontalSpacescrollPosition.top+windowSize.height-offsetHeight||box.left>scrollPosition.left+windowSize.width||scrollPosition.top>box.top+box.height||scrollPosition.left>box.left+box.width){return +}var top=box.top; +var left=box.left; +var height=box.height; +var width=box.width; +var margin=Firebug.browser.getMeasurementBox(el,"margin"); +var padding=Firebug.browser.getMeasurementBox(el,"padding"); +var border=Firebug.browser.getMeasurementBox(el,"border"); +boxModelStyle.top=top-margin.top+"px"; +boxModelStyle.left=left-margin.left+"px"; +boxModelStyle.height=height+margin.top+margin.bottom+"px"; +boxModelStyle.width=width+margin.left+margin.right+"px"; +boxBorderStyle.top=margin.top+"px"; +boxBorderStyle.left=margin.left+"px"; +boxBorderStyle.height=height+"px"; +boxBorderStyle.width=width+"px"; +boxPaddingStyle.top=margin.top+border.top+"px"; +boxPaddingStyle.left=margin.left+border.left+"px"; +boxPaddingStyle.height=height-border.top-border.bottom+"px"; +boxPaddingStyle.width=width-border.left-border.right+"px"; +boxContentStyle.top=margin.top+border.top+padding.top+"px"; +boxContentStyle.left=margin.left+border.left+padding.left+"px"; +boxContentStyle.height=height-border.top-padding.top-padding.bottom-border.bottom+"px"; +boxContentStyle.width=width-border.left-padding.left-padding.right-border.right+"px"; +if(!boxModelVisible){this.showBoxModel() +}},hideBoxModel:function(){if(!boxModelVisible){return +}offlineFragment.appendChild(boxModel); +boxModelVisible=false +},showBoxModel:function(){if(boxModelVisible){return +}if(outlineVisible){this.hideOutline() +}Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel); +boxModelVisible=true +}}; +var offlineFragment=null; +var boxModelVisible=false; +var boxModel,boxModelStyle,boxMargin,boxMarginStyle,boxBorder,boxBorderStyle,boxPadding,boxPaddingStyle,boxContent,boxContentStyle; +var resetStyle="margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; +var offscreenStyle=resetStyle+"top:-1234px; left:-1234px;"; +var inspectStyle=resetStyle+"z-index: 2147483500;"; +var inspectFrameStyle=resetStyle+"z-index: 2147483550; top:0; left:0; background:url("+Env.Location.skinDir+"pixel_transparent.gif);"; +var inspectModelOpacity=isIE?"filter:alpha(opacity=80);":"opacity:0.8;"; +var inspectModelStyle=inspectStyle+inspectModelOpacity; +var inspectMarginStyle=inspectStyle+"background: #EDFF64; height:100%; width:100%;"; +var inspectBorderStyle=inspectStyle+"background: #666;"; +var inspectPaddingStyle=inspectStyle+"background: SlateBlue;"; +var inspectContentStyle=inspectStyle+"background: SkyBlue;"; +var outlineStyle={fbHorizontalLine:"background: #3875D7;height: 2px;",fbVerticalLine:"background: #3875D7;width: 2px;"}; +var lastInspecting=0; +var fbInspectFrame=null; +var outlineVisible=false; +var outlineElements={}; +var outline={fbOutlineT:"fbHorizontalLine",fbOutlineL:"fbVerticalLine",fbOutlineB:"fbHorizontalLine",fbOutlineR:"fbVerticalLine"}; +var getInspectingTarget=function(){}; +var createInspectorFrame=function createInspectorFrame(){fbInspectFrame=createGlobalElement("div"); +fbInspectFrame.id="fbInspectFrame"; +fbInspectFrame.firebugIgnore=true; +fbInspectFrame.style.cssText=inspectFrameStyle; +Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame) +}; +var destroyInspectorFrame=function destroyInspectorFrame(){if(fbInspectFrame){Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame); +fbInspectFrame=null +}}; +var createOutlineInspector=function createOutlineInspector(){for(var name in outline){var el=outlineElements[name]=createGlobalElement("div"); +el.id=name; +el.firebugIgnore=true; +el.style.cssText=inspectStyle+outlineStyle[outline[name]]; +offlineFragment.appendChild(el) +}}; +var destroyOutlineInspector=function destroyOutlineInspector(){for(var name in outline){var el=outlineElements[name]; +el.parentNode.removeChild(el) +}}; +var createBoxModelInspector=function createBoxModelInspector(){boxModel=createGlobalElement("div"); +boxModel.id="fbBoxModel"; +boxModel.firebugIgnore=true; +boxModelStyle=boxModel.style; +boxModelStyle.cssText=inspectModelStyle; +boxMargin=createGlobalElement("div"); +boxMargin.id="fbBoxMargin"; +boxMarginStyle=boxMargin.style; +boxMarginStyle.cssText=inspectMarginStyle; +boxModel.appendChild(boxMargin); +boxBorder=createGlobalElement("div"); +boxBorder.id="fbBoxBorder"; +boxBorderStyle=boxBorder.style; +boxBorderStyle.cssText=inspectBorderStyle; +boxModel.appendChild(boxBorder); +boxPadding=createGlobalElement("div"); +boxPadding.id="fbBoxPadding"; +boxPaddingStyle=boxPadding.style; +boxPaddingStyle.cssText=inspectPaddingStyle; +boxModel.appendChild(boxPadding); +boxContent=createGlobalElement("div"); +boxContent.id="fbBoxContent"; +boxContentStyle=boxContent.style; +boxContentStyle.cssText=inspectContentStyle; +boxModel.appendChild(boxContent); +offlineFragment.appendChild(boxModel) +}; +var destroyBoxModelInspector=function destroyBoxModelInspector(){boxModel.parentNode.removeChild(boxModel) +} +}}); +FBL.ns(function(){with(FBL){var consoleQueue=[]; +var lastHighlightedObject; +var FirebugContext=Env.browser; +var maxQueueRequests=500; +Firebug.ConsoleBase={log:function(object,context,className,rep,noThrottle,sourceLink){return this.logRow(appendObject,object,context,className,rep,sourceLink,noThrottle) +},logFormatted:function(objects,context,className,noThrottle,sourceLink){return this.logRow(appendFormatted,objects,context,className,null,sourceLink,noThrottle) +},openGroup:function(objects,context,className,rep,noThrottle,sourceLink,noPush){return this.logRow(appendOpenGroup,objects,context,className,rep,sourceLink,noThrottle) +},closeGroup:function(context,noThrottle){return this.logRow(appendCloseGroup,null,context,null,null,null,noThrottle,true) +},logRow:function(appender,objects,context,className,rep,sourceLink,noThrottle,noRow){noThrottle=true; +if(!context){context=FirebugContext +}if(FBTrace.DBG_ERRORS&&!context){FBTrace.sysout("Console.logRow has no context, skipping objects",objects) +}if(!context){return +}if(noThrottle||!context){var panel=this.getPanel(context); +if(panel){var row=panel.append(appender,objects,className,rep,sourceLink,noRow); +var container=panel.panelNode; +return row +}else{consoleQueue.push([appender,objects,context,className,rep,sourceLink,noThrottle,noRow]) +}}else{if(!context.throttle){return +}var args=[appender,objects,context,className,rep,sourceLink,true,noRow]; +context.throttle(this.logRow,this,args) +}},appendFormatted:function(args,row,context){if(!context){context=FirebugContext +}var panel=this.getPanel(context); +panel.appendFormatted(args,row) +},clear:function(context){if(!context){context=Firebug.context +}var panel=this.getPanel(context,true); +if(panel){panel.clear() +}},getPanel:function(context,noCreate){return Firebug.chrome?Firebug.chrome.getPanel("Console"):null +}}; +var ActivableConsole=extend(Firebug.ConsoleBase,{isAlwaysEnabled:function(){return true +}}); +Firebug.Console=Firebug.Console=extend(ActivableConsole,{dispatchName:"console",error:function(){Firebug.Console.logFormatted(arguments,Firebug.browser,"error") +},flush:function(){dispatch(this.fbListeners,"flush",[]); +for(var i=0,length=consoleQueue.length; +iobjects.length){format=""; +objIndex=-1; +parts.length=0; +break +}}}for(var i=0; +i1){traceRecursion--; +return +}var frames=[]; +for(var fn=arguments.callee.caller.caller; +fn; +fn=fn.caller){if(wasVisited(fn)){break +}var args=[]; +for(var i=0,l=fn.arguments.length; +i1){objects=[errorObject]; +for(var i=1; +i0)){var oldest=frames.length-1; +for(var i=0; +i0&&commandHistory.length>0){this.element.value=commandHistory[--commandPointer] +}},nextCommand:function(){var element=this.element; +var limit=commandHistory.length-1; +var i=commandPointer; +if(i=0&&i',msg,"",'"] +},onKeyDown:function(e){e=e||event; +var code=e.keyCode; +if(code!=9&&code!=16&&code!=17&&code!=18){isAutoCompleting=false +}if(code==13){this.enter(); +this.clear() +}else{if(code==27){setTimeout(this.clear,0) +}else{if(code==38){this.prevCommand() +}else{if(code==40){this.nextCommand() +}else{if(code==9){this.autocomplete(e.shiftKey) +}else{return +}}}}}cancelEvent(e,true); +return false +},onMultiLineKeyDown:function(e){e=e||event; +var code=e.keyCode; +if(code==13&&e.ctrlKey){this.enter() +}}}); +Firebug.registerModule(Firebug.CommandLine); +function getExpressionOffset(command){var bracketCount=0; +var start=command.length-1; +for(; +start>=0; +--start){var c=command[start]; +if((c==","||c==";"||c==" ")&&!bracketCount){break +}if(reOpenBracket.test(c)){if(bracketCount){--bracketCount +}else{break +}}else{if(reCloseBracket.test(c)){++bracketCount +}}}return start+1 +}var CommandLineAPI={$:function(id){return Firebug.browser.document.getElementById(id) +},$$:function(selector,context){context=context||Firebug.browser.document; +return Firebug.Selector?Firebug.Selector(selector,context):Firebug.Console.error("Firebug.Selector module not loaded.") +},$0:null,$1:null,dir:function(o){Firebug.Console.log(o,Firebug.context,"dir",Firebug.DOMPanel.DirTable) +},dirxml:function(o){if(instanceOf(o,"Window")){o=o.document.documentElement +}else{if(instanceOf(o,"Document")){o=o.documentElement +}}var div=Firebug.Console.log(o,Firebug.context,"dirxml"); +var html=[]; +Firebug.Reps.appendNode(o,html); +div.innerHTML=html.join("") +}}; +var defineCommandLineAPI=function defineCommandLineAPI(){Firebug.CommandLine.API={}; +for(var m in CommandLineAPI){if(!Env.browser.window[m]){Firebug.CommandLine.API[m]=CommandLineAPI[m] +}}var stack=FirebugChrome.htmlSelectionStack; +if(stack){Firebug.CommandLine.API.$0=stack[0]; +Firebug.CommandLine.API.$1=stack[1] +}} +}}); +FBL.ns(function(){with(FBL){if(Env.Options.disableXHRListener){return +}var XHRSpy=function(){this.requestHeaders=[]; +this.responseHeaders=[] +}; +XHRSpy.prototype={method:null,url:null,async:null,xhrRequest:null,href:null,loaded:false,logRow:null,responseText:null,requestHeaders:null,responseHeaders:null,sourceLink:null,getURL:function(){return this.href +}}; +var XMLHttpRequestWrapper=function(activeXObject){var xhrRequest=typeof activeXObject!="undefined"?activeXObject:new _XMLHttpRequest(),spy=new XHRSpy(),self=this,reqType,reqUrl,reqStartTS; +var updateSelfPropertiesIgnore={abort:1,channel:1,getAllResponseHeaders:1,getInterface:1,getResponseHeader:1,mozBackgroundRequest:1,multipart:1,onreadystatechange:1,open:1,send:1,setRequestHeader:1}; +var updateSelfProperties=function(){if(supportsXHRIterator){for(var propName in xhrRequest){if(propName in updateSelfPropertiesIgnore){continue +}try{var propValue=xhrRequest[propName]; +if(propValue&&!isFunction(propValue)){self[propName]=propValue +}}catch(E){}}}else{if(xhrRequest.readyState==4){self.status=xhrRequest.status; +self.statusText=xhrRequest.statusText; +self.responseText=xhrRequest.responseText; +self.responseXML=xhrRequest.responseXML +}}}; +var updateXHRPropertiesIgnore={channel:1,onreadystatechange:1,readyState:1,responseBody:1,responseText:1,responseXML:1,status:1,statusText:1,upload:1}; +var updateXHRProperties=function(){for(var propName in self){if(propName in updateXHRPropertiesIgnore){continue +}try{var propValue=self[propName]; +if(propValue&&!xhrRequest[propName]){xhrRequest[propName]=propValue +}}catch(E){}}}; +var logXHR=function(){var row=Firebug.Console.log(spy,null,"spy",Firebug.Spy.XHR); +if(row){setClass(row,"loading"); +spy.logRow=row +}}; +var finishXHR=function(){var duration=new Date().getTime()-reqStartTS; +var success=xhrRequest.status==200; +var responseHeadersText=xhrRequest.getAllResponseHeaders(); +var responses=responseHeadersText?responseHeadersText.split(/[\n\r]/):[]; +var reHeader=/^(\S+):\s*(.*)/; +for(var i=0,l=responses.length; +i0; +return this +}; +var _ActiveXObject; +var isIE6=/msie 6/i.test(navigator.appVersion); +if(isIE6){_ActiveXObject=window.ActiveXObject; +var xhrObjects=" MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP "; +window.ActiveXObject=function(name){var error=null; +try{var activeXObject=new _ActiveXObject(name) +}catch(e){error=e +}finally{if(!error){if(xhrObjects.indexOf(" "+name+" ")!=-1){return new XMLHttpRequestWrapper(activeXObject) +}else{return activeXObject +}}else{throw error.message +}}} +}if(!isIE6){var _XMLHttpRequest=XMLHttpRequest; +window.XMLHttpRequest=function(){return new XMLHttpRequestWrapper() +} +}}}); +FBL.ns(function(){with(FBL){var reIgnore=/about:|javascript:|resource:|chrome:|jar:/; +var layoutInterval=300; +var indentWidth=18; +var cacheSession=null; +var contexts=new Array(); +var panelName="net"; +var maxQueueRequests=500; +var activeRequests=[]; +var mimeExtensionMap={txt:"text/plain",html:"text/html",htm:"text/html",xhtml:"text/html",xml:"text/xml",css:"text/css",js:"application/x-javascript",jss:"application/x-javascript",jpg:"image/jpg",jpeg:"image/jpeg",gif:"image/gif",png:"image/png",bmp:"image/bmp",swf:"application/x-shockwave-flash",flv:"video/x-flv"}; +var fileCategories={"undefined":1,html:1,css:1,js:1,xhr:1,image:1,flash:1,txt:1,bin:1}; +var textFileCategories={txt:1,html:1,xhr:1,css:1,js:1}; +var binaryFileCategories={bin:1,flash:1}; +var mimeCategoryMap={"text/plain":"txt","application/octet-stream":"bin","text/html":"html","text/xml":"html","text/css":"css","application/x-javascript":"js","text/javascript":"js","application/javascript":"js","image/jpeg":"image","image/jpg":"image","image/gif":"image","image/png":"image","image/bmp":"image","application/x-shockwave-flash":"flash","video/x-flv":"flash"}; +var binaryCategoryMap={image:1,flash:1}; +Firebug.NetMonitor=extend(Firebug.ActivableModule,{dispatchName:"netMonitor",clear:function(context){var panel=context.getPanel(panelName,true); +if(panel){panel.clear() +}},initialize:function(){return; +this.panelName=panelName; +Firebug.ActivableModule.initialize.apply(this,arguments); +if(Firebug.TraceModule){Firebug.TraceModule.addListener(this.TraceListener) +}NetHttpObserver.registerObserver(); +NetHttpActivityObserver.registerObserver(); +Firebug.Debugger.addListener(this.DebuggerListener) +},shutdown:function(){return; +prefs.removeObserver(Firebug.prefDomain,this,false); +if(Firebug.TraceModule){Firebug.TraceModule.removeListener(this.TraceListener) +}NetHttpObserver.unregisterObserver(); +NetHttpActivityObserver.unregisterObserver(); +Firebug.Debugger.removeListener(this.DebuggerListener) +}}); +Firebug.NetMonitor.NetInfoBody=domplate(Firebug.Rep,new Firebug.Listener(),{tag:DIV({"class":"netInfoBody",_repObject:"$file"},TAG("$infoTabs",{file:"$file"}),TAG("$infoBodies",{file:"$file"})),infoTabs:DIV({"class":"netInfoTabs focusRow subFocusRow",role:"tablist"},A({"class":"netInfoParamsTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Params",$collapsed:"$file|hideParams"},$STR("URLParameters")),A({"class":"netInfoHeadersTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Headers"},$STR("Headers")),A({"class":"netInfoPostTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Post",$collapsed:"$file|hidePost"},$STR("Post")),A({"class":"netInfoPutTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Put",$collapsed:"$file|hidePut"},$STR("Put")),A({"class":"netInfoResponseTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Response",$collapsed:"$file|hideResponse"},$STR("Response")),A({"class":"netInfoCacheTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Cache",$collapsed:"$file|hideCache"},$STR("Cache")),A({"class":"netInfoHtmlTab netInfoTab a11yFocus",onclick:"$onClickTab",role:"tab",view:"Html",$collapsed:"$file|hideHtml"},$STR("HTML"))),infoBodies:DIV({"class":"netInfoBodies outerFocusRow"},TABLE({"class":"netInfoParamsText netInfoText netInfoParamsTable",role:"tabpanel",cellpadding:0,cellspacing:0},TBODY()),DIV({"class":"netInfoHeadersText netInfoText",role:"tabpanel"}),DIV({"class":"netInfoPostText netInfoText",role:"tabpanel"}),DIV({"class":"netInfoPutText netInfoText",role:"tabpanel"}),PRE({"class":"netInfoResponseText netInfoText",role:"tabpanel"}),DIV({"class":"netInfoCacheText netInfoText",role:"tabpanel"},TABLE({"class":"netInfoCacheTable",cellpadding:0,cellspacing:0,role:"presentation"},TBODY({role:"list","aria-label":$STR("Cache")}))),DIV({"class":"netInfoHtmlText netInfoText",role:"tabpanel"},IFRAME({"class":"netInfoHtmlPreview",role:"document"}))),headerDataTag:FOR("param","$headers",TR({role:"listitem"},TD({"class":"netInfoParamName",role:"presentation"},TAG("$param|getNameTag",{param:"$param"})),TD({"class":"netInfoParamValue",role:"list","aria-label":"$param.name"},FOR("line","$param|getParamValueIterator",CODE({"class":"focusRow subFocusRow",role:"listitem"},"$line"))))),customTab:A({"class":"netInfo$tabId\\Tab netInfoTab",onclick:"$onClickTab",view:"$tabId",role:"tab"},"$tabTitle"),customBody:DIV({"class":"netInfo$tabId\\Text netInfoText",role:"tabpanel"}),nameTag:SPAN("$param|getParamName"),nameWithTooltipTag:SPAN({title:"$param.name"},"$param|getParamName"),getNameTag:function(param){return(this.getParamName(param)==param.name)?this.nameTag:this.nameWithTooltipTag +},getParamName:function(param){var limit=25; +var name=param.name; +if(name.length>limit){name=name.substr(0,limit)+"..." +}return name +},getParamTitle:function(param){var limit=25; +var name=param.name; +if(name.length>limit){return name +}return"" +},hideParams:function(file){return !file.urlParams||!file.urlParams.length +},hidePost:function(file){return file.method.toUpperCase()!="POST" +},hidePut:function(file){return file.method.toUpperCase()!="PUT" +},hideResponse:function(file){return false +},hideCache:function(file){return true; +return !file.cacheEntry +},hideHtml:function(file){return(file.mimeType!="text/html")&&(file.mimeType!="application/xhtml+xml") +},onClickTab:function(event){this.selectTab(event.currentTarget||event.srcElement) +},getParamValueIterator:function(param){return param.value; +return wrapText(param.value,true) +},appendTab:function(netInfoBox,tabId,tabTitle){var args={tabId:tabId,tabTitle:tabTitle}; +this.customTab.append(args,$$(".netInfoTabs",netInfoBox)[0]); +this.customBody.append(args,$$(".netInfoBodies",netInfoBox)[0]) +},selectTabByName:function(netInfoBox,tabName){var tab=getChildByClass(netInfoBox,"netInfoTabs","netInfo"+tabName+"Tab"); +if(tab){this.selectTab(tab) +}},selectTab:function(tab){var view=tab.getAttribute("view"); +var netInfoBox=getAncestorByClass(tab,"netInfoBody"); +var selectedTab=netInfoBox.selectedTab; +if(selectedTab){removeClass(netInfoBox.selectedText,"netInfoTextSelected"); +removeClass(selectedTab,"netInfoTabSelected"); +selectedTab.setAttribute("aria-selected","false") +}var textBodyName="netInfo"+view+"Text"; +selectedTab=netInfoBox.selectedTab=tab; +netInfoBox.selectedText=$$("."+textBodyName,netInfoBox)[0]; +setClass(netInfoBox.selectedText,"netInfoTextSelected"); +setClass(selectedTab,"netInfoTabSelected"); +selectedTab.setAttribute("selected","true"); +selectedTab.setAttribute("aria-selected","true"); +var file=Firebug.getRepObject(netInfoBox); +var context=Firebug.chrome; +this.updateInfo(netInfoBox,file,context) +},updateInfo:function(netInfoBox,file,context){if(FBTrace.DBG_NET){FBTrace.sysout("net.updateInfo; file",file) +}if(!netInfoBox){if(FBTrace.DBG_NET||FBTrace.DBG_ERRORS){FBTrace.sysout("net.updateInfo; ERROR netInfo == null "+file.href,file) +}return +}var tab=netInfoBox.selectedTab; +if(hasClass(tab,"netInfoParamsTab")){if(file.urlParams&&!netInfoBox.urlParamsPresented){netInfoBox.urlParamsPresented=true; +this.insertHeaderRows(netInfoBox,file.urlParams,"Params") +}}else{if(hasClass(tab,"netInfoHeadersTab")){var headersText=$$(".netInfoHeadersText",netInfoBox)[0]; +if(file.responseHeaders&&!netInfoBox.responseHeadersPresented){netInfoBox.responseHeadersPresented=true; +NetInfoHeaders.renderHeaders(headersText,file.responseHeaders,"ResponseHeaders") +}if(file.requestHeaders&&!netInfoBox.requestHeadersPresented){netInfoBox.requestHeadersPresented=true; +NetInfoHeaders.renderHeaders(headersText,file.requestHeaders,"RequestHeaders") +}}else{if(hasClass(tab,"netInfoPostTab")){if(!netInfoBox.postPresented){netInfoBox.postPresented=true; +var postText=$$(".netInfoPostText",netInfoBox)[0]; +NetInfoPostData.render(context,postText,file) +}}else{if(hasClass(tab,"netInfoPutTab")){if(!netInfoBox.putPresented){netInfoBox.putPresented=true; +var putText=$$(".netInfoPutText",netInfoBox)[0]; +NetInfoPostData.render(context,putText,file) +}}else{if(hasClass(tab,"netInfoResponseTab")&&file.loaded&&!netInfoBox.responsePresented){var responseTextBox=$$(".netInfoResponseText",netInfoBox)[0]; +if(file.category=="image"){netInfoBox.responsePresented=true; +var responseImage=netInfoBox.ownerDocument.createElement("img"); +responseImage.src=file.href; +clearNode(responseTextBox); +responseTextBox.appendChild(responseImage,responseTextBox) +}else{this.setResponseText(file,netInfoBox,responseTextBox,context) +}}else{if(hasClass(tab,"netInfoCacheTab")&&file.loaded&&!netInfoBox.cachePresented){var responseTextBox=netInfoBox.getElementsByClassName("netInfoCacheText").item(0); +if(file.cacheEntry){netInfoBox.cachePresented=true; +this.insertHeaderRows(netInfoBox,file.cacheEntry,"Cache") +}}else{if(hasClass(tab,"netInfoHtmlTab")&&file.loaded&&!netInfoBox.htmlPresented){netInfoBox.htmlPresented=true; +var text=Utils.getResponseText(file,context); +var iframe=$$(".netInfoHtmlPreview",netInfoBox)[0]; +var reScript=//gi; +text=text.replace(reScript,""); +iframe.contentWindow.document.write(text); +iframe.contentWindow.document.close() +}}}}}}}dispatch(NetInfoBody.fbListeners,"updateTabBody",[netInfoBox,file,context]) +},setResponseText:function(file,netInfoBox,responseTextBox,context){netInfoBox.responsePresented=true; +if(isIE){responseTextBox.style.whiteSpace="nowrap" +}responseTextBox[typeof responseTextBox.textContent!="undefined"?"textContent":"innerText"]=file.responseText; +return; +var text=Utils.getResponseText(file,context); +var limit=Firebug.netDisplayedResponseLimit+15; +var limitReached=text?(text.length>limit):false; +if(limitReached){text=text.substr(0,limit)+"..." +}if(text){insertWrappedText(text,responseTextBox) +}else{insertWrappedText("",responseTextBox) +}if(limitReached){var object={text:$STR("net.responseSizeLimitMessage"),onClickLink:function(){var panel=context.getPanel("net",true); +panel.openResponseInTab(file) +}}; +Firebug.NetMonitor.ResponseSizeLimit.append(object,responseTextBox) +}netInfoBox.responsePresented=true; +if(FBTrace.DBG_NET){FBTrace.sysout("net.setResponseText; response text updated") +}},insertHeaderRows:function(netInfoBox,headers,tableName,rowName){if(!headers.length){return +}var headersTable=$$(".netInfo"+tableName+"Table",netInfoBox)[0]; +var tbody=getChildByClass(headersTable,"netInfo"+rowName+"Body"); +if(!tbody){tbody=headersTable.firstChild +}var titleRow=getChildByClass(tbody,"netInfo"+rowName+"Title"); +this.headerDataTag.insertRows({headers:headers},titleRow?titleRow:tbody); +removeClass(titleRow,"collapsed") +}}); +var NetInfoBody=Firebug.NetMonitor.NetInfoBody; +Firebug.NetMonitor.NetInfoHeaders=domplate(Firebug.Rep,{tag:DIV({"class":"netInfoHeadersTable",role:"tabpanel"},DIV({"class":"netInfoHeadersGroup netInfoResponseHeadersTitle"},SPAN($STR("ResponseHeaders")),SPAN({"class":"netHeadersViewSource response collapsed",onclick:"$onViewSource",_sourceDisplayed:false,_rowName:"ResponseHeaders"},$STR("net.headers.view source"))),TABLE({cellpadding:0,cellspacing:0},TBODY({"class":"netInfoResponseHeadersBody",role:"list","aria-label":$STR("ResponseHeaders")})),DIV({"class":"netInfoHeadersGroup netInfoRequestHeadersTitle"},SPAN($STR("RequestHeaders")),SPAN({"class":"netHeadersViewSource request collapsed",onclick:"$onViewSource",_sourceDisplayed:false,_rowName:"RequestHeaders"},$STR("net.headers.view source"))),TABLE({cellpadding:0,cellspacing:0},TBODY({"class":"netInfoRequestHeadersBody",role:"list","aria-label":$STR("RequestHeaders")}))),sourceTag:TR({role:"presentation"},TD({colspan:2,role:"presentation"},PRE({"class":"source"}))),onViewSource:function(event){var target=event.target; +var requestHeaders=(target.rowName=="RequestHeaders"); +var netInfoBox=getAncestorByClass(target,"netInfoBody"); +var file=netInfoBox.repObject; +if(target.sourceDisplayed){var headers=requestHeaders?file.requestHeaders:file.responseHeaders; +this.insertHeaderRows(netInfoBox,headers,target.rowName); +target.innerHTML=$STR("net.headers.view source") +}else{var source=requestHeaders?file.requestHeadersText:file.responseHeadersText; +this.insertSource(netInfoBox,source,target.rowName); +target.innerHTML=$STR("net.headers.pretty print") +}target.sourceDisplayed=!target.sourceDisplayed; +cancelEvent(event) +},insertSource:function(netInfoBox,source,rowName){var tbody=$$(".netInfo"+rowName+"Body",netInfoBox)[0]; +var node=this.sourceTag.replace({},tbody); +var sourceNode=$$(".source",node)[0]; +sourceNode.innerHTML=source +},insertHeaderRows:function(netInfoBox,headers,rowName){var headersTable=$$(".netInfoHeadersTable",netInfoBox)[0]; +var tbody=$$(".netInfo"+rowName+"Body",headersTable)[0]; +clearNode(tbody); +if(!headers.length){return +}NetInfoBody.headerDataTag.insertRows({headers:headers},tbody); +var titleRow=getChildByClass(headersTable,"netInfo"+rowName+"Title"); +removeClass(titleRow,"collapsed") +},init:function(parent){var rootNode=this.tag.append({},parent); +var netInfoBox=getAncestorByClass(parent,"netInfoBody"); +var file=netInfoBox.repObject; +var viewSource; +viewSource=$$(".request",rootNode)[0]; +if(file.requestHeadersText){removeClass(viewSource,"collapsed") +}viewSource=$$(".response",rootNode)[0]; +if(file.responseHeadersText){removeClass(viewSource,"collapsed") +}},renderHeaders:function(parent,headers,rowName){if(!parent.firstChild){this.init(parent) +}this.insertHeaderRows(parent,headers,rowName) +}}); +var NetInfoHeaders=Firebug.NetMonitor.NetInfoHeaders; +Firebug.NetMonitor.NetInfoPostData=domplate(Firebug.Rep,{paramsTable:TABLE({"class":"netInfoPostParamsTable",cellpadding:0,cellspacing:0,role:"presentation"},TBODY({role:"list","aria-label":$STR("net.label.Parameters")},TR({"class":"netInfoPostParamsTitle",role:"presentation"},TD({colspan:3,role:"presentation"},DIV({"class":"netInfoPostParams"},$STR("net.label.Parameters"),SPAN({"class":"netInfoPostContentType"},"application/x-www-form-urlencoded")))))),partsTable:TABLE({"class":"netInfoPostPartsTable",cellpadding:0,cellspacing:0,role:"presentation"},TBODY({role:"list","aria-label":$STR("net.label.Parts")},TR({"class":"netInfoPostPartsTitle",role:"presentation"},TD({colspan:2,role:"presentation"},DIV({"class":"netInfoPostParams"},$STR("net.label.Parts"),SPAN({"class":"netInfoPostContentType"},"multipart/form-data")))))),jsonTable:TABLE({"class":"netInfoPostJSONTable",cellpadding:0,cellspacing:0,role:"presentation"},TBODY({role:"list","aria-label":$STR("JSON")},TR({"class":"netInfoPostJSONTitle",role:"presentation"},TD({role:"presentation"},DIV({"class":"netInfoPostParams"},$STR("JSON")))),TR(TD({"class":"netInfoPostJSONBody"})))),xmlTable:TABLE({"class":"netInfoPostXMLTable",cellpadding:0,cellspacing:0,role:"presentation"},TBODY({role:"list","aria-label":$STR("xmlviewer.tab.XML")},TR({"class":"netInfoPostXMLTitle",role:"presentation"},TD({role:"presentation"},DIV({"class":"netInfoPostParams"},$STR("xmlviewer.tab.XML")))),TR(TD({"class":"netInfoPostXMLBody"})))),sourceTable:TABLE({"class":"netInfoPostSourceTable",cellpadding:0,cellspacing:0,role:"presentation"},TBODY({role:"list","aria-label":$STR("net.label.Source")},TR({"class":"netInfoPostSourceTitle",role:"presentation"},TD({colspan:2,role:"presentation"},DIV({"class":"netInfoPostSource"},$STR("net.label.Source")))))),sourceBodyTag:TR({role:"presentation"},TD({colspan:2,role:"presentation"},FOR("line","$param|getParamValueIterator",CODE({"class":"focusRow subFocusRow",role:"listitem"},"$line")))),getParamValueIterator:function(param){return NetInfoBody.getParamValueIterator(param) +},render:function(context,parentNode,file){var spy=getAncestorByClass(parentNode,"spyHead"); +var spyObject=spy.repObject; +var data=spyObject.data; +var contentType=file.mimeType; +if(contentType&&contentType=="application/x-www-form-urlencoded"||data&&data.indexOf("=")!=-1){var params=parseURLEncodedTextArray(data); +if(params){this.insertParameters(parentNode,params) +}}var jsonData={responseText:data}; +if(Firebug.JSONViewerModel.isJSON(contentType,data)){this.insertJSON(parentNode,jsonData,context) +}var postText=data; +if(postText){this.insertSource(parentNode,postText) +}},insertParameters:function(parentNode,params){if(!params||!params.length){return +}var paramTable=this.paramsTable.append({object:{}},parentNode); +var row=$$(".netInfoPostParamsTitle",paramTable)[0]; +var tbody=paramTable.getElementsByTagName("tbody")[0]; +NetInfoBody.headerDataTag.insertRows({headers:params},row) +},insertParts:function(parentNode,data){if(!data.params||!data.params.length){return +}var partsTable=this.partsTable.append({object:{}},parentNode); +var row=$$(".netInfoPostPartsTitle",paramTable)[0]; +NetInfoBody.headerDataTag.insertRows({headers:data.params},row) +},insertJSON:function(parentNode,file,context){var text=file.responseText; +var data=parseJSONString(text); +if(!data){return +}var jsonTable=this.jsonTable.append({},parentNode); +var jsonBody=$$(".netInfoPostJSONBody",jsonTable)[0]; +if(!this.toggles){this.toggles={} +}Firebug.DOMPanel.DirTable.tag.replace({object:data,toggles:this.toggles},jsonBody) +},insertXML:function(parentNode,file,context){var text=Utils.getPostText(file,context); +var jsonTable=this.xmlTable.append(null,parentNode); +var jsonBody=$$(".netInfoPostXMLBody",jsonTable)[0]; +Firebug.XMLViewerModel.insertXML(jsonBody,text) +},insertSource:function(parentNode,text){var sourceTable=this.sourceTable.append({object:{}},parentNode); +var row=$$(".netInfoPostSourceTitle",sourceTable)[0]; +var param={value:[text]}; +this.sourceBodyTag.insertRows({param:param},row) +},parseMultiPartText:function(file,context){var text=Utils.getPostText(file,context); +if(text==undefined){return null +}FBTrace.sysout("net.parseMultiPartText; boundary: ",text); +var boundary=text.match(/\s*boundary=\s*(.*)/)[1]; +var divider="\r\n\r\n"; +var bodyStart=text.indexOf(divider); +var body=text.substr(bodyStart+divider.length); +var postData={}; +postData.mimeType="multipart/form-data"; +postData.params=[]; +var parts=body.split("--"+boundary); +for(var i=0; +i1)?m[1]:"",value:trim(part[1])}) +}return postData +}}); +var NetInfoPostData=Firebug.NetMonitor.NetInfoPostData; +var $STRP=function(a){return a +}; +Firebug.NetMonitor.NetLimit=domplate(Firebug.Rep,{collapsed:true,tableTag:DIV(TABLE({width:"100%",cellpadding:0,cellspacing:0},TBODY())),limitTag:TR({"class":"netRow netLimitRow",$collapsed:"$isCollapsed"},TD({"class":"netCol netLimitCol",colspan:6},TABLE({cellpadding:0,cellspacing:0},TBODY(TR(TD(SPAN({"class":"netLimitLabel"},$STRP("plural.Limit_Exceeded",[0]))),TD({style:"width:100%"}),TD(BUTTON({"class":"netLimitButton",title:"$limitPrefsTitle",onclick:"$onPreferences"},$STR("LimitPrefs"))),TD(" ")))))),isCollapsed:function(){return this.collapsed +},onPreferences:function(event){openNewTab("about:config") +},updateCounter:function(row){removeClass(row,"collapsed"); +var limitLabel=row.getElementsByClassName("netLimitLabel").item(0); +limitLabel.firstChild.nodeValue=$STRP("plural.Limit_Exceeded",[row.limitInfo.totalCount]) +},createTable:function(parent,limitInfo){var table=this.tableTag.replace({},parent); +var row=this.createRow(table.firstChild.firstChild,limitInfo); +return[table,row] +},createRow:function(parent,limitInfo){var row=this.limitTag.insertRows(limitInfo,parent,this)[0]; +row.limitInfo=limitInfo; +return row +},observe:function(subject,topic,data){if(topic!="nsPref:changed"){return +}if(data.indexOf("net.logLimit")!=-1){this.updateMaxLimit() +}},updateMaxLimit:function(){var value=Firebug.getPref(Firebug.prefDomain,"net.logLimit"); +maxQueueRequests=value?value:maxQueueRequests +}}); +var NetLimit=Firebug.NetMonitor.NetLimit; +Firebug.NetMonitor.ResponseSizeLimit=domplate(Firebug.Rep,{tag:DIV({"class":"netInfoResponseSizeLimit"},SPAN("$object.beforeLink"),A({"class":"objectLink",onclick:"$onClickLink"},"$object.linkText"),SPAN("$object.afterLink")),reLink:/^(.*)(.*)<\/a>(.*$)/,append:function(obj,parent){var m=obj.text.match(this.reLink); +return this.tag.append({onClickLink:obj.onClickLink,object:{beforeLink:m[1],linkText:m[2],afterLink:m[3]}},parent,this) +}}); +Firebug.NetMonitor.Utils={findHeader:function(headers,name){if(!headers){return null +}name=name.toLowerCase(); +for(var i=0; +ilimit&&!noLimit){return cropString(file.postText,limit,"\n\n... "+$STR("net.postDataSizeLimitMessage")+" ...\n\n") +}return file.postText +},getResponseText:function(file,context){return(typeof(file.responseText)!="undefined")?file.responseText:context.sourceCache.loadText(file.href,file.method,file) +},isURLEncodedRequest:function(file,context){var text=Utils.getPostText(file,context); +if(text&&text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded")==0){return true +}var headerValue=Utils.findHeader(file.requestHeaders,"content-type"); +if(headerValue&&headerValue.indexOf("application/x-www-form-urlencoded")==0){return true +}return false +},isMultiPartRequest:function(file,context){var text=Utils.getPostText(file,context); +if(text&&text.toLowerCase().indexOf("content-type: multipart/form-data")==0){return true +}return false +},getMimeType:function(mimeType,uri){if(!mimeType||!(mimeCategoryMap.hasOwnProperty(mimeType))){var ext=getFileExtension(uri); +if(!ext){return mimeType +}else{var extMimeType=mimeExtensionMap[ext.toLowerCase()]; +return extMimeType?extMimeType:mimeType +}}else{return mimeType +}},getDateFromSeconds:function(s){var d=new Date(); +d.setTime(s*1000); +return d +},getHttpHeaders:function(request,file){try{var http=QI(request,Ci.nsIHttpChannel); +file.status=request.responseStatus; +file.method=http.requestMethod; +file.urlParams=parseURLParams(file.href); +file.mimeType=Utils.getMimeType(request.contentType,request.name); +if(!file.responseHeaders&&Firebug.collectHttpHeaders){var requestHeaders=[],responseHeaders=[]; +http.visitRequestHeaders({visitHeader:function(name,value){requestHeaders.push({name:name,value:value}) +}}); +http.visitResponseHeaders({visitHeader:function(name,value){responseHeaders.push({name:name,value:value}) +}}); +file.requestHeaders=requestHeaders; +file.responseHeaders=responseHeaders +}}catch(exc){if(FBTrace.DBG_ERRORS){FBTrace.sysout("net.getHttpHeaders FAILS "+file.href,exc) +}}},isXHR:function(request){try{var callbacks=request.notificationCallbacks; +var xhrRequest=callbacks?callbacks.getInterface(Ci.nsIXMLHttpRequest):null; +if(FBTrace.DBG_NET){FBTrace.sysout("net.isXHR; "+(xhrRequest!=null)+", "+safeGetName(request)) +}return(xhrRequest!=null) +}catch(exc){}return false +},getFileCategory:function(file){if(file.category){if(FBTrace.DBG_NET){FBTrace.sysout("net.getFileCategory; current: "+file.category+" for: "+file.href,file) +}return file.category +}if(file.isXHR){if(FBTrace.DBG_NET){FBTrace.sysout("net.getFileCategory; XHR for: "+file.href,file) +}return file.category="xhr" +}if(!file.mimeType){var ext=getFileExtension(file.href); +if(ext){file.mimeType=mimeExtensionMap[ext.toLowerCase()] +}}if(!file.mimeType){return"" +}var mimeType=file.mimeType; +if(mimeType){mimeType=mimeType.split(";")[0] +}return(file.category=mimeCategoryMap[mimeType]) +}}; +var Utils=Firebug.NetMonitor.Utils; +Firebug.registerModule(Firebug.NetMonitor) +}}); +FBL.ns(function(){with(FBL){var contexts=[]; +Firebug.Spy=extend(Firebug.Module,{dispatchName:"spy",initialize:function(){if(Firebug.TraceModule){Firebug.TraceModule.addListener(this.TraceListener) +}Firebug.Module.initialize.apply(this,arguments) +},shutdown:function(){Firebug.Module.shutdown.apply(this,arguments); +if(Firebug.TraceModule){Firebug.TraceModule.removeListener(this.TraceListener) +}},initContext:function(context){context.spies=[]; +if(Firebug.showXMLHttpRequests&&Firebug.Console.isAlwaysEnabled()){this.attachObserver(context,context.window) +}if(FBTrace.DBG_SPY){FBTrace.sysout("spy.initContext "+contexts.length+" ",context.getName()) +}},destroyContext:function(context){this.detachObserver(context,null); +if(FBTrace.DBG_SPY&&context.spies.length){FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies ("+context.spies.length+") "+context.getName()) +}delete context.spies; +if(FBTrace.DBG_SPY){FBTrace.sysout("spy.destroyContext "+contexts.length+" ",context.getName()) +}},watchWindow:function(context,win){if(Firebug.showXMLHttpRequests&&Firebug.Console.isAlwaysEnabled()){this.attachObserver(context,win) +}},unwatchWindow:function(context,win){try{this.detachObserver(context,win) +}catch(ex){ERROR(ex) +}},updateOption:function(name,value){if(name=="showXMLHttpRequests"){var tach=value?this.attachObserver:this.detachObserver; +for(var i=0; +i\s*/,""); +var div=parentNode.ownerDocument.createElement("div"); +div.innerHTML=xmlText; +var root=div.getElementsByTagName("*")[0]; +if(FBTrace.DBG_XMLVIEWER){FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed",doc) +}var html=[]; +Firebug.Reps.appendNode(root,html); +parentNode.innerHTML=html.join("") +}}); +Firebug.XMLViewerModel.ParseError=domplate(Firebug.Rep,{tag:DIV({"class":"xmlInfoError"},DIV({"class":"xmlInfoErrorMsg"},"$error.message"),PRE({"class":"xmlInfoErrorSource"},"$error|getSource")),getSource:function(error){var parts=error.source.split("\n"); +if(parts.length!=2){return error.source +}var limit=50; +var column=parts[1].length; +if(column>=limit){parts[0]="..."+parts[0].substr(column-limit); +parts[1]="..."+parts[1].substr(column-limit) +}if(parts[0].length>80){parts[0]=parts[0].substr(0,80)+"..." +}return parts.join("\n") +}}); +Firebug.registerModule(Firebug.XMLViewerModel) +}}); +FBL.ns(function(){with(FBL){var ElementCache=Firebug.Lite.Cache.Element; +var cacheID=Firebug.Lite.Cache.ID; +var ignoreHTMLProps={sizcache:1,sizset:1}; +ignoreHTMLProps[cacheID]=1; +Firebug.HTML=extend(Firebug.Module,{appendTreeNode:function(nodeArray,html){var reTrim=/^\s+|\s+$/g; +if(!nodeArray.length){nodeArray=[nodeArray] +}for(var n=0,node; +node=nodeArray[n]; +n++){if(node.nodeType==1){if(Firebug.ignoreFirebugElements&&node.firebugIgnore){continue +}var uid=ElementCache(node); +var child=node.childNodes; +var childLength=child.length; +var nodeName=node.nodeName.toLowerCase(); +var nodeVisible=isVisible(node); +var hasSingleTextChild=childLength==1&&node.firstChild.nodeType==3&&nodeName!="script"&&nodeName!="style"; +var nodeControl=!hasSingleTextChild&&childLength>0?('
      '):""; +var isIE=false; +if(isIE&&nodeControl){html.push(nodeControl) +}if(typeof uid!="undefined"){html.push('
      ',!isIE&&nodeControl?nodeControl:"","<',nodeName,"") +}else{html.push('
      <',nodeName,"") +}for(var i=0; +i',name,'="',escapeHTML(value),""") +}if(hasSingleTextChild){var value=child[0].nodeValue.replace(reTrim,""); +if(value){html.push('>',escapeHTML(value),'</',nodeName,">
      ") +}else{html.push("/>
      ") +}}else{if(childLength>0){html.push(">") +}else{html.push("/>") +}}}else{if(node.nodeType==3){if(node.parentNode&&(node.parentNode.nodeName.toLowerCase()=="script"||node.parentNode.nodeName.toLowerCase()=="style")){var value=node.nodeValue.replace(reTrim,""); +if(isIE){var src=value+"\n" +}else{var src="\n"+value+"\n" +}var match=src.match(/\n/g); +var num=match?match.length:0; +var s=[],sl=0; +for(var c=1; +c'+c+"" +}html.push('
      ',s.join(""),'
      ',escapeHTML(src),"
      ") +}else{var value=node.nodeValue.replace(reTrim,""); +if(value){html.push('
      ',escapeHTML(value),"
      ") +}}}}}},appendTreeChildren:function(treeNode){var doc=Firebug.chrome.document; +var uid=treeNode.id; +var parentNode=ElementCache.get(uid); +if(parentNode.childNodes.length==0){return +}var treeNext=treeNode.nextSibling; +var treeParent=treeNode.parentNode; +var isIE=false; +var control=isIE?treeNode.previousSibling:treeNode.firstChild; +control.className="nodeControl nodeMaximized"; +var html=[]; +var children=doc.createElement("div"); +children.className="nodeChildren"; +this.appendTreeNode(parentNode.childNodes,html); +children.innerHTML=html.join(""); +treeParent.insertBefore(children,treeNext); +var closeElement=doc.createElement("div"); +closeElement.className="objectBox-element"; +closeElement.innerHTML='</'+parentNode.nodeName.toLowerCase()+">"; +treeParent.insertBefore(closeElement,treeNext) +},removeTreeChildren:function(treeNode){var children=treeNode.nextSibling; +var closeTag=children.nextSibling; +var isIE=false; +var control=isIE?treeNode.previousSibling:treeNode.firstChild; +control.className="nodeControl"; +children.parentNode.removeChild(children); +closeTag.parentNode.removeChild(closeTag) +},isTreeNodeVisible:function(id){return $(id) +},select:function(el){var id=el&&ElementCache(el); +if(id){this.selectTreeNode(id) +}},selectTreeNode:function(id){id=""+id; +var node,stack=[]; +while(id&&!this.isTreeNodeVisible(id)){stack.push(id); +var node=ElementCache.get(id).parentNode; +if(node){id=ElementCache(node) +}else{break +}}stack.push(id); +while(stack.length>0){id=stack.pop(); +node=$(id); +if(stack.length>0&&ElementCache.get(id).childNodes.length>0){this.appendTreeChildren(node) +}}selectElement(node); +if(fbPanel1){fbPanel1.scrollTop=Math.round(node.offsetTop-fbPanel1.clientHeight/2) +}}}); +Firebug.registerModule(Firebug.HTML); +function HTMLPanel(){}HTMLPanel.prototype=extend(Firebug.Panel,{name:"HTML",title:"HTML",options:{hasSidePanel:true,isPreRendered:true,innerHTMLSync:true},create:function(){Firebug.Panel.create.apply(this,arguments); +this.panelNode.style.padding="4px 3px 1px 15px"; +this.panelNode.style.minWidth="500px"; +if(Env.Options.enablePersistent||Firebug.chrome.type!="popup"){this.createUI() +}if(!this.sidePanelBar.selectedPanel){this.sidePanelBar.selectPanel("css") +}},destroy:function(){selectedElement=null; +fbPanel1=null; +selectedSidePanelTS=null; +selectedSidePanelTimer=null; +Firebug.Panel.destroy.apply(this,arguments) +},createUI:function(){var rootNode=Firebug.browser.document.documentElement; +var html=[]; +Firebug.HTML.appendTreeNode(rootNode,html); +this.panelNode.innerHTML=html.join("") +},initialize:function(){Firebug.Panel.initialize.apply(this,arguments); +addEvent(this.panelNode,"click",Firebug.HTML.onTreeClick); +fbPanel1=$("fbPanel1"); +if(!selectedElement){Firebug.HTML.selectTreeNode(ElementCache(Firebug.browser.document.body)) +}addEvent(fbPanel1,"mousemove",Firebug.HTML.onListMouseMove); +addEvent($("fbContent"),"mouseout",Firebug.HTML.onListMouseMove); +addEvent(Firebug.chrome.node,"mouseout",Firebug.HTML.onListMouseMove) +},shutdown:function(){removeEvent(fbPanel1,"mousemove",Firebug.HTML.onListMouseMove); +removeEvent($("fbContent"),"mouseout",Firebug.HTML.onListMouseMove); +removeEvent(Firebug.chrome.node,"mouseout",Firebug.HTML.onListMouseMove); +removeEvent(this.panelNode,"click",Firebug.HTML.onTreeClick); +fbPanel1=null; +Firebug.Panel.shutdown.apply(this,arguments) +},reattach:function(){if(FirebugChrome.selectedHTMLElementId){Firebug.HTML.selectTreeNode(FirebugChrome.selectedHTMLElementId) +}},updateSelection:function(object){var id=ElementCache(object); +if(id){Firebug.HTML.selectTreeNode(id) +}}}); +Firebug.registerPanel(HTMLPanel); +var formatStyles=function(styles){return isIE?styles.replace(/([^\s]+)\s*:/g,function(m,g){return g.toLowerCase()+":" +}):styles +}; +var selectedElement=null; +var fbPanel1=null; +var selectedSidePanelTS,selectedSidePanelTimer; +var selectElement=function selectElement(e){if(e!=selectedElement){if(selectedElement){selectedElement.className="objectBox-element" +}e.className=e.className+" selectedElement"; +if(FBL.isFirefox){e.style.MozBorderRadius="2px" +}else{if(FBL.isSafari){e.style.WebkitBorderRadius="2px" +}}selectedElement=e; +FirebugChrome.selectedHTMLElementId=e.id; +var target=ElementCache.get(e.id); +var selectedSidePanel=Firebug.chrome.getPanel("HTML").sidePanelBar.selectedPanel; +var stack=FirebugChrome.htmlSelectionStack; +stack.unshift(target); +if(stack.length>2){stack.pop() +}var lazySelect=function(){selectedSidePanelTS=new Date().getTime(); +selectedSidePanel.select(target,true) +}; +if(selectedSidePanelTimer){clearTimeout(selectedSidePanelTimer); +selectedSidePanelTimer=null +}if(new Date().getTime()-selectedSidePanelTS>100){setTimeout(lazySelect,0) +}else{selectedSidePanelTimer=setTimeout(lazySelect,150) +}}}; +Firebug.HTML.onTreeClick=function(e){e=e||event; +var targ; +if(e.target){targ=e.target +}else{if(e.srcElement){targ=e.srcElement +}}if(targ.nodeType==3){targ=targ.parentNode +}if(targ.className.indexOf("nodeControl")!=-1||targ.className=="nodeTag"){var isIE=false; +if(targ.className=="nodeTag"){var control=isIE?(targ.parentNode.previousSibling||targ):(targ.parentNode.previousSibling||targ); +selectElement(targ.parentNode.parentNode); +if(control.className.indexOf("nodeControl")==-1){return +}}else{control=targ +}FBL.cancelEvent(e); +var treeNode=isIE?control.nextSibling:control.parentNode; +if(control.className.indexOf(" nodeMaximized")!=-1){FBL.Firebug.HTML.removeTreeChildren(treeNode) +}else{FBL.Firebug.HTML.appendTreeChildren(treeNode) +}}else{if(targ.className=="nodeValue"||targ.className=="nodeName"){}}}; +function onListMouseOut(e){e=e||event||window; +var targ; +if(e.target){targ=e.target +}else{if(e.srcElement){targ=e.srcElement +}}if(targ.nodeType==3){targ=targ.parentNode +}if(hasClass(targ,"fbPanel")){FBL.Firebug.Inspector.hideBoxModel(); +hoverElement=null +}}var hoverElement=null; +var hoverElementTS=0; +Firebug.HTML.onListMouseMove=function onListMouseMove(e){try{e=e||event||window; +var targ; +if(e.target){targ=e.target +}else{if(e.srcElement){targ=e.srcElement +}}if(targ.nodeType==3){targ=targ.parentNode +}var found=false; +while(targ&&!found){if(!/\snodeBox\s|\sobjectBox-selector\s/.test(" "+targ.className+" ")){targ=targ.parentNode +}else{found=true +}}if(!targ){FBL.Firebug.Inspector.hideBoxModel(); +hoverElement=null; +return +}if(typeof targ.attributes[cacheID]=="undefined"){return +}var uid=targ.attributes[cacheID]; +if(!uid){return +}var el=ElementCache.get(uid.value); +var nodeName=el.nodeName.toLowerCase(); +if(FBL.isIE&&" meta title script link ".indexOf(" "+nodeName+" ")!=-1){return +}if(!/\snodeBox\s|\sobjectBox-selector\s/.test(" "+targ.className+" ")){return +}if(el.id=="FirebugUI"||" html head body br script link iframe ".indexOf(" "+nodeName+" ")!=-1){FBL.Firebug.Inspector.hideBoxModel(); +hoverElement=null; +return +}if((new Date().getTime()-hoverElementTS>40)&&hoverElement!=el){hoverElementTS=new Date().getTime(); +hoverElement=el; +FBL.Firebug.Inspector.drawBoxModel(el) +}}catch(E){}}; +Firebug.Reps={appendText:function(object,html){html.push(escapeHTML(objectToString(object))) +},appendNull:function(object,html){html.push('',escapeHTML(objectToString(object)),"") +},appendString:function(object,html){html.push('"',escapeHTML(objectToString(object)),""") +},appendInteger:function(object,html){html.push('',escapeHTML(objectToString(object)),"") +},appendFloat:function(object,html){html.push('',escapeHTML(objectToString(object)),"") +},appendFunction:function(object,html){var reName=/function ?(.*?)\(/; +var m=reName.exec(objectToString(object)); +var name=m&&m[1]?m[1]:"function"; +html.push('',escapeHTML(name),"()") +},appendObject:function(object,html){try{if(object==undefined){this.appendNull("undefined",html) +}else{if(object==null){this.appendNull("null",html) +}else{if(typeof object=="string"){this.appendString(object,html) +}else{if(typeof object=="number"){this.appendInteger(object,html) +}else{if(typeof object=="boolean"){this.appendInteger(object,html) +}else{if(typeof object=="function"){this.appendFunction(object,html) +}else{if(object.nodeType==1){this.appendSelector(object,html) +}else{if(typeof object=="object"){if(typeof object.length!="undefined"){this.appendArray(object,html) +}else{this.appendObjectFormatted(object,html) +}}else{this.appendText(object,html) +}}}}}}}}}catch(exc){}},appendObjectFormatted:function(object,html){var text=objectToString(object); +var reObject=/\[object (.*?)\]/; +var m=reObject.exec(text); +html.push('',m?m[1]:text,"") +},appendSelector:function(object,html){var uid=ElementCache(object); +var uidString=uid?[cacheID,'="',uid,'"'].join(""):""; +html.push('"); +html.push('',escapeHTML(object.nodeName.toLowerCase()),""); +if(object.id){html.push('#',escapeHTML(object.id),"") +}if(object.className){html.push('.',escapeHTML(object.className),"") +}html.push("") +},appendNode:function(node,html){if(node.nodeType==1){var uid=ElementCache(node); +var uidString=uid?[cacheID,'="',uid,'"'].join(""):""; +html.push('
      ',"','<',node.nodeName.toLowerCase(),""); +for(var i=0; +i',name,'="',escapeHTML(value),""") +}if(node.firstChild){html.push('>
      '); +for(var child=node.firstChild; +child; +child=child.nextSibling){this.appendNode(child,html) +}html.push('
      </',node.nodeName.toLowerCase(),">
      ") +}else{html.push("/>") +}}else{if(node.nodeType==3){var value=trim(node.nodeValue); +if(value){html.push('
      ',escapeHTML(value),"
      ") +}}}},appendArray:function(object,html){html.push('[ '); +for(var i=0,l=object.length,obj; +i]") +}} +}}); +FBL.ns(function(){with(FBL){var maxWidth=100,maxHeight=80; +var infoTipMargin=10; +var infoTipWindowPadding=25; +Firebug.InfoTip=extend(Firebug.Module,{dispatchName:"infoTip",tags:domplate({infoTipTag:DIV({"class":"infoTip"}),colorTag:DIV({style:"background: $rgbValue; width: 100px; height: 40px"}," "),imgTag:DIV({"class":"infoTipImageBox infoTipLoading"},IMG({"class":"infoTipImage",src:"$urlValue",repeat:"$repeat",onload:"$onLoadImage"}),IMG({"class":"infoTipBgImage",collapsed:true,src:"blank.gif"}),DIV({"class":"infoTipCaption"})),onLoadImage:function(event){var img=event.currentTarget||event.srcElement; +var innerBox=img.parentNode; +var caption=getElementByClass(innerBox,"infoTipCaption"); +var bgImg=getElementByClass(innerBox,"infoTipBgImage"); +if(!bgImg){return +}if(isIE){removeClass(innerBox,"infoTipLoading") +}var updateInfoTip=function(){var w=img.naturalWidth||img.width||10,h=img.naturalHeight||img.height||10; +var repeat=img.getAttribute("repeat"); +if(repeat=="repeat-x"||(w==1&&h>1)){collapse(img,true); +collapse(bgImg,false); +bgImg.style.background="url("+img.src+") repeat-x"; +bgImg.style.width=maxWidth+"px"; +if(h>maxHeight){bgImg.style.height=maxHeight+"px" +}else{bgImg.style.height=h+"px" +}}else{if(repeat=="repeat-y"||(h==1&&w>1)){collapse(img,true); +collapse(bgImg,false); +bgImg.style.background="url("+img.src+") repeat-y"; +bgImg.style.height=maxHeight+"px"; +if(w>maxWidth){bgImg.style.width=maxWidth+"px" +}else{bgImg.style.width=w+"px" +}}else{if(repeat=="repeat"||(w==1&&h==1)){collapse(img,true); +collapse(bgImg,false); +bgImg.style.background="url("+img.src+") repeat"; +bgImg.style.width=maxWidth+"px"; +bgImg.style.height=maxHeight+"px" +}else{if(w>maxWidth||h>maxHeight){if(w>h){img.style.width=maxWidth+"px"; +img.style.height=Math.round((h/w)*maxWidth)+"px" +}else{img.style.width=Math.round((w/h)*maxHeight)+"px"; +img.style.height=maxHeight+"px" +}}}}}caption.innerHTML=$STRF(w+" x "+h) +}; +if(isIE){setTimeout(updateInfoTip,0) +}else{updateInfoTip(); +removeClass(innerBox,"infoTipLoading") +}}}),initializeBrowser:function(browser){browser.onInfoTipMouseOut=bind(this.onMouseOut,this,browser); +browser.onInfoTipMouseMove=bind(this.onMouseMove,this,browser); +var doc=browser.document; +if(!doc){return +}addEvent(doc,"mouseover",browser.onInfoTipMouseMove); +addEvent(doc,"mouseout",browser.onInfoTipMouseOut); +addEvent(doc,"mousemove",browser.onInfoTipMouseMove); +return browser.infoTip=this.tags.infoTipTag.append({},getBody(doc)) +},uninitializeBrowser:function(browser){if(browser.infoTip){var doc=browser.document; +removeEvent(doc,"mouseover",browser.onInfoTipMouseMove); +removeEvent(doc,"mouseout",browser.onInfoTipMouseOut); +removeEvent(doc,"mousemove",browser.onInfoTipMouseMove); +browser.infoTip.parentNode.removeChild(browser.infoTip); +delete browser.infoTip; +delete browser.onInfoTipMouseMove +}},showInfoTip:function(infoTip,panel,target,x,y,rangeParent,rangeOffset){if(!Firebug.showInfoTips){return +}var scrollParent=getOverflowParent(target); +var scrollX=x+(scrollParent?scrollParent.scrollLeft:0); +if(panel.showInfoTip(infoTip,target,scrollX,y,rangeParent,rangeOffset)){var htmlElt=infoTip.ownerDocument.documentElement; +var panelWidth=htmlElt.clientWidth; +var panelHeight=htmlElt.clientHeight; +if(x+infoTip.offsetWidth+infoTipMargin>panelWidth){infoTip.style.left=Math.max(0,panelWidth-(infoTip.offsetWidth+infoTipMargin))+"px"; +infoTip.style.right="auto" +}else{infoTip.style.left=(x+infoTipMargin)+"px"; +infoTip.style.right="auto" +}if(y+infoTip.offsetHeight+infoTipMargin>panelHeight){infoTip.style.top=Math.max(0,panelHeight-(infoTip.offsetHeight+infoTipMargin))+"px"; +infoTip.style.bottom="auto" +}else{infoTip.style.top=(y+infoTipMargin)+"px"; +infoTip.style.bottom="auto" +}if(FBTrace.DBG_INFOTIP){FBTrace.sysout("infotip.showInfoTip; top: "+infoTip.style.top+", left: "+infoTip.style.left+", bottom: "+infoTip.style.bottom+", right:"+infoTip.style.right+", offsetHeight: "+infoTip.offsetHeight+", offsetWidth: "+infoTip.offsetWidth+", x: "+x+", panelWidth: "+panelWidth+", y: "+y+", panelHeight: "+panelHeight) +}infoTip.setAttribute("active","true") +}else{this.hideInfoTip(infoTip) +}},hideInfoTip:function(infoTip){if(infoTip){infoTip.removeAttribute("active") +}},onMouseOut:function(event,browser){if(!event.relatedTarget){this.hideInfoTip(browser.infoTip) +}},onMouseMove:function(event,browser){if(getAncestorByClass(event.target,"infoTip")){return +}if(browser.currentPanel){var x=event.clientX,y=event.clientY,target=event.target||event.srcElement; +this.showInfoTip(browser.infoTip,browser.currentPanel,target,x,y,event.rangeParent,event.rangeOffset) +}else{this.hideInfoTip(browser.infoTip) +}},populateColorInfoTip:function(infoTip,color){this.tags.colorTag.replace({rgbValue:color},infoTip); +return true +},populateImageInfoTip:function(infoTip,url,repeat){if(!repeat){repeat="no-repeat" +}this.tags.imgTag.replace({urlValue:url,repeat:repeat},infoTip); +return true +},disable:function(){},showPanel:function(browser,panel){if(panel){var infoTip=panel.panelBrowser.infoTip; +if(!infoTip){infoTip=this.initializeBrowser(panel.panelBrowser) +}this.hideInfoTip(infoTip) +}},showSidePanel:function(browser,panel){this.showPanel(browser,panel) +}}); +Firebug.registerModule(Firebug.InfoTip) +}}); +(function(){this.getElementXPath=function(element){if(element&&element.id){return'//*[@id="'+element.id+'"]' +}else{return this.getElementTreeXPath(element) +}}; +this.getElementTreeXPath=function(element){var paths=[]; +for(; +element&&element.nodeType==1; +element=element.parentNode){var index=0; +for(var sibling=element.previousSibling; +sibling; +sibling=sibling.previousSibling){if(sibling.nodeName==element.nodeName){++index +}}var tagName=element.nodeName.toLowerCase(); +var pathIndex=(index?"["+(index+1)+"]":""); +paths.splice(0,0,tagName+pathIndex) +}return paths.length?"/"+paths.join("/"):null +}; +this.getElementsByXPath=function(doc,xpath){var nodes=[]; +try{var result=doc.evaluate(xpath,doc,null,XPathResult.ANY_TYPE,null); +for(var item=result.iterateNext(); +item; +item=result.iterateNext()){nodes.push(item) +}}catch(exc){}return nodes +}; +this.getRuleMatchingElements=function(rule,doc){var css=rule.selectorText; +var xpath=this.cssToXPath(css); +return this.getElementsByXPath(doc,xpath) +} +}).call(FBL); +FBL.ns(function(){with(FBL){var toCamelCase=function toCamelCase(s){return s.replace(reSelectorCase,toCamelCaseReplaceFn) +}; +var toSelectorCase=function toSelectorCase(s){return s.replace(reCamelCase,"-$1").toLowerCase() +}; +var reCamelCase=/([A-Z])/g; +var reSelectorCase=/\-(.)/g; +var toCamelCaseReplaceFn=function toCamelCaseReplaceFn(m,g){return g.toUpperCase() +}; +var ElementCache=Firebug.Lite.Cache.Element; +var StyleSheetCache=Firebug.Lite.Cache.StyleSheet; +var globalCSSRuleIndex; +var externalStyleSheetURLs=[]; +var externalStyleSheetWarning=domplate(Firebug.Rep,{tag:DIV({"class":"warning focusRow",style:"font-weight:normal;",role:"listitem"},SPAN("$object|STR"),A({href:"$href",target:"_blank"},"$link|STR"))}); +var processAllStyleSheetsTimeout=null; +var loadExternalStylesheet=function(doc,styleSheetIterator,styleSheet){var url=styleSheet.href; +styleSheet.firebugIgnore=true; +var source=Firebug.Lite.Proxy.load(url); +source=source.replace(/url\(([^\)]+)\)/g,function(a,name){var hasDomain=/\w+:\/\/./.test(name); +if(!hasDomain){name=name.replace(/^(["'])(.+)\1$/,"$2"); +var first=name.charAt(0); +if(first=="/"){var m=/^([^:]+:\/{1,3}[^\/]+)/.exec(url); +return m?"url("+m[1]+name+")":"url("+name+")" +}else{var path=url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g,""); +path=path+name; +var reBack=/[^\/]+\/\.\.\//; +while(reBack.test(path)){path=path.replace(reBack,"") +}return"url("+path+")" +}}return a +}); +var oldStyle=styleSheet.ownerNode; +if(!oldStyle){return +}if(!oldStyle.parentNode){return +}var style=createGlobalElement("style"); +style.setAttribute("charset","utf-8"); +style.setAttribute("type","text/css"); +style.innerHTML=source; +oldStyle.parentNode.insertBefore(style,oldStyle.nextSibling); +oldStyle.parentNode.removeChild(oldStyle); +doc.styleSheets[doc.styleSheets.length-1].externalURL=url; +console.log(url,"call "+externalStyleSheetURLs.length,source); +externalStyleSheetURLs.pop(); +if(processAllStyleSheetsTimeout){clearTimeout(processAllStyleSheetsTimeout) +}processAllStyleSheetsTimeout=setTimeout(function(){console.log("processing"); +FBL.processAllStyleSheets(doc,styleSheetIterator); +processAllStyleSheetsTimeout=null +},200) +}; +FBL.processAllStyleSheets=function(doc,styleSheetIterator){styleSheetIterator=styleSheetIterator||processStyleSheet; +globalCSSRuleIndex=-1; +var styleSheets=doc.styleSheets; +var importedStyleSheets=[]; +if(FBTrace.DBG_CSS){var start=new Date().getTime() +}for(var i=0,length=styleSheets.length; +imaxSpecificity){maxSpecificity=spec; +mostSpecificSelector=sel +}}}rule.specificity=maxSpecificity +}}rules.sort(sortElementRules); +return rules +}; +var sortElementRules=function(a,b){var ruleA=CSSRuleMap[a]; +var ruleB=CSSRuleMap[b]; +var specificityA=ruleA.specificity; +var specificityB=ruleB.specificity; +if(specificityA>specificityB){return 1 +}else{if(specificityAruleB.order?1:-1 +}}}; +var solveRulesTied=function(a,b){var ruleA=CSSRuleMap[a]; +var ruleB=CSSRuleMap[b]; +if(ruleA.specificity==ruleB.specificity){return ruleA.order>ruleB.order?1:-1 +}return null +}; +var reSelectorTag=/(^|\s)(?:\w+)/g; +var reSelectorClass=/\.[\w\d_-]+/g; +var reSelectorId=/#[\w\d_-]+/g; +var getCSSRuleSpecificity=function(selector){var match=selector.match(reSelectorTag); +var tagCount=match?match.length:0; +match=selector.match(reSelectorClass); +var classCount=match?match.length:0; +match=selector.match(reSelectorId); +var idCount=match?match.length:0; +return tagCount+10*classCount+100*idCount +}; +Firebug.SourceBoxPanel=Firebug.Panel; +var domUtils=null; +var textContent=isIE?"innerText":"textContent"; +var CSSDomplateBase={isEditable:function(rule){return !rule.isSystemSheet +},isSelectorEditable:function(rule){return rule.isSelectorEditable&&this.isEditable(rule) +}}; +var CSSPropTag=domplate(CSSDomplateBase,{tag:DIV({"class":"cssProp focusRow",$disabledStyle:"$prop.disabled",$editGroup:"$rule|isEditable",$cssOverridden:"$prop.overridden",role:"option"},A({"class":"cssPropDisable"},"  "),SPAN({"class":"cssPropName",$editable:"$rule|isEditable"},"$prop.name"),SPAN({"class":"cssColon"},":"),SPAN({"class":"cssPropValue",$editable:"$rule|isEditable"},"$prop.value$prop.important"),SPAN({"class":"cssSemi"},";"))}); +var CSSRuleTag=TAG("$rule.tag",{rule:"$rule"}); +var CSSImportRuleTag=domplate({tag:DIV({"class":"cssRule insertInto focusRow importRule",_repObject:"$rule.rule"},"@import "",A({"class":"objectLink",_repObject:"$rule.rule.styleSheet"},"$rule.rule.href"),"";")}); +var CSSStyleRuleTag=domplate(CSSDomplateBase,{tag:DIV({"class":"cssRule insertInto",$cssEditableRule:"$rule|isEditable",$editGroup:"$rule|isSelectorEditable",_repObject:"$rule.rule",ruleId:"$rule.id",role:"presentation"},DIV({"class":"cssHead focusRow",role:"listitem"},SPAN({"class":"cssSelector",$editable:"$rule|isSelectorEditable"},"$rule.selector")," {"),DIV({role:"group"},DIV({"class":"cssPropertyListBox",role:"listbox"},FOR("prop","$rule.props",TAG(CSSPropTag.tag,{rule:"$rule",prop:"$prop"})))),DIV({"class":"editable insertBefore",role:"presentation"},"}"))}); +var reSplitCSS=/(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/; +var reURL=/url\("?([^"\)]+)?"?\)/; +var reRepeat=/no-repeat|repeat-x|repeat-y|repeat/; +var sothinkInstalled=false; +var styleGroups={text:["font-family","font-size","font-weight","font-style","color","text-transform","text-decoration","letter-spacing","word-spacing","line-height","text-align","vertical-align","direction","column-count","column-gap","column-width"],background:["background-color","background-image","background-repeat","background-position","background-attachment","opacity"],box:["width","height","top","right","bottom","left","margin-top","margin-right","margin-bottom","margin-left","padding-top","padding-right","padding-bottom","padding-left","border-top-width","border-right-width","border-bottom-width","border-left-width","border-top-color","border-right-color","border-bottom-color","border-left-color","border-top-style","border-right-style","border-bottom-style","border-left-style","-moz-border-top-radius","-moz-border-right-radius","-moz-border-bottom-radius","-moz-border-left-radius","outline-top-width","outline-right-width","outline-bottom-width","outline-left-width","outline-top-color","outline-right-color","outline-bottom-color","outline-left-color","outline-top-style","outline-right-style","outline-bottom-style","outline-left-style"],layout:["position","display","visibility","z-index","overflow-x","overflow-y","overflow-clip","white-space","clip","float","clear","-moz-box-sizing"],other:["cursor","list-style-image","list-style-position","list-style-type","marker-offset","user-focus","user-select","user-modify","user-input"]}; +var styleGroupTitles={text:"Text",background:"Background",box:"Box Model",layout:"Layout",other:"Other"}; +Firebug.CSSModule=extend(Firebug.Module,{freeEdit:function(styleSheet,value){if(!styleSheet.editStyleSheet){var ownerNode=getStyleSheetOwnerNode(styleSheet); +styleSheet.disabled=true; +var url=CCSV("@mozilla.org/network/standard-url;1",Components.interfaces.nsIURL); +url.spec=styleSheet.href; +var editStyleSheet=ownerNode.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml","style"); +unwrapObject(editStyleSheet).firebugIgnore=true; +editStyleSheet.setAttribute("type","text/css"); +editStyleSheet.setAttributeNS("http://www.w3.org/XML/1998/namespace","base",url.directory); +if(ownerNode.hasAttribute("media")){editStyleSheet.setAttribute("media",ownerNode.getAttribute("media")) +}ownerNode.parentNode.insertBefore(editStyleSheet,ownerNode.nextSibling); +styleSheet.editStyleSheet=editStyleSheet +}styleSheet.editStyleSheet.innerHTML=value; +if(FBTrace.DBG_CSS){FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n") +}dispatch(this.fbListeners,"onCSSFreeEdit",[styleSheet,value]) +},insertRule:function(styleSheet,cssText,ruleIndex){if(FBTrace.DBG_CSS){FBTrace.sysout("Insert: "+ruleIndex+" "+cssText) +}var insertIndex=styleSheet.insertRule(cssText,ruleIndex); +dispatch(this.fbListeners,"onCSSInsertRule",[styleSheet,cssText,ruleIndex]); +return insertIndex +},deleteRule:function(styleSheet,ruleIndex){if(FBTrace.DBG_CSS){FBTrace.sysout("deleteRule: "+ruleIndex+" "+styleSheet.cssRules.length,styleSheet.cssRules) +}dispatch(this.fbListeners,"onCSSDeleteRule",[styleSheet,ruleIndex]); +styleSheet.deleteRule(ruleIndex) +},setProperty:function(rule,propName,propValue,propPriority){var style=rule.style||rule; +var baseText=style.cssText; +if(style.getPropertyValue){var prevValue=style.getPropertyValue(propName); +var prevPriority=style.getPropertyPriority(propName); +style.removeProperty(propName); +style.setProperty(propName,propValue,propPriority) +}else{style[toCamelCase(propName)]=propValue +}if(propName){dispatch(this.fbListeners,"onCSSSetProperty",[style,propName,propValue,propPriority,prevValue,prevPriority,rule,baseText]) +}},removeProperty:function(rule,propName,parent){var style=rule.style||rule; +var baseText=style.cssText; +if(style.getPropertyValue){var prevValue=style.getPropertyValue(propName); +var prevPriority=style.getPropertyPriority(propName); +style.removeProperty(propName) +}else{style[toCamelCase(propName)]="" +}if(propName){dispatch(this.fbListeners,"onCSSRemoveProperty",[style,propName,prevValue,prevPriority,rule,baseText]) +}}}); +Firebug.CSSStyleSheetPanel=function(){}; +Firebug.CSSStyleSheetPanel.prototype=extend(Firebug.SourceBoxPanel,{template:domplate({tag:DIV({"class":"cssSheet insertInto a11yCSSView"},FOR("rule","$rules",CSSRuleTag),DIV({"class":"cssSheet editable insertBefore"},""))}),refresh:function(){if(this.location){this.updateLocation(this.location) +}else{if(this.selection){this.updateSelection(this.selection) +}}},toggleEditing:function(){if(!this.stylesheetEditor){this.stylesheetEditor=new StyleSheetEditor(this.document) +}if(this.editing){Firebug.Editor.stopEditing() +}else{if(!this.location){return +}var styleSheet=this.location.editStyleSheet?this.location.editStyleSheet.sheet:this.location; +var css=getStyleSheetCSS(styleSheet,this.context); +this.stylesheetEditor.styleSheet=this.location; +Firebug.Editor.startEditing(this.panelNode,css,this.stylesheetEditor) +}},getStylesheetURL:function(rule){if(this.location.href){return this.location.href +}else{return this.context.window.location.href +}},getRuleByLine:function(styleSheet,line){if(!domUtils){return null +}var cssRules=styleSheet.cssRules; +for(var i=0; +i=line){return rule +}}}},highlightRule:function(rule){var ruleElement=Firebug.getElementByRepObject(this.panelNode.firstChild,rule); +if(ruleElement){scrollIntoCenterView(ruleElement,this.panelNode); +setClassTimed(ruleElement,"jumpHighlight",this.context) +}},getStyleSheetRules:function(context,styleSheet){var isSystemSheet=isSystemStyleSheet(styleSheet); +function appendRules(cssRules){for(var i=0; +i20){return +}var target=event.target||event.srcElement; +if(hasClass(target,"textEditor")){return +}var row=getAncestorByClass(target,"cssProp"); +if(row&&hasClass(row,"editGroup")){this.disablePropertyRow(row); +cancelEvent(event) +}},onDoubleClick:function(event){var offset=event.clientX-this.panelNode.parentNode.offsetLeft; +if(!isLeftClick(event)||offset<=20){return +}var target=event.target||event.srcElement; +if(hasClass(target,"textEditorInner")){return +}var row=getAncestorByClass(target,"cssRule"); +if(row&&!getAncestorByClass(target,"cssPropName")&&!getAncestorByClass(target,"cssPropValue")){this.insertPropertyRow(row); +cancelEvent(event) +}},name:"stylesheet",title:"CSS",parentPanel:null,searchable:true,dependents:["css","stylesheet","dom","domSide","layout"],options:{hasToolButtons:true},create:function(){Firebug.Panel.create.apply(this,arguments); +this.onMouseDown=bind(this.onMouseDown,this); +this.onDoubleClick=bind(this.onDoubleClick,this); +if(this.name=="stylesheet"){this.onChangeSelect=bind(this.onChangeSelect,this); +var doc=Firebug.browser.document; +var selectNode=this.selectNode=createElement("select"); +processAllStyleSheets(doc,function(doc,styleSheet){var key=StyleSheetCache.key(styleSheet); +var fileName=getFileName(styleSheet.href)||getFileName(doc.location.href); +var option=createElement("option",{value:key}); +option.appendChild(Firebug.chrome.document.createTextNode(fileName)); +selectNode.appendChild(option) +}); +this.toolButtonsNode.appendChild(selectNode) +}},onChangeSelect:function(event){event=event||window.event; +var target=event.srcElement||event.currentTarget; +var key=target.value; +var styleSheet=StyleSheetCache.get(key); +this.updateLocation(styleSheet) +},initialize:function(){Firebug.Panel.initialize.apply(this,arguments); +this.context=Firebug.chrome; +this.document=Firebug.chrome.document; +this.initializeNode(); +if(this.name=="stylesheet"){var styleSheets=Firebug.browser.document.styleSheets; +if(styleSheets.length>0){addEvent(this.selectNode,"change",this.onChangeSelect); +this.updateLocation(styleSheets[0]) +}}},shutdown:function(){Firebug.Editor.stopEditing(); +if(this.name=="stylesheet"){removeEvent(this.selectNode,"change",this.onChangeSelect) +}this.destroyNode(); +Firebug.Panel.shutdown.apply(this,arguments) +},destroy:function(state){Firebug.Panel.destroy.apply(this,arguments) +},initializeNode:function(oldPanelNode){addEvent(this.panelNode,"mousedown",this.onMouseDown); +addEvent(this.panelNode,"dblclick",this.onDoubleClick) +},destroyNode:function(){removeEvent(this.panelNode,"mousedown",this.onMouseDown); +removeEvent(this.panelNode,"dblclick",this.onDoubleClick) +},ishow:function(state){Firebug.Inspector.stopInspecting(true); +this.showToolbarButtons("fbCSSButtons",true); +if(this.context.loaded&&!this.location){restoreObjects(this,state); +if(!this.location){this.location=this.getDefaultLocation() +}if(state&&state.scrollTop){this.panelNode.scrollTop=state.scrollTop +}}},ihide:function(){this.showToolbarButtons("fbCSSButtons",false); +this.lastScrollTop=this.panelNode.scrollTop +},supportsObject:function(object){if(object instanceof CSSStyleSheet){return 1 +}else{if(object instanceof CSSStyleRule){return 2 +}else{if(object instanceof CSSStyleDeclaration){return 2 +}else{if(object instanceof SourceLink&&object.type=="css"&&reCSS.test(object.href)){return 2 +}else{return 0 +}}}}},updateLocation:function(styleSheet){if(!styleSheet){return +}if(styleSheet.editStyleSheet){styleSheet=styleSheet.editStyleSheet.sheet +}if(styleSheet.restricted){FirebugReps.Warning.tag.replace({object:"AccessRestricted"},this.panelNode); +externalStyleSheetWarning.tag.append({object:"The stylesheet could not be loaded due to access restrictions. ",link:"more...",href:"http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22"},this.panelNode); +return +}var rules=this.getStyleSheetRules(this.context,styleSheet); +var result; +if(rules.length){result=this.template.tag.replace({rules:rules},this.panelNode) +}else{result=FirebugReps.Warning.tag.replace({object:"EmptyStyleSheet"},this.panelNode) +}},updateSelection:function(object){this.selection=null; +if(object instanceof CSSStyleDeclaration){object=object.parentRule +}if(object instanceof CSSStyleRule){this.navigate(object.parentStyleSheet); +this.highlightRule(object) +}else{if(object instanceof CSSStyleSheet){this.navigate(object) +}else{if(object instanceof SourceLink){try{var sourceLink=object; +var sourceFile=getSourceFileByHref(sourceLink.href,this.context); +if(sourceFile){clearNode(this.panelNode); +this.showSourceFile(sourceFile); +var lineNo=object.line; +if(lineNo){this.scrollToLine(lineNo,this.jumpHighlightFactory(lineNo,this.context)) +}}else{var stylesheet=getStyleSheetByHref(sourceLink.href,this.context); +if(stylesheet){this.navigate(stylesheet) +}else{if(FBTrace.DBG_CSS){FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href,sourceLink) +}}}}catch(exc){if(FBTrace.DBG_CSS){FBTrace.sysout("css.upDateSelection FAILS "+exc,exc) +}}}}}},updateOption:function(name,value){if(name=="expandShorthandProps"){this.refresh() +}},getLocationList:function(){var styleSheets=getAllStyleSheets(this.context); +return styleSheets +},getOptionsMenuItems:function(){return[{label:"Expand Shorthand Properties",type:"checkbox",checked:Firebug.expandShorthandProps,command:bindFixed(Firebug.togglePref,Firebug,"expandShorthandProps")},"-",{label:"Refresh",command:bind(this.refresh,this)}] +},getContextMenuItems:function(style,target){var items=[]; +if(this.infoTipType=="color"){items.push({label:"CopyColor",command:bindFixed(copyToClipboard,FBL,this.infoTipObject)}) +}else{if(this.infoTipType=="image"){items.push({label:"CopyImageLocation",command:bindFixed(copyToClipboard,FBL,this.infoTipObject)},{label:"OpenImageInNewTab",command:bindFixed(openNewTab,FBL,this.infoTipObject)}) +}}if(isElement(this.selection)){items.push({label:"EditStyle",command:bindFixed(this.editElementStyle,this)}) +}else{if(!isSystemStyleSheet(this.selection)){items.push({label:"NewRule",command:bindFixed(this.insertRule,this,target)}) +}}var cssRule=getAncestorByClass(target,"cssRule"); +if(cssRule&&hasClass(cssRule,"cssEditableRule")){items.push("-",{label:"NewProp",command:bindFixed(this.insertPropertyRow,this,target)}); +var propRow=getAncestorByClass(target,"cssProp"); +if(propRow){var propName=getChildByClass(propRow,"cssPropName")[textContent]; +var isDisabled=hasClass(propRow,"disabledStyle"); +items.push({label:$STRF("EditProp",[propName]),nol10n:true,command:bindFixed(this.editPropertyRow,this,propRow)},{label:$STRF("DeleteProp",[propName]),nol10n:true,command:bindFixed(this.deletePropertyRow,this,propRow)},{label:$STRF("DisableProp",[propName]),nol10n:true,type:"checkbox",checked:isDisabled,command:bindFixed(this.disablePropertyRow,this,propRow)}) +}}items.push("-",{label:"Refresh",command:bind(this.refresh,this)}); +return items +},browseObject:function(object){if(this.infoTipType=="image"){openNewTab(this.infoTipObject); +return true +}},showInfoTip:function(infoTip,target,x,y){var propValue=getAncestorByClass(target,"cssPropValue"); +if(propValue){var offset=getClientOffset(propValue); +var offsetX=x-offset.x; +var text=propValue[textContent]; +var charWidth=propValue.offsetWidth/text.length; +var charOffset=Math.floor(offsetX/charWidth); +var cssValue=parseCSSValue(text,charOffset); +if(cssValue){if(cssValue.value==this.infoTipValue){return true +}this.infoTipValue=cssValue.value; +if(cssValue.type=="rgb"||(!cssValue.type&&isColorKeyword(cssValue.value))){this.infoTipType="color"; +this.infoTipObject=cssValue.value; +return Firebug.InfoTip.populateColorInfoTip(infoTip,cssValue.value) +}else{if(cssValue.type=="url"){var propNameNode=getElementByClass(target.parentNode,"cssPropName"); +if(propNameNode&&isImageRule(propNameNode[textContent])){var rule=Firebug.getRepObject(target); +var baseURL=this.getStylesheetURL(rule); +var relURL=parseURLValue(cssValue.value); +var absURL=isDataURL(relURL)?relURL:absoluteURL(relURL,baseURL); +var repeat=parseRepeatValue(text); +this.infoTipType="image"; +this.infoTipObject=absURL; +return Firebug.InfoTip.populateImageInfoTip(infoTip,absURL,repeat) +}}}}}delete this.infoTipType; +delete this.infoTipValue; +delete this.infoTipObject +},getEditor:function(target,value){if(target==this.panelNode||hasClass(target,"cssSelector")||hasClass(target,"cssRule")||hasClass(target,"cssSheet")){if(!this.ruleEditor){this.ruleEditor=new CSSRuleEditor(this.document) +}return this.ruleEditor +}else{if(!this.editor){this.editor=new CSSEditor(this.document) +}return this.editor +}},getDefaultLocation:function(){try{var styleSheets=this.context.window.document.styleSheets; +if(styleSheets.length){var sheet=styleSheets[0]; +return(Firebug.filterSystemURLs&&isSystemURL(getURLForStyleSheet(sheet)))?null:sheet +}}catch(exc){if(FBTrace.DBG_LOCATIONS){FBTrace.sysout("css.getDefaultLocation FAILS "+exc,exc) +}}},getObjectDescription:function(styleSheet){var url=getURLForStyleSheet(styleSheet); +var instance=getInstanceForStyleSheet(styleSheet); +var baseDescription=splitURLBase(url); +if(instance){baseDescription.name=baseDescription.name+" #"+(instance+1) +}return baseDescription +},search:function(text,reverse){var curDoc=this.searchCurrentDoc(!Firebug.searchGlobal,text,reverse); +if(!curDoc&&Firebug.searchGlobal){return this.searchOtherDocs(text,reverse) +}return curDoc +},searchOtherDocs:function(text,reverse){var scanRE=Firebug.Search.getTestingRegex(text); +function scanDoc(styleSheet){for(var i=0; +i0){externalStyleSheetWarning.tag.append({object:"The results here may be inaccurate because some stylesheets could not be loaded due to access restrictions. ",link:"more...",href:"http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22"},this.panelNode) +}},getStylesheetURL:function(rule){if(rule&&rule.parentStyleSheet&&rule.parentStyleSheet.href){return rule.parentStyleSheet.href +}else{return this.selection.ownerDocument.location.href +}},getInheritedRules:function(element,sections,usedProps){var parent=element.parentNode; +if(parent&&parent.nodeType==1){this.getInheritedRules(parent,sections,usedProps); +var rules=[]; +this.getElementRules(parent,rules,usedProps,true); +if(rules.length){sections.splice(0,0,{element:parent,rules:rules}) +}}},getElementRules:function(element,rules,usedProps,inheritMode){var inspectedRules,displayedRules={}; +inspectedRules=getElementCSSRules(element); +if(inspectedRules){for(var i=0,length=inspectedRules.length; +i"+value+" = "+propValue+"\n") +}if(previousValue){Firebug.CSSModule.removeProperty(rule,previousValue) +}Firebug.CSSModule.setProperty(rule,value,parsedValue.value,parsedValue.priority) +}}else{if(!value){Firebug.CSSModule.removeProperty(rule,previousValue) +}}}else{if(getAncestorByClass(target,"cssPropValue")){var propName=getChildByClass(row,"cssPropName")[textContent]; +var propValue=getChildByClass(row,"cssPropValue")[textContent]; +if(FBTrace.DBG_CSS){FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName+" = "+propValue+"\n") +}if(value&&value!="null"){var parsedValue=parsePriority(value); +Firebug.CSSModule.setProperty(rule,propName,parsedValue.value,parsedValue.priority) +}else{if(previousValue&&previousValue!="null"){Firebug.CSSModule.removeProperty(rule,propName) +}}}}this.panel.markChange(this.panel.name=="stylesheet") +},advanceToNext:function(target,charCode){if(charCode==58&&hasClass(target,"cssPropName")){return true +}},getAutoCompleteRange:function(value,offset){if(hasClass(this.target,"cssPropName")){return{start:0,end:value.length-1} +}else{return parseCSSValue(value,offset) +}},getAutoCompleteList:function(preExpr,expr,postExpr){if(hasClass(this.target,"cssPropName")){return getCSSPropertyNames() +}else{var row=getAncestorByClass(this.target,"cssProp"); +var propName=getChildByClass(row,"cssPropName")[textContent]; +return getCSSKeywordsByProperty(propName) +}}}); +function CSSRuleEditor(doc){this.initializeInline(doc); +this.completeAsYouType=false +}CSSRuleEditor.uniquifier=0; +CSSRuleEditor.prototype=domplate(Firebug.InlineEditor.prototype,{insertNewRow:function(target,insertWhere){var emptyRule={selector:"",id:"",props:[],isSelectorEditable:true}; +if(insertWhere=="before"){return CSSStyleRuleTag.tag.insertBefore({rule:emptyRule},target) +}else{return CSSStyleRuleTag.tag.insertAfter({rule:emptyRule},target) +}},saveEdit:function(target,value,previousValue){if(FBTrace.DBG_CSS){FBTrace.sysout("CSSRuleEditor.saveEdit: '"+value+"' '"+previousValue+"'",target) +}target.innerHTML=escapeForCss(value); +if(value===previousValue){return +}var row=getAncestorByClass(target,"cssRule"); +var styleSheet=this.panel.location; +styleSheet=styleSheet.editStyleSheet?styleSheet.editStyleSheet.sheet:styleSheet; +var cssRules=styleSheet.cssRules; +var rule=Firebug.getRepObject(target),oldRule=rule; +var ruleIndex=cssRules.length; +if(rule||Firebug.getRepObject(row.nextSibling)){var searchRule=rule||Firebug.getRepObject(row.nextSibling); +for(ruleIndex=0; +ruleIndexb.name?1:-1 +}) +}function getTopmostRuleLine(panelNode){for(var child=panelNode.firstChild; +child; +child=child.nextSibling){if(child.offsetTop+child.offsetHeight>panelNode.scrollTop){var rule=child.repObject; +if(rule){return{line:domUtils.getRuleLine(rule),offset:panelNode.scrollTop-child.offsetTop} +}}}return 0 +}function getStyleSheetCSS(sheet,context){if(sheet.ownerNode instanceof HTMLStyleElement){return sheet.ownerNode.innerHTML +}else{return context.sourceCache.load(sheet.href).join("") +}}function getStyleSheetOwnerNode(sheet){for(; +sheet&&!sheet.ownerNode; +sheet=sheet.parentStyleSheet){}return sheet.ownerNode +}function scrollSelectionIntoView(panel){var selCon=getSelectionController(panel); +selCon.scrollSelectionIntoView(nsISelectionController.SELECTION_NORMAL,nsISelectionController.SELECTION_FOCUS_REGION,true) +}function getSelectionController(panel){var browser=Firebug.chrome.getPanelBrowser(panel); +return browser.docShell.QueryInterface(nsIInterfaceRequestor).getInterface(nsISelectionDisplay).QueryInterface(nsISelectionController) +}Firebug.registerModule(Firebug.CSSModule); +Firebug.registerPanel(Firebug.CSSStyleSheetPanel); +Firebug.registerPanel(CSSElementPanel); +Firebug.registerPanel(CSSComputedElementPanel) +}}); +FBL.ns(function(){with(FBL){Firebug.Script=extend(Firebug.Module,{getPanel:function(){return Firebug.chrome?Firebug.chrome.getPanel("Script"):null +},selectSourceCode:function(index){this.getPanel().selectSourceCode(index) +}}); +Firebug.registerModule(Firebug.Script); +function ScriptPanel(){}ScriptPanel.prototype=extend(Firebug.Panel,{name:"Script",title:"Script",selectIndex:0,sourceIndex:-1,options:{hasToolButtons:true},create:function(){Firebug.Panel.create.apply(this,arguments); +this.onChangeSelect=bind(this.onChangeSelect,this); +var doc=Firebug.browser.document; +var scripts=doc.getElementsByTagName("script"); +var selectNode=this.selectNode=createElement("select"); +for(var i=0,script; +script=scripts[i]; +i++){if(Firebug.ignoreFirebugElements&&script.getAttribute("firebugIgnore")){continue +}var fileName=getFileName(script.src)||getFileName(doc.location.href); +var option=createElement("option",{value:i}); +option.appendChild(Firebug.chrome.document.createTextNode(fileName)); +selectNode.appendChild(option) +}this.toolButtonsNode.appendChild(selectNode) +},initialize:function(){this.selectSourceCode(this.selectIndex); +Firebug.Panel.initialize.apply(this,arguments); +addEvent(this.selectNode,"change",this.onChangeSelect) +},shutdown:function(){removeEvent(this.selectNode,"change",this.onChangeSelect); +Firebug.Panel.shutdown.apply(this,arguments) +},detach:function(oldChrome,newChrome){Firebug.Panel.detach.apply(this,arguments); +var oldPanel=oldChrome.getPanel("Script"); +var index=oldPanel.selectIndex; +this.selectNode.selectedIndex=index; +this.selectIndex=index; +this.sourceIndex=-1 +},onChangeSelect:function(event){var select=this.selectNode; +this.selectIndex=select.selectedIndex; +var option=select.options[select.selectedIndex]; +if(!option){return +}var selectedSourceIndex=parseInt(option.value); +this.renderSourceCode(selectedSourceIndex) +},selectSourceCode:function(index){var select=this.selectNode; +select.selectedIndex=index; +var option=select.options[index]; +if(!option){return +}var selectedSourceIndex=parseInt(option.value); +this.renderSourceCode(selectedSourceIndex) +},renderSourceCode:function(index){if(this.sourceIndex!=index){var renderProcess=function renderProcess(src){var html=[],hl=0; +src=isIE&&!isExternal?src+"\n":"\n"+src; +src=src.replace(/\n\r|\r\n/g,"\n"); +var match=src.match(/[\n]/g); +var lines=match?match.length:0; +html[hl++]='
      0){path=reLastDir.exec(path)[1] +}path+=backDir[2] +}else{if(src.indexOf("/")!=-1){if(/^\.\/./.test(src)){path+=src.substring(2) +}else{if(/^\/./.test(src)){var domain=/^(\w+:\/\/[^\/]+)/.exec(path); +path=domain[1]+src +}else{path+=src +}}}}}}var m=path&&path.match(/([^\/]+)\/$/)||null; +if(path&&m){return path+fileName +}}; +var getFileName=function getFileName(path){if(!path){return"" +}var match=path&&path.match(/[^\/]+(\?.*)?(#.*)?$/); +return match&&match[0]||path +} +}}); +FBL.ns(function(){with(FBL){var ElementCache=Firebug.Lite.Cache.Element; +var insertSliceSize=18; +var insertInterval=40; +var ignoreVars={__firebug__:1,"eval":1,java:1,sun:1,Packages:1,JavaArray:1,JavaMember:1,JavaObject:1,JavaClass:1,JavaPackage:1,_firebug:1,_FirebugConsole:1,_FirebugCommandLine:1}; +if(Firebug.ignoreFirebugElements){ignoreVars[Firebug.Lite.Cache.ID]=1 +}var memberPanelRep=isIE6?{"class":"memberLabel $member.type\\Label",href:"javacript:void(0)"}:{"class":"memberLabel $member.type\\Label"}; +var RowTag=TR({"class":"memberRow $member.open $member.type\\Row",$hasChildren:"$member.hasChildren",role:"presentation",level:"$member.level"},TD({"class":"memberLabelCell",style:"padding-left: $member.indent\\px",role:"presentation"},A(memberPanelRep,SPAN({},"$member.name"))),TD({"class":"memberValueCell",role:"presentation"},TAG("$member.tag",{object:"$member.value"}))); +var WatchRowTag=TR({"class":"watchNewRow",level:0},TD({"class":"watchEditCell",colspan:2},DIV({"class":"watchEditBox a11yFocusNoTab",role:"button",tabindex:"0","aria-label":$STR("press enter to add new watch expression")},$STR("NewWatch")))); +var SizerRow=TR({role:"presentation"},TD({width:"30%"}),TD({width:"70%"})); +var domTableClass=isIElt8?"domTable domTableIE":"domTable"; +var DirTablePlate=domplate(Firebug.Rep,{tag:TABLE({"class":domTableClass,cellpadding:0,cellspacing:0,onclick:"$onClick",role:"tree"},TBODY({role:"presentation"},SizerRow,FOR("member","$object|memberIterator",RowTag))),watchTag:TABLE({"class":domTableClass,cellpadding:0,cellspacing:0,_toggles:"$toggles",_domPanel:"$domPanel",onclick:"$onClick",role:"tree"},TBODY({role:"presentation"},SizerRow,WatchRowTag)),tableTag:TABLE({"class":domTableClass,cellpadding:0,cellspacing:0,_toggles:"$toggles",_domPanel:"$domPanel",onclick:"$onClick",role:"tree"},TBODY({role:"presentation"},SizerRow)),rowTag:FOR("member","$members",RowTag),memberIterator:function(object,level){return getMembers(object,level) +},onClick:function(event){if(!isLeftClick(event)){return +}var target=event.target||event.srcElement; +var row=getAncestorByClass(target,"memberRow"); +var label=getAncestorByClass(target,"memberLabel"); +if(label&&hasClass(row,"hasChildren")){var row=label.parentNode.parentNode; +this.toggleRow(row) +}else{var object=Firebug.getRepObject(target); +if(typeof(object)=="function"){Firebug.chrome.select(object,"script"); +cancelEvent(event) +}else{if(event.detail==2&&!object){var panel=row.parentNode.parentNode.domPanel; +if(panel){var rowValue=panel.getRowPropertyValue(row); +if(typeof(rowValue)=="boolean"){panel.setPropertyValue(row,!rowValue) +}else{panel.editProperty(row) +}cancelEvent(event) +}}}}return false +},toggleRow:function(row){var level=parseInt(row.getAttribute("level")); +var toggles=row.parentNode.parentNode.toggles; +if(hasClass(row,"opened")){removeClass(row,"opened"); +if(toggles){var path=getPath(row); +for(var i=0; +i=priorScrollTop){panelNode.scrollTop=priorScrollTop +}},delay)); +delay+=insertInterval +}}if(offscreen){timeouts.push(this.context.setTimeout(function(){if(panelNode.firstChild){panelNode.replaceChild(table,panelNode.firstChild) +}else{panelNode.appendChild(table) +}panelNode.scrollTop=priorScrollTop +},delay)) +}else{timeouts.push(this.context.setTimeout(function(){panelNode.scrollTop=scrollTop==undefined?0:scrollTop +},delay)) +}this.timeouts=timeouts +},showEmptyMembers:function(){FirebugReps.Warning.tag.replace({object:"NoMembersWarning"},this.panelNode) +},findPathObject:function(object){var pathIndex=-1; +for(var i=0; +i1){for(var i=1; +i"); +r.push(i==0?"window":path[i]||"Object"); +r.push(""); +if(i>') +}}panel.statusBarNode.innerHTML=r.join("") +}; +var DOMMainPanel=Firebug.DOMPanel=function(){}; +Firebug.DOMPanel.DirTable=DirTablePlate; +DOMMainPanel.prototype=extend(Firebug.DOMBasePanel.prototype,{onClickStatusBar:function(event){var target=event.srcElement||event.target; +var element=getAncestorByClass(target,"fbHover"); +if(element){var pathIndex=element.getAttribute("pathIndex"); +if(pathIndex){this.select(this.getPathObject(pathIndex)) +}}},selectRow:function(row,target){if(!target){target=row.lastChild.firstChild +}if(!target||!target.repObject){return +}this.pathToAppend=getPath(row); +var valueBox=row.lastChild.firstChild; +if(hasClass(valueBox,"objectBox-array")){var arrayIndex=FirebugReps.Arr.getItemIndex(target); +this.pathToAppend.push(arrayIndex) +}this.select(target.repObject,true) +},onClick:function(event){var target=event.srcElement||event.target; +var repNode=Firebug.getRepNode(target); +if(repNode){var row=getAncestorByClass(target,"memberRow"); +if(row){this.selectRow(row,repNode); +cancelEvent(event) +}}},name:"DOM",title:"DOM",searchable:true,statusSeparator:">",options:{hasToolButtons:true,hasStatusBar:true},create:function(){Firebug.DOMBasePanel.prototype.create.apply(this,arguments); +this.onClick=bind(this.onClick,this); +this.onClickStatusBar=bind(this.onClickStatusBar,this); +this.panelNode.style.padding="0 1px" +},initialize:function(oldPanelNode){Firebug.DOMBasePanel.prototype.initialize.apply(this,arguments); +addEvent(this.panelNode,"click",this.onClick); +this.ishow(); +addEvent(this.statusBarNode,"click",this.onClickStatusBar) +},shutdown:function(){removeEvent(this.panelNode,"click",this.onClick); +Firebug.DOMBasePanel.prototype.shutdown.apply(this,arguments) +}}); +Firebug.registerPanel(DOMMainPanel); +var getMembers=function getMembers(object,level){if(!level){level=0 +}var ordinals=[],userProps=[],userClasses=[],userFuncs=[],domProps=[],domFuncs=[],domConstants=[]; +try{var domMembers=getDOMMembers(object); +if(object.wrappedJSObject){var insecureObject=object.wrappedJSObject +}else{var insecureObject=object +}if(isIE&&isFunction(object)){addMember("user",userProps,"prototype",object.prototype,level) +}for(var name in insecureObject){if(ignoreVars[name]==1){continue +}var val; +try{val=insecureObject[name] +}catch(exc){if(FBTrace.DBG_ERRORS&&FBTrace.DBG_DOM){FBTrace.sysout("dom.getMembers cannot access "+name,exc) +}}var ordinal=parseInt(name); +if(ordinal||ordinal==0){addMember("ordinal",ordinals,name,val,level) +}else{if(isFunction(val)){if(isClassFunction(val)&&!(name in domMembers)){addMember("userClass",userClasses,name,val,level) +}else{if(name in domMembers){addMember("domFunction",domFuncs,name,val,level,domMembers[name]) +}else{addMember("userFunction",userFuncs,name,val,level) +}}}else{var prefix=""; +if(name in domMembers&&!(name in domConstantMap)){addMember("dom",domProps,(prefix+name),val,level,domMembers[name]) +}else{if(name in domConstantMap){addMember("dom",domConstants,(prefix+name),val,level) +}else{addMember("user",userProps,(prefix+name),val,level) +}}}}}}catch(exc){throw exc; +if(FBTrace.DBG_ERRORS&&FBTrace.DBG_DOM){FBTrace.sysout("dom.getMembers FAILS: ",exc) +}}function sortName(a,b){return a.name>b.name?1:-1 +}function sortOrder(a,b){return a.order>b.order?1:-1 +}var members=[]; +members.push.apply(members,ordinals); +Firebug.showUserProps=true; +Firebug.showUserFuncs=true; +Firebug.showDOMProps=true; +Firebug.showDOMFuncs=true; +Firebug.showDOMConstants=true; +if(Firebug.showUserProps){userProps.sort(sortName); +members.push.apply(members,userProps) +}if(Firebug.showUserFuncs){userClasses.sort(sortName); +members.push.apply(members,userClasses); +userFuncs.sort(sortName); +members.push.apply(members,userFuncs) +}if(Firebug.showDOMProps){domProps.sort(sortName); +members.push.apply(members,domProps) +}if(Firebug.showDOMFuncs){domFuncs.sort(sortName); +members.push.apply(members,domFuncs) +}if(Firebug.showDOMConstants){members.push.apply(members,domConstants) +}return members +}; +function expandMembers(members,toggles,offset,level){var expanded=0; +for(var i=offset; +ilevel){break +}if(toggles.hasOwnProperty(member.name)){member.open="opened"; +var newMembers=getMembers(member.value,level+1); +var args=[i+1,0]; +args.push.apply(args,newMembers); +members.splice.apply(members,args); +expanded+=newMembers.length; +i+=newMembers.length+expandMembers(members,toggles[member.name],i+1,level+1) +}}return expanded +}function isClassFunction(fn){try{for(var name in fn.prototype){return true +}}catch(exc){}return false +}var hasProperties=function hasProperties(ob){try{for(var name in ob){return true +}}catch(exc){}if(isFunction(ob)){return true +}return false +}; +FBL.ErrorCopy=function(message){this.message=message +}; +var addMember=function addMember(type,props,name,value,level,order){var rep=Firebug.getRep(value); +var tag=rep.shortTag?rep.shortTag:rep.tag; +var ErrorCopy=function(){}; +var valueType=typeof(value); +var hasChildren=hasProperties(value)&&!(value instanceof ErrorCopy)&&(isFunction(value)||(valueType=="object"&&value!=null)||(valueType=="string"&&value.length>Firebug.stringCropLength)); +props.push({name:name,value:value,type:type,rowClass:"memberRow-"+type,open:"",order:order,level:level,indent:level*16,hasChildren:hasChildren,tag:tag}) +}; +var getWatchRowIndex=function getWatchRowIndex(row){var index=-1; +for(; +row&&hasClass(row,"watchRow"); +row=row.previousSibling){++index +}return index +}; +var getRowName=function getRowName(row){var node=row.firstChild; +return node.textContent?node.textContent:node.innerText +}; +var getRowValue=function getRowValue(row){return row.lastChild.firstChild.repObject +}; +var getRowOwnerObject=function getRowOwnerObject(row){var parentRow=getParentRow(row); +if(parentRow){return getRowValue(parentRow) +}}; +var getParentRow=function getParentRow(row){var level=parseInt(row.getAttribute("level"))-1; +for(row=row.previousSibling; +row; +row=row.previousSibling){if(parseInt(row.getAttribute("level"))==level){return row +}}}; +var getPath=function getPath(row){var name=getRowName(row); +var path=[name]; +var level=parseInt(row.getAttribute("level"))-1; +for(row=row.previousSibling; +row; +row=row.previousSibling){if(parseInt(row.getAttribute("level"))==level){var name=getRowName(row); +path.splice(0,0,name); +--level +}}return path +}; +Firebug.DOM=extend(Firebug.Module,{getPanel:function(){return Firebug.chrome?Firebug.chrome.getPanel("DOM"):null +}}); +Firebug.registerModule(Firebug.DOM); +var lastHighlightedObject; +function DOMSidePanel(){}DOMSidePanel.prototype=extend(Firebug.DOMBasePanel.prototype,{selectRow:function(row,target){if(!target){target=row.lastChild.firstChild +}if(!target||!target.repObject){return +}this.pathToAppend=getPath(row); +var valueBox=row.lastChild.firstChild; +if(hasClass(valueBox,"objectBox-array")){var arrayIndex=FirebugReps.Arr.getItemIndex(target); +this.pathToAppend.push(arrayIndex) +}var object=target.repObject; +if(instanceOf(object,"Element")){Firebug.HTML.selectTreeNode(ElementCache(object)) +}else{Firebug.chrome.selectPanel("DOM"); +Firebug.chrome.getPanel("DOM").select(object,true) +}},onClick:function(event){var target=event.srcElement||event.target; +var repNode=Firebug.getRepNode(target); +if(repNode){var row=getAncestorByClass(target,"memberRow"); +if(row){this.selectRow(row,repNode); +cancelEvent(event) +}}},name:"DOMSidePanel",parentPanel:"HTML",title:"DOM",options:{hasToolButtons:true},isInitialized:false,create:function(){Firebug.DOMBasePanel.prototype.create.apply(this,arguments); +this.onClick=bind(this.onClick,this) +},initialize:function(){Firebug.DOMBasePanel.prototype.initialize.apply(this,arguments); +addEvent(this.panelNode,"click",this.onClick); +var selection=ElementCache.get(FirebugChrome.selectedHTMLElementId); +if(selection){this.select(selection,true) +}},shutdown:function(){removeEvent(this.panelNode,"click",this.onClick); +Firebug.DOMBasePanel.prototype.shutdown.apply(this,arguments) +},reattach:function(oldChrome){this.toggles=oldChrome.getPanel("DOMSidePanel").toggles +}}); +Firebug.registerPanel(DOMSidePanel) +}}); +FBL.FBTrace={}; +(function(){var traceOptions={DBG_TIMESTAMP:1,DBG_INITIALIZE:1,DBG_CHROME:1,DBG_ERRORS:1,DBG_DISPATCH:1,DBG_CSS:1}; +this.module=null; +this.initialize=function(){if(!this.messageQueue){this.messageQueue=[] +}for(var name in traceOptions){this[name]=traceOptions[name] +}}; +this.sysout=function(){return this.logFormatted(arguments,"") +}; +this.dumpProperties=function(title,object){return this.logFormatted("dumpProperties() not supported.","warning") +}; +this.dumpStack=function(){return this.logFormatted("dumpStack() not supported.","warning") +}; +this.flush=function(module){this.module=module; +var queue=this.messageQueue; +this.messageQueue=[]; +for(var i=0; +i"); +appendText(object,html); +html.push("") +}else{appendText(object,html) +}}return this.logRow(html,className) +}; +this.logRow=function(message,className){var panel=this.getPanel(); +if(panel&&panel.panelNode){this.writeMessage(message,className) +}else{this.messageQueue.push([message,className]) +}return this.LOG_COMMAND +}; +this.writeMessage=function(message,className){var container=this.getPanel().containerNode; +var isScrolledToBottom=container.scrollTop+container.offsetHeight>=container.scrollHeight; +this.writeRow.call(this,message,className); +if(isScrolledToBottom){container.scrollTop=container.scrollHeight-container.offsetHeight +}}; +this.appendRow=function(row){var container=this.getPanel().panelNode; +container.appendChild(row) +}; +this.writeRow=function(message,className){var row=this.getPanel().panelNode.ownerDocument.createElement("div"); +row.className="logRow"+(className?" logRow-"+className:""); +row.innerHTML=message.join(""); +this.appendRow(row) +}; +function appendText(object,html){html.push(escapeHTML(objectToString(object))) +}function getTimestamp(){var now=new Date(); +var ms=""+(now.getMilliseconds()/1000).toFixed(3); +ms=ms.substr(2); +return now.toLocaleTimeString()+"."+ms +}var HTMLtoEntity={"<":"<",">":">","&":"&","'":"'",'"':"""}; +function replaceChars(ch){return HTMLtoEntity[ch] +}function escapeHTML(value){return(value+"").replace(/[<>&"']/g,replaceChars) +}function objectToString(object){try{return object+"" +}catch(exc){return null +}}}).apply(FBL.FBTrace); +FBL.ns(function(){with(FBL){if(!Env.Options.enableTrace){return +}Firebug.Trace=extend(Firebug.Module,{getPanel:function(){return Firebug.chrome?Firebug.chrome.getPanel("Trace"):null +},clear:function(){this.getPanel().panelNode.innerHTML="" +}}); +Firebug.registerModule(Firebug.Trace); +function TracePanel(){}TracePanel.prototype=extend(Firebug.Panel,{name:"Trace",title:"Trace",options:{hasToolButtons:true,innerHTMLSync:true},create:function(){Firebug.Panel.create.apply(this,arguments); +this.clearButton=new Button({caption:"Clear",title:"Clear FBTrace logs",owner:Firebug.Trace,onClick:Firebug.Trace.clear}) +},initialize:function(){Firebug.Panel.initialize.apply(this,arguments); +this.clearButton.initialize() +}}); +Firebug.registerPanel(TracePanel) +}}); +FBL.ns(function(){with(FBL){var modules=[]; +var panelTypes=[]; +var panelTypeMap={}; +var parentPanelMap={}; +var registerModule=Firebug.registerModule; +var registerPanel=Firebug.registerPanel; +append(Firebug,{extend:function(fn){if(Firebug.chrome&&Firebug.chrome.addPanel){var namespace=ns(fn); +fn.call(namespace,FBL) +}else{setTimeout(function(){Firebug.extend(fn) +},100) +}},registerModule:function(){registerModule.apply(Firebug,arguments); +modules.push.apply(modules,arguments); +dispatch(modules,"initialize",[]); +if(FBTrace.DBG_INITIALIZE){FBTrace.sysout("Firebug.registerModule") +}},registerPanel:function(){registerPanel.apply(Firebug,arguments); +panelTypes.push.apply(panelTypes,arguments); +for(var i=0,panelType; +panelType=arguments[i]; +++i){if(panelType.prototype.name=="Dev"){continue +}panelTypeMap[panelType.prototype.name]=arguments[i]; +var parentPanelName=panelType.prototype.parentPanel; +if(parentPanelName){parentPanelMap[parentPanelName]=1 +}else{var panelName=panelType.prototype.name; +var chrome=Firebug.chrome; +chrome.addPanel(panelName); +var onTabClick=function onTabClick(){chrome.selectPanel(panelName); +return false +}; +chrome.addController([chrome.panelMap[panelName].tabNode,"mousedown",onTabClick]) +}}if(FBTrace.DBG_INITIALIZE){for(var i=0; +i .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) no-repeat !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;}#fbPanelBarBox{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}',HTML:'
       
       
      >>>
      2 errors'} +}}); +FBL.initialize() +})(); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/license.txt b/php/kindeditor_demo/kindeditor/lib/firebug-lite/license.txt new file mode 100755 index 0000000..ba43b75 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/license.txt @@ -0,0 +1,30 @@ +Software License Agreement (BSD License) + +Copyright (c) 2007, Parakey Inc. +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Parakey Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Parakey Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/plugin/proxy/proxy.php b/php/kindeditor_demo/kindeditor/lib/firebug-lite/plugin/proxy/proxy.php new file mode 100755 index 0000000..3bf3f92 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/plugin/proxy/proxy.php @@ -0,0 +1,258 @@ + and +// are disabled by default, see for more information. +// callback - If specified, the response JSON will be wrapped in this named +// function call. This parameter and are disabled by +// default, see for more information. +// user_agent - This value will be sent to the remote URL request as the +// `User-Agent:` HTTP request header. If omitted, the browser user agent +// will be passed through. +// send_cookies - If send_cookies=1, all cookies will be forwarded through to +// the remote URL request. +// send_session - If send_session=1 and send_cookies=1, the SID cookie will be +// forwarded through to the remote URL request. +// full_headers - If a JSON request and full_headers=1, the JSON response will +// contain detailed header information. +// full_status - If a JSON request and full_status=1, the JSON response will +// contain detailed cURL status information, otherwise it will just contain +// the `http_code` property. +// +// Topic: POST Parameters +// +// All POST parameters are automatically passed through to the remote URL +// request. +// +// Topic: JSON requests +// +// This request will return the contents of the specified url in JSON format. +// +// Request: +// +// > ba-simple-proxy.php?url=http://example.com/ +// +// Response: +// +// > { "contents": "...", "headers": {...}, "status": {...} } +// +// JSON object properties: +// +// contents - (String) The contents of the remote URL resource. +// headers - (Object) A hash of HTTP headers returned by the remote URL +// resource. +// status - (Object) A hash of status codes returned by cURL. +// +// Topic: JSONP requests +// +// This request will return the contents of the specified url in JSONP format +// (but only if $enable_jsonp is enabled in the PHP script). +// +// Request: +// +// > ba-simple-proxy.php?url=http://example.com/&callback=foo +// +// Response: +// +// > foo({ "contents": "...", "headers": {...}, "status": {...} }) +// +// JSON object properties: +// +// contents - (String) The contents of the remote URL resource. +// headers - (Object) A hash of HTTP headers returned by the remote URL +// resource. +// status - (Object) A hash of status codes returned by cURL. +// +// Topic: Native requests +// +// This request will return the contents of the specified url in the format it +// was received in, including the same content-type and other headers (but only +// if $enable_native is enabled in the PHP script). +// +// Request: +// +// > ba-simple-proxy.php?url=http://example.com/&mode=native +// +// Response: +// +// > ... +// +// Topic: Notes +// +// * Assumes magic_quotes_gpc = Off in php.ini +// +// Topic: Configuration Options +// +// These variables can be manually edited in the PHP file if necessary. +// +// $enable_jsonp - Only enable if you really need to. If you +// install this script on the same server as the page you're calling it +// from, plain JSON will work. Defaults to false. +// $enable_native - You can enable , but you should only do +// this if you also whitelist specific URLs using $valid_url_regex, to avoid +// possible XSS vulnerabilities. Defaults to false. +// $valid_url_regex - This regex is matched against the url parameter to +// ensure that it is valid. This setting only needs to be used if either +// $enable_jsonp or $enable_native are enabled. Defaults to '/.*/' which +// validates all URLs. +// +// ############################################################################ + +// Change these configuration options if needed, see above descriptions for info. +$enable_jsonp = false; +$enable_native = false; +$valid_url_regex = '/.*/'; + +// ############################################################################ + +$url = $_GET['url']; + +if ( !$url ) { + + // Passed url not specified. + $contents = 'ERROR: url not specified'; + $status = array( 'http_code' => 'ERROR' ); + +} else if ( !preg_match( $valid_url_regex, $url ) ) { + + // Passed url doesn't match $valid_url_regex. + $contents = 'ERROR: invalid url'; + $status = array( 'http_code' => 'ERROR' ); + +} else { + $ch = curl_init( $url ); + + if ( strtolower($_SERVER['REQUEST_METHOD']) == 'post' ) { + curl_setopt( $ch, CURLOPT_POST, true ); + curl_setopt( $ch, CURLOPT_POSTFIELDS, $_POST ); + } + + if ( $_GET['send_cookies'] ) { + $cookie = array(); + foreach ( $_COOKIE as $key => $value ) { + $cookie[] = $key . '=' . $value; + } + if ( $_GET['send_session'] ) { + $cookie[] = SID; + } + $cookie = implode( '; ', $cookie ); + + curl_setopt( $ch, CURLOPT_COOKIE, $cookie ); + } + + curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true ); + curl_setopt( $ch, CURLOPT_HEADER, true ); + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); + + curl_setopt( $ch, CURLOPT_USERAGENT, $_GET['user_agent'] ? $_GET['user_agent'] : $_SERVER['HTTP_USER_AGENT'] ); + + list( $header, $contents ) = preg_split( '/([\r\n][\r\n])\\1/', curl_exec( $ch ), 2 ); + + $status = curl_getinfo( $ch ); + + curl_close( $ch ); +} + +// Split header text into an array. +$header_text = preg_split( '/[\r\n]+/', $header ); + +if ( $_GET['mode'] == 'native' ) { + if ( !$enable_native ) { + $contents = 'ERROR: invalid mode'; + $status = array( 'http_code' => 'ERROR' ); + } + + // Propagate headers to response. + foreach ( $header_text as $header ) { + if ( preg_match( '/^(?:Content-Type|Content-Language|Set-Cookie):/i', $header ) ) { + header( $header ); + } + } + + print $contents; + +} else { + + // $data will be serialized into JSON data. + $data = array(); + + // Propagate all HTTP headers into the JSON data object. + if ( $_GET['full_headers'] ) { + $data['headers'] = array(); + + foreach ( $header_text as $header ) { + preg_match( '/^(.+?):\s+(.*)$/', $header, $matches ); + if ( $matches ) { + $data['headers'][ $matches[1] ] = $matches[2]; + } + } + } + + // Propagate all cURL request / response info to the JSON data object. + if ( $_GET['full_status'] ) { + $data['status'] = $status; + } else { + $data['status'] = array(); + $data['status']['http_code'] = $status['http_code']; + } + + // Set the JSON data object contents, decoding it from JSON if possible. + $decoded_json = json_decode( $contents ); + $data['contents'] = $decoded_json ? $decoded_json : $contents; + + // Generate appropriate content-type header. + $is_xhr = strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'; + header( 'Content-type: application/' . ( $is_xhr ? 'json' : 'x-javascript' ) ); + header('Access-Control-Allow-Origin: *'); + + // Get JSONP callback. + $jsonp_callback = $enable_jsonp && isset($_GET['callback']) ? $_GET['callback'] : null; + + // Generate JSON/JSONP string + $json = json_encode( $data ); + + print $jsonp_callback ? "$jsonp_callback($json)" : $json; + +} + +?> diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/blank.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/blank.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/blank.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/buttonBg.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/buttonBg.png new file mode 100755 index 0000000..f367b42 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/buttonBg.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/buttonBgHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/buttonBgHover.png new file mode 100755 index 0000000..cd37a0d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/buttonBgHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/detach.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/detach.png new file mode 100755 index 0000000..0ddb9a1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/detach.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/detachHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/detachHover.png new file mode 100755 index 0000000..e419272 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/detachHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disable.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disable.gif new file mode 100755 index 0000000..dd9eb0e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disable.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disable.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disable.png new file mode 100755 index 0000000..c28bcdf Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disable.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disableHover.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disableHover.gif new file mode 100755 index 0000000..70565a8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disableHover.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disableHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disableHover.png new file mode 100755 index 0000000..26fe375 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/disableHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/down.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/down.png new file mode 100755 index 0000000..acbbd30 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/down.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/downActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/downActive.png new file mode 100755 index 0000000..f4312b2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/downActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/downHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/downHover.png new file mode 100755 index 0000000..8144e63 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/downHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon-sm.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon-sm.png new file mode 100755 index 0000000..0c377e3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon-sm.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon.gif new file mode 100755 index 0000000..8ee8116 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon.png new file mode 100755 index 0000000..2d75261 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/errorIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.css new file mode 100755 index 0000000..004925f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.css @@ -0,0 +1,3063 @@ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Loose */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* +.netInfoResponseHeadersTitle, netInfoResponseHeadersBody { + display: none; +} +/**/ + +/* IE6 need a separated rule, otherwise it will not recognize it */ +.collapsed { + display: none; +} + +[collapsed="true"] { + display: none; +} + +#fbCSS { + padding: 0 !important; +} + +.cssPropDisable { + float: left; + display: block; + width: 2em; + cursor: default; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* panelBase */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/************************************************************************************************/ + +.infoTip { + z-index: 2147483647; + position: fixed; + padding: 2px 3px; + border: 1px solid #CBE087; + background: LightYellow; + font-family: Monaco, monospace; + color: #000000; + display: none; + white-space: nowrap; + pointer-events: none; +} + +.infoTip[active="true"] { + display: block; +} + +.infoTipLoading { + width: 16px; + height: 16px; + background: url(chrome://firebug/skin/loading_16.gif) no-repeat; +} + +.infoTipImageBox { + min-width: 100px; + text-align: center; +} + +.infoTipCaption { + font: message-box; +} + +.infoTipLoading > .infoTipImage, +.infoTipLoading > .infoTipCaption { + display: none; +} + +/************************************************************************************************/ + +h1.groupHeader { + padding: 2px 4px; + margin: 0 0 4px 0; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + background: #eee url(group.gif) repeat-x; + font-size: 11px; + font-weight: bold; + _position: relative; +} + +/************************************************************************************************/ + +.inlineEditor, +.fixedWidthEditor { + z-index: 2147483647; + position: absolute; + display: none; +} + +.inlineEditor { + margin-left: -6px; + margin-top: -3px; + /* + _margin-left: -7px; + _margin-top: -5px; + /**/ +} + +.textEditorInner, +.fixedWidthEditor { + margin: 0 0 0 0 !important; + padding: 0; + border: none !important; + font: inherit; + text-decoration: inherit; + background-color: #FFFFFF; +} + +.fixedWidthEditor { + border-top: 1px solid #888888 !important; + border-bottom: 1px solid #888888 !important; +} + +.textEditorInner { + position: relative; + top: -7px; + left: -5px; + + outline: none; + resize: none; + + /* + _border: 1px solid #999 !important; + _padding: 1px !important; + _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040"); + /**/ +} + +.textEditorInner1 { + padding-left: 11px; + background: url(textEditorBorders.png) repeat-y; + _background: url(textEditorBorders.gif) repeat-y; + _overflow: hidden; +} + +.textEditorInner2 { + position: relative; + padding-right: 2px; + background: url(textEditorBorders.png) repeat-y 100% 0; + _background: url(textEditorBorders.gif) repeat-y 100% 0; + _position: fixed; +} + +.textEditorTop1 { + background: url(textEditorCorners.png) no-repeat 100% 0; + margin-left: 11px; + height: 10px; + _background: url(textEditorCorners.gif) no-repeat 100% 0; + _overflow: hidden; +} + +.textEditorTop2 { + position: relative; + left: -11px; + width: 11px; + height: 10px; + background: url(textEditorCorners.png) no-repeat; + _background: url(textEditorCorners.gif) no-repeat; +} + +.textEditorBottom1 { + position: relative; + background: url(textEditorCorners.png) no-repeat 100% 100%; + margin-left: 11px; + height: 12px; + _background: url(textEditorCorners.gif) no-repeat 100% 100%; +} + +.textEditorBottom2 { + position: relative; + left: -11px; + width: 11px; + height: 12px; + background: url(textEditorCorners.png) no-repeat 0 100%; + _background: url(textEditorCorners.gif) no-repeat 0 100%; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* CSS */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-css { + overflow-x: hidden; +} + +.cssSheet > .insertBefore { + height: 1.5em; +} + +.cssRule { + position: relative; + margin: 0; + padding: 1em 0 0 6px; + font-family: Monaco, monospace; + color: #000000; +} + +.cssRule:first-child { + padding-top: 6px; +} + +.cssElementRuleContainer { + position: relative; +} + +.cssHead { + padding-right: 150px; +} + +.cssProp { + /*padding-left: 2em;*/ +} + +.cssPropName { + color: DarkGreen; +} + +.cssPropValue { + margin-left: 8px; + color: DarkBlue; +} + +.cssOverridden span { + text-decoration: line-through; +} + +.cssInheritedRule { +} + +.cssInheritLabel { + margin-right: 0.5em; + font-weight: bold; +} + +.cssRule .objectLink-sourceLink { + top: 0; +} + +.cssProp.editGroup:hover { + background: url(disable.png) no-repeat 2px 1px; + _background: url(disable.gif) no-repeat 2px 1px; +} + +.cssProp.editGroup.editing { + background: none; +} + +.cssProp.disabledStyle { + background: url(disableHover.png) no-repeat 2px 1px; + _background: url(disableHover.gif) no-repeat 2px 1px; + opacity: 1; + color: #CCCCCC; +} + +.disabledStyle .cssPropName, +.disabledStyle .cssPropValue { + color: #CCCCCC; +} + +.cssPropValue.editing + .cssSemi, +.inlineExpander + .cssSemi { + display: none; +} + +.cssPropValue.editing { + white-space: nowrap; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.stylePropName { + font-weight: bold; + padding: 0 4px 4px 4px; + width: 50%; +} + +.stylePropValue { + width: 50%; +} +/* +.useA11y .a11yCSSView .focusRow:focus { + outline: none; + background-color: transparent + } + + .useA11y .a11yCSSView .focusRow:focus .cssSelector, + .useA11y .a11yCSSView .focusRow:focus .cssPropName, + .useA11y .a11yCSSView .focusRow:focus .cssPropValue, + .useA11y .a11yCSSView .computedStyleRow:focus, + .useA11y .a11yCSSView .groupHeader:focus { + outline: 2px solid #FF9933; + outline-offset: -2px; + background-color: #FFFFD6; + } + + .useA11y .a11yCSSView .groupHeader:focus { + outline-offset: -2px; + } +/**/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Net */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-net { + overflow-x: hidden; +} + +.netTable { + width: 100%; +} + +/************************************************************************************************/ + +.hideCategory-undefined .category-undefined, +.hideCategory-html .category-html, +.hideCategory-css .category-css, +.hideCategory-js .category-js, +.hideCategory-image .category-image, +.hideCategory-xhr .category-xhr, +.hideCategory-flash .category-flash, +.hideCategory-txt .category-txt, +.hideCategory-bin .category-bin { + display: none; +} + +/************************************************************************************************/ + +.netHeadRow { + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netHeadCol { + border-bottom: 1px solid #CCCCCC; + padding: 2px 4px 2px 18px; + font-weight: bold; +} + +.netHeadLabel { + white-space: nowrap; + overflow: hidden; +} + +/************************************************************************************************/ +/* Header for Net panel table */ + +.netHeaderRow { + height: 16px; +} + +.netHeaderCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x; + white-space: nowrap; +} + +.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox { + padding: 2px 14px 2px 18px; +} + +.netHeaderCellBox { + padding: 2px 14px 2px 10px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.netHeaderCell:hover:active { + background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x; +} + +.netHeaderSorted { + background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x; +} + +.netHeaderSorted > .netHeaderCellBox { + border-right-color: #6B7C93; + background: url(chrome://firebug/skin/arrowDown.png) no-repeat right; +} + +.netHeaderSorted.sortedAscending > .netHeaderCellBox { + background-image: url(chrome://firebug/skin/arrowUp.png); +} + +.netHeaderSorted:hover:active { + background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x; +} + +/************************************************************************************************/ +/* Breakpoints */ + +.panelNode-net .netRowHeader { + display: block; +} + +.netRowHeader { + cursor: pointer; + display: none; + height: 15px; + margin-right: 0 !important; +} + +/* Display brekpoint disc */ +.netRow .netRowHeader { + background-position: 5px 1px; +} + +.netRow[breakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpoint.png); +} + +.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpointDisabled.png); +} + +.netRow.category-xhr:hover .netRowHeader { + background-color: #F6F6F6; +} + +#netBreakpointBar { + max-width: 38px; +} + +#netHrefCol > .netHeaderCellBox { + border-left: 0px; +} + +.netRow .netRowHeader { + width: 3px; +} + +.netInfoRow .netRowHeader { + display: table-cell; +} + +/************************************************************************************************/ +/* Column visibility */ + +.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"], +.netTable[hiddenCols~=netHrefCol] TD.netHrefCol, +.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"], +.netTable[hiddenCols~=netStatusCol] TD.netStatusCol, +.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"], +.netTable[hiddenCols~=netDomainCol] TD.netDomainCol, +.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"], +.netTable[hiddenCols~=netSizeCol] TD.netSizeCol, +.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"], +.netTable[hiddenCols~=netTimeCol] TD.netTimeCol { + display: none; +} + +/************************************************************************************************/ + +.netRow { + background: LightYellow; +} + +.netRow.loaded { + background: #FFFFFF; +} + +.netRow.loaded:hover { + background: #EFEFEF; +} + +.netCol { + padding: 0; + vertical-align: top; + border-bottom: 1px solid #EFEFEF; + white-space: nowrap; + height: 17px; +} + +.netLabel { + width: 100%; +} + +.netStatusCol { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.responseError > .netStatusCol { + color: red; +} + +.netDomainCol { + padding-left: 5px; +} + +.netSizeCol { + text-align: right; + padding-right: 10px; +} + +.netHrefLabel { + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 10; + position: absolute; + padding-left: 18px; + padding-top: 1px; + max-width: 15%; + font-weight: bold; +} + +.netFullHrefLabel { + display: none; + -moz-user-select: none; + padding-right: 10px; + padding-bottom: 3px; + max-width: 100%; + background: #FFFFFF; + z-index: 200; +} + +.netHrefCol:hover > .netFullHrefLabel { + display: block; +} + +.netRow.loaded:hover .netCol > .netFullHrefLabel { + background-color: #EFEFEF; +} + +.useA11y .a11yShowFullLabel { + display: block; + background-image: none !important; + border: 1px solid #CBE087; + background-color: LightYellow; + font-family: Monaco, monospace; + color: #000000; + font-size: 10px; + z-index: 2147483647; +} + +.netSizeLabel { + padding-left: 6px; +} + +.netStatusLabel, +.netDomainLabel, +.netSizeLabel, +.netBar { + padding: 1px 0 2px 0 !important; +} + +.responseError { + color: red; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.hasHeaders .netHrefLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/************************************************************************************************/ + +.netLoadingIcon { + position: absolute; + border: 0; + margin-left: 14px; + width: 16px; + height: 16px; + background: transparent no-repeat 0 0; + background-image: url(chrome://firebug/skin/loading_16.gif); + display:inline-block; +} + +.loaded .netLoadingIcon { + display: none; +} + +/************************************************************************************************/ + +.netBar, .netSummaryBar { + position: relative; + border-right: 50px solid transparent; +} + +.netResolvingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x; + z-index:60; +} + +.netConnectingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x; + z-index:50; +} + +.netBlockingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x; + z-index:40; +} + +.netSendingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x; + z-index:30; +} + +.netWaitingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x; + z-index:20; + min-width: 1px; +} + +.netReceivingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x; + z-index:10; +} + +.netWindowLoadBar, +.netContentLoadBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 1px; + background-color: red; + z-index: 70; + opacity: 0.5; + display: none; + margin-bottom:-1px; +} + +.netContentLoadBar { + background-color: Blue; +} + +.netTimeLabel { + -moz-box-sizing: padding-box; + position: absolute; + top: 1px; + left: 100%; + padding-left: 6px; + color: #444444; + min-width: 16px; +} + +/* + * Timing info tip is reusing net timeline styles to display the same + * colors for individual request phases. Notice that the info tip must + * respect also loaded and fromCache styles that also modify the + * actual color. These are used both on the same element in case + * of the tooltip. + */ +.loaded .netReceivingBar, +.loaded.netReceivingBar { + background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x; + border-color: #B6B6B6; +} + +.fromCache .netReceivingBar, +.fromCache.netReceivingBar { + background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x; + border-color: #D6D6D6; +} + +.netSummaryRow .netTimeLabel, +.loaded .netTimeLabel { + background: transparent; +} + +/************************************************************************************************/ +/* Time Info tip */ + +.timeInfoTip { + width: 150px; + height: 40px +} + +.timeInfoTipBar, +.timeInfoTipEventBar { + position: relative; + display: block; + margin: 0; + opacity: 1; + height: 15px; + width: 4px; +} + +.timeInfoTipEventBar { + width: 1px !important; +} + +.timeInfoTipCell.startTime { + padding-right: 8px; +} + +.timeInfoTipCell.elapsedTime { + text-align: right; + padding-right: 8px; +} + +/************************************************************************************************/ +/* Size Info tip */ + +.sizeInfoLabelCol { + font-weight: bold; + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; +} + +.sizeInfoSizeCol { + font-weight: bold; +} + +.sizeInfoDetailCol { + color: gray; + text-align: right; +} + +.sizeInfoDescCol { + font-style: italic; +} + +/************************************************************************************************/ +/* Summary */ + +.netSummaryRow .netReceivingBar { + background: #BBBBBB; + border: none; +} + +.netSummaryLabel { + color: #222222; +} + +.netSummaryRow { + background: #BBBBBB !important; + font-weight: bold; +} + +.netSummaryRow .netBar { + border-right-color: #BBBBBB; +} + +.netSummaryRow > .netCol { + border-top: 1px solid #999999; + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 1px; + padding-bottom: 2px; +} + +.netSummaryRow > .netHrefCol:hover { + background: transparent !important; +} + +.netCountLabel { + padding-left: 18px; +} + +.netTotalSizeCol { + text-align: right; + padding-right: 10px; +} + +.netTotalTimeCol { + text-align: right; +} + +.netCacheSizeLabel { + position: absolute; + z-index: 1000; + left: 0; + top: 0; +} + +/************************************************************************************************/ + +.netLimitRow { + background: rgb(255, 255, 225) !important; + font-weight:normal; + color: black; + font-weight:normal; +} + +.netLimitLabel { + padding-left: 18px; +} + +.netLimitRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + vertical-align: middle !important; + padding-top: 2px; + padding-bottom: 2px; +} + +.netLimitButton { + font-size: 11px; + padding-top: 1px; + padding-bottom: 1px; +} + +/************************************************************************************************/ + +.netInfoCol { + border-top: 1px solid #EEEEEE; + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netInfoBody { + margin: 10px 0 4px 10px; +} + +.netInfoTabs { + position: relative; + padding-left: 17px; +} + +.netInfoTab { + position: relative; + top: -3px; + margin-top: 10px; + padding: 4px 6px; + border: 1px solid transparent; + border-bottom: none; + _border: none; + font-weight: bold; + color: #565656; + cursor: pointer; +} + +/*.netInfoTab:hover { + cursor: pointer; +}*/ + +/* replaced by .netInfoTabSelected for IE6 support +.netInfoTab[selected="true"] { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} +/**/ +.netInfoTabSelected { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} + +.logRow-netInfo.error .netInfoTitle { + color: red; +} + +.logRow-netInfo.loading .netInfoResponseText { + font-style: italic; + color: #888888; +} + +.loading .netInfoResponseHeadersTitle { + display: none; +} + +.netInfoResponseSizeLimit { + font-family: Lucida Grande, Tahoma, sans-serif; + padding-top: 10px; + font-size: 11px; +} + +.netInfoText { + display: none; + margin: 0; + border: 1px solid #D7D7D7; + border-right: none; + padding: 8px; + background-color: #FFFFFF; + font-family: Monaco, monospace; + /* white-space: pre; */ + /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */ +} + +/* replaced by .netInfoTextSelected for IE6 support +.netInfoText[selected="true"] { + display: block; +} +/**/ +.netInfoTextSelected { + display: block; +} + +.netInfoParamName { + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + vertical-align: top; + text-align: right; + white-space: nowrap; +} + +.netInfoPostText .netInfoParamName { + width: 1px; /* Google Chrome need this otherwise the first column of + the post variables table will be larger than expected */ +} + +.netInfoParamValue { + width: 100%; +} + +.netInfoHeadersText, +.netInfoPostText, +.netInfoPutText { + padding-top: 0; +} + +.netInfoHeadersGroup, +.netInfoPostParams, +.netInfoPostSource { + margin-bottom: 4px; + border-bottom: 1px solid #D7D7D7; + padding-top: 8px; + padding-bottom: 2px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #565656; +} + +.netInfoPostParamsTable, +.netInfoPostPartsTable, +.netInfoPostJSONTable, +.netInfoPostXMLTable, +.netInfoPostSourceTable { + margin-bottom: 10px; + width: 100%; +} + +.netInfoPostContentType { + color: #bdbdbd; + padding-left: 50px; + font-weight: normal; +} + +.netInfoHtmlPreview { + border: 0; + width: 100%; + height:100%; +} + +/************************************************************************************************/ +/* Request & Response Headers */ + +.netHeadersViewSource { + color: #bdbdbd; + margin-left: 200px; + font-weight: normal; +} + +.netHeadersViewSource:hover { + color: blue; + cursor: pointer; +} + +/************************************************************************************************/ + +.netActivationRow, +.netPageSeparatorRow { + background: rgb(229, 229, 229) !important; + font-weight: normal; + color: black; +} + +.netActivationLabel { + background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px; + padding-left: 22px; +} + +/************************************************************************************************/ + +.netPageSeparatorRow { + height: 5px !important; +} + +.netPageSeparatorLabel { + padding-left: 22px; + height: 5px !important; +} + +.netPageRow { + background-color: rgb(255, 255, 255); +} + +.netPageRow:hover { + background: #EFEFEF; +} + +.netPageLabel { + padding: 1px 0 2px 18px !important; + font-weight: bold; +} + +/************************************************************************************************/ + +.netActivationRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 2px; + padding-bottom: 3px; +} +/* +.useA11y .panelNode-net .a11yFocus:focus, +.useA11y .panelNode-net .focusRow:focus { + outline-offset: -2px; + background-color: #FFFFD6 !important; +} + +.useA11y .panelNode-net .netHeaderCell:focus, +.useA11y .panelNode-net :focus .netHeaderCell, +.useA11y .panelNode-net :focus .netReceivingBar, +.useA11y .netSummaryRow :focus .netBar, +.useA11y .netSummaryRow:focus .netBar { + background-color: #FFFFD6; + background-image: none; + border-color: #FFFFD6; +} +/**/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Windows */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/************************************************************************************************/ +/* Twisties */ + +/* IE6 has problems with > operator, and multiple classes */ +/*.twisty, +.logRow-errorMessage > .hasTwisty > .errorTitle, + /* avoid rule not being parsed IE6 */ +.logRow-spy .spyHead .spyTitle, +.logGroup .logGroupLabel, +.hasChildren .memberLabelCell .memberLabel, +.hasHeaders .netHrefLabel { + background-image: url(tree_open.gif); + background-repeat: no-repeat; + background-position: 2px 2px; +} +/* +.logRow-errorMessage > .hasTwisty.opened > .errorTitle, +/* avoid rule not being parsed IE6 */ +.opened .spyHead .spyTitle, +.opened .logGroupLabel, +.opened .memberLabelCell .memberLabel/*, +.nodeBox.highlightOpen > .nodeLabel > .twisty, +.nodeBox.open > .nodeLabel > .twisty, +.netRow.opened > .netCol > .netHrefLabel /* avoid rule not being parsed IE6 */ { + background-image: url(tree_close.gif); +} + +.twisty { + background-position: 2px 0; +} + + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Console */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-console { + overflow-x: hidden; +} + +.objectLink { + text-decoration: none; +} + +.objectLink:hover { + cursor: pointer; + text-decoration: underline; +} + +.logRow { + position: relative; + margin: 0; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; + overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */ +} + +.useA11y .logRow:focus { + border-bottom: 1px solid #000000 !important; + outline: none !important; + background-color: #FFFFAD !important; +} + +.useA11y .logRow:focus a.objectLink-sourceLink { + background-color: #FFFFAD; +} + +.useA11y .a11yFocus:focus, .useA11y .objectBox:focus { + outline: 2px solid #FF9933; + background-color: #FFFFAD; +} + +.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{ + background-color: #888888 !important; +} + +.useA11y .logGroup.opened > .logRow { + border-bottom: 1px solid #ffffff; +} + +.logGroup { + background: url(group.gif) repeat-x #FFFFFF; + padding: 0 !important; + border: none !important; +} + +.logGroupBody { + display: none; + margin-left: 16px; + border-left: 1px solid #D7D7D7; + border-top: 1px solid #D7D7D7; + background: #FFFFFF; +} + +.logGroup > .logRow { + background-color: transparent !important; + font-weight: bold; +} + +.logGroup.opened > .logRow { + border-bottom: none; +} + +.logGroup.opened > .logGroupBody { + display: block; +} + +/*****************************************************************************************/ + +.logRow-command > .objectBox-text { + font-family: Monaco, monospace; + color: #0000FF; + white-space: pre-wrap; +} + +.logRow-info, +.logRow-warn, +.logRow-error, +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-left: 22px; + background-repeat: no-repeat; + background-position: 4px 2px; +} + +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-top: 0; + padding-bottom: 0; +} + +.logRow-info, +.logRow-info .objectLink-sourceLink { + background-color: #FFFFFF; +} + +.logRow-warn, +.logRow-warningMessage, +.logRow-warn .objectLink-sourceLink, +.logRow-warningMessage .objectLink-sourceLink { + background-color: cyan; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage, +.logRow-error .objectLink-sourceLink, +.logRow-errorMessage .objectLink-sourceLink { + background-color: LightYellow; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + color: #FF0000; +} + +.logRow-info { + /*background-image: url(chrome://firebug/skin/infoIcon.png);*/ +} + +.logRow-warn, +.logRow-warningMessage { + /*background-image: url(chrome://firebug/skin/warningIcon.png);*/ +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + /*background-image: url(chrome://firebug/skin/errorIcon.png);*/ +} + +/*****************************************************************************************/ + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-string, +.objectBox-text, +.objectLink-textNode { + white-space: pre-wrap; +} + +.objectBox-number, +.objectLink-styleRule, +.objectLink-element, +.objectLink-textNode { + color: #000088; +} + +.objectBox-string { + color: #FF0000; +} + +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + color: DarkGreen; +} + +.objectBox-null, +.objectBox-undefined { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-exception { + padding: 0 2px 0 18px; + /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/ + color: red; +} + +.objectLink-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ + +.errorTitle { + margin-top: 0px; + margin-bottom: 1px; + padding-top: 2px; + padding-bottom: 2px; +} + +.errorTrace { + margin-left: 17px; +} + +.errorSourceBox { + margin: 2px 0; +} + +.errorSource-none { + display: none; +} + +.errorSource-syntax > .errorBreak { + visibility: hidden; +} + +.errorSource { + cursor: pointer; + font-family: Monaco, monospace; + color: DarkGreen; +} + +.errorSource:hover { + text-decoration: underline; +} + +.errorBreak { + cursor: pointer; + display: none; + margin: 0 6px 0 0; + width: 13px; + height: 14px; + vertical-align: bottom; + /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/ + opacity: 0.1; +} + +.hasBreakSwitch .errorBreak { + display: inline; +} + +.breakForError .errorBreak { + opacity: 1; +} + +.assertDescription { + margin: 0; +} + +/************************************************************************************************/ + +.logRow-profile > .logRow > .objectBox-text { + font-family: Lucida Grande, Tahoma, sans-serif; + color: #000000; +} + +.logRow-profile > .logRow > .objectBox-text:last-child { + color: #555555; + font-style: italic; +} + +.logRow-profile.opened > .logRow { + padding-bottom: 4px; +} + +.profilerRunning > .logRow { + /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/ + padding-left: 22px !important; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.profileSizer { + width:100%; + overflow-x:auto; + overflow-y: scroll; +} + +.profileTable { + border-bottom: 1px solid #D7D7D7; + padding: 0 0 4px 0; +} + +.profileTable tr[odd="1"] { + background-color: #F5F5F5; + vertical-align:middle; +} + +.profileTable a { + vertical-align:middle; +} + +.profileTable td { + padding: 1px 4px 0 4px; +} + +.headerCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/ +} + +.headerCellBox { + padding: 2px 4px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.headerCell:hover:active { + /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/ +} + +.headerSorted { + /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/ +} + +.headerSorted > .headerCellBox { + border-right-color: #6B7C93; + /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/ +} + +.headerSorted.sortedAscending > .headerCellBox { + /*background-image: url(chrome://firebug/skin/arrowUp.png);*/ +} + +.headerSorted:hover:active { + /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/ +} + +.linkCell { + text-align: right; +} + +.linkCell > .objectLink-sourceLink { + position: static; +} + +/*****************************************************************************************/ + +.logRow-stackTrace { + padding-top: 0; + background: #f8f8f8; +} + +.logRow-stackTrace > .objectBox-stackFrame { + position: relative; + padding-top: 2px; +} + +/************************************************************************************************/ + +.objectLink-object { + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: DarkGreen; + white-space: pre-wrap; +} + +.objectPropValue { + font-weight: normal; + font-style: italic; + color: #555555; +} + +/************************************************************************************************/ + +.selectorTag, +.selectorId, +.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +.selectorHidden > .selectorTag { + color: #5F82D9; +} + +.selectorHidden > .selectorId { + color: #888888; +} + +.selectorHidden > .selectorClass { + color: #D86060; +} + +.selectorValue { + font-family: Lucida Grande, sans-serif; + font-style: italic; + color: #555555; +} + +/*****************************************************************************************/ + +.panelNode.searching .logRow { + display: none; +} + +.logRow.matched { + display: block !important; +} + +.logRow.matching { + position: absolute; + left: -1000px; + top: -1000px; + max-width: 0; + max-height: 0; + overflow: hidden; +} + +/*****************************************************************************************/ + +.arrayLeftBracket, +.arrayRightBracket, +.arrayComma { + font-family: Monaco, monospace; +} + +.arrayLeftBracket, +.arrayRightBracket { + font-weight: bold; +} + +.arrayLeftBracket { + margin-right: 4px; +} + +.arrayRightBracket { + margin-left: 4px; +} + +/*****************************************************************************************/ + +.logRow-dir { + padding: 0; +} + +/************************************************************************************************/ + +/* +.logRow-errorMessage > .hasTwisty > .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup > .logRow +*/ +.logRow-errorMessage .hasTwisty .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup .logRow { + cursor: pointer; + padding-left: 18px; + background-repeat: no-repeat; + background-position: 3px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle { + background-position: 2px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle:hover, +.logRow-spy .spyHead .spyTitle:hover, +.logGroup > .logRow:hover { + text-decoration: underline; +} + +/*****************************************************************************************/ + +.logRow-spy { + padding: 0 !important; +} + +.logRow-spy, +.logRow-spy .objectLink-sourceLink { + background: url(group.gif) repeat-x #FFFFFF; + padding-right: 4px; + right: 0; +} + +.logRow-spy.opened { + padding-bottom: 4px; + border-bottom: none; +} + +.spyTitle { + color: #000000; + font-weight: bold; + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 100; + padding-left: 18px; +} + +.spyCol { + padding: 0; + white-space: nowrap; + height: 16px; +} + +.spyTitleCol:hover > .objectLink-sourceLink, +.spyTitleCol:hover > .spyTime, +.spyTitleCol:hover > .spyStatus, +.spyTitleCol:hover > .spyTitle { + display: none; +} + +.spyFullTitle { + display: none; + -moz-user-select: none; + max-width: 100%; + background-color: Transparent; +} + +.spyTitleCol:hover > .spyFullTitle { + display: block; +} + +.spyStatus { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.spyTime { + margin-left:4px; + margin-right:4px; + color: rgb(128, 128, 128); +} + +.spyIcon { + margin-right: 4px; + margin-left: 4px; + width: 16px; + height: 16px; + vertical-align: middle; + background: transparent no-repeat 0 0; + display: none; +} + +.loading .spyHead .spyRow .spyIcon { + background-image: url(loading_16.gif); + display: block; +} + +.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon { + width: 0; + margin: 0; +} + +.logRow-spy.error .spyHead .spyRow .spyIcon { + background-image: url(errorIcon-sm.png); + display: block; + background-position: 2px 2px; +} + +.logRow-spy .spyHead .netInfoBody { + display: none; +} + +.logRow-spy.opened .spyHead .netInfoBody { + margin-top: 10px; + display: block; +} + +.logRow-spy.error .spyTitle, +.logRow-spy.error .spyStatus, +.logRow-spy.error .spyTime { + color: red; +} + +.logRow-spy.loading .spyResponseText { + font-style: italic; + color: #888888; +} + +/************************************************************************************************/ + +.caption { + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #444444; +} + +.warning { + padding: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #888888; +} + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* DOM */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-dom { + overflow-x: hidden !important; +} + +.domTable { + font-size: 1em; + width: 100%; + table-layout: fixed; + background: #fff; +} + +.domTableIE { + width: auto; +} + +.memberLabelCell { + padding: 2px 0 2px 0; + vertical-align: top; +} + +.memberValueCell { + padding: 1px 0 1px 5px; + display: block; + overflow: hidden; +} + +.memberLabel { + display: block; + cursor: default; + -moz-user-select: none; + overflow: hidden; + /*position: absolute;*/ + padding-left: 18px; + /*max-width: 30%;*/ + /*white-space: nowrap;*/ + background-color: #FFFFFF; + text-decoration: none; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.memberRow.hasChildren .memberLabelCell .memberLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.userLabel { + color: #000000; + font-weight: bold; +} + +.userClassLabel { + color: #E90000; + font-weight: bold; +} + +.userFunctionLabel { + color: #025E2A; + font-weight: bold; +} + +.domLabel { + color: #000000; +} + +.domFunctionLabel { + color: #025E2A; +} + +.ordinalLabel { + color: SlateBlue; + font-weight: bold; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +.scopesRow { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 5px solid #BEBEBE; + color: #666666; +} +.scopesLabel { + background-color: LightYellow; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchEditCell { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 1px solid #BEBEBE; + color: #666666; +} + +.editor-watchNewRow, +.editor-memberRow { + font-family: Monaco, monospace !important; +} + +.editor-memberRow { + padding: 1px 0 !important; +} + +.editor-watchRow { + padding-bottom: 0 !important; +} + +.watchRow > .memberLabelCell { + font-family: Monaco, monospace; + padding-top: 1px; + padding-bottom: 1px; +} + +.watchRow > .memberLabelCell > .memberLabel { + background-color: transparent; +} + +.watchRow > .memberValueCell { + padding-top: 2px; + padding-bottom: 2px; +} + +.watchRow > .memberLabelCell, +.watchRow > .memberValueCell { + background-color: #F5F5F5; + border-bottom: 1px solid #BEBEBE; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchToolbox { + z-index: 2147483647; + position: absolute; + right: 0; + padding: 1px 2px; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* FROM ORIGINAL FIREBUG */ + + + + +/************************************************************************************************ + CSS Not organized +*************************************************************************************************/ +#fbConsole { + overflow-x: hidden !important; +} + +#fbCSS { + font: 1em Monaco, monospace; + padding: 0 7px; +} + +#fbstylesheetButtons select, #fbScriptButtons select { + font: 11px Lucida Grande, Tahoma, sans-serif; + margin-top: 1px; + padding-left: 3px; + background: #fafafa; + border: 1px inset #fff; + width: 220px; + outline: none; +} + +.Selector { margin-top:10px } +.CSSItem {margin-left: 4% } +.CSSText { padding-left:20px; } +.CSSProperty { color:#005500; } +.CSSValue { padding-left:5px; color:#000088; } + + +/************************************************************************************************ + Not organized +*************************************************************************************************/ + +#fbHTMLStatusBar { + display: inline; +} + +.fbToolbarButtons { + display: none; +} + +.fbStatusSeparator{ + display: block; + float: left; + padding-top: 4px; +} + +#fbStatusBarBox { + display: none; +} + +#fbToolbarContent { + display: block; + position: absolute; + _position: absolute; + top: 0; + padding-top: 6px; + height: 23px; + clip: rect(0, 2048px, 27px, 0); +} + +.fbTabMenuTarget { + display: none !important; + float: left; + width: 10px; + height: 10px; + margin-top: 6px; + background: url(tabMenuTarget.png); +} + +.fbTabMenuTarget:hover { + background: url(tabMenuTargetHover.png); +} + +.fbShadow { + float: left; + background: url(shadowAlpha.png) no-repeat bottom right !important; + background: url(shadow2.gif) no-repeat bottom right; + margin: 10px 0 0 10px !important; + margin: 10px 0 0 5px; +} + +.fbShadowContent { + display: block; + position: relative; + background-color: #fff; + border: 1px solid #a9a9a9; + top: -6px; + left: -6px; +} + +.fbMenu { + display: none; + position: absolute; + font-size: 11px; + z-index: 2147483647; +} + +.fbMenuContent { + padding: 2px; +} + +.fbMenuSeparator { + display: block; + position: relative; + padding: 1px 18px 0; + text-decoration: none; + color: #000; + cursor: default; + background: #ACA899; + margin: 4px 0; +} + +.fbMenuOption +{ + display: block; + position: relative; + padding: 2px 18px; + text-decoration: none; + color: #000; + cursor: default; +} + +.fbMenuOption:hover +{ + color: #fff; + background: #316AC5; +} + +.fbMenuGroup { + background: transparent url(tabMenuPin.png) no-repeat right 0; +} + +.fbMenuGroup:hover { + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuGroupSelected { + color: #fff; + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuChecked { + background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0; +} + +.fbMenuChecked:hover { + background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px; +} + +.fbMenuRadioSelected { + background: transparent url(tabMenuRadio.png) no-repeat 4px 0; +} + +.fbMenuRadioSelected:hover { + background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px; +} + +.fbMenuShortcut { + padding-right: 85px; +} + +.fbMenuShortcutKey { + position: absolute; + right: 0; + top: 2px; + width: 77px; +} + +#fbFirebugMenu { + top: 22px; + left: 0; +} + +.fbMenuDisabled { + color: #ACA899 !important; +} + +#fbFirebugSettingsMenu { + left: 245px; + top: 99px; +} + +#fbConsoleMenu { + top: 42px; + left: 48px; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; + float: left; + height: 20px; + width: 20px; + color: #000; + margin-right: 2px; + text-decoration: none; + cursor: default; +} + +.fbIconButton:hover { + position: relative; + top: -1px; + left: -1px; + margin-right: 0; + _margin-right: 1px; + color: #333; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbIconPressed { + position: relative; + margin-right: 0; + _margin-right: 1px; + top: 0 !important; + left: 0 !important; + height: 19px; + color: #333 !important; + border: 1px solid #bbb !important; + border-bottom: 1px solid #cfcfcf !important; + border-right: 1px solid #ddd !important; +} + + + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +.fbBody { + margin: 0; + padding: 0; + overflow: hidden; + + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px !important; + background: #fff url(search.gif) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat !important; + background: url(errorIcon.gif) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + position: absolute; + _position: static; + top: 0; + left: 0; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; + overflow: hidden; +} + +#fbTop { + height: 50px; +} + +#fbToolbar { + background: url(sprite.png) #d4d0c8 0 0; + height: 28px; + font-size: 11px; +} + +#fbPanelBarBox { + background: url(sprite.png) #c5c1ba 0 -28px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 0 5px 0; +} + +#fbToolbarIcon a { + background: url(sprite.png) 0 -135px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} +/* +#fbStatusBarBox a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 5px; + margin: 0 0 0 1px; + cursor: default; +} + +#fbStatusBarBox a:hover { + color: #333; + padding: 3px 4px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} +/**/ + +.fbButton { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 6px 4px 7px; + cursor: default; +} + +.fbButton:hover { + color: #333; + padding: 3px 5px 3px 6px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbBtnPressed { + background: #ECEBE3; + padding: 3px 4px 2px 6px !important; + margin: 1px 0 0 1px !important; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +#fbStatusBarBox { + top: 4px; + cursor: default; +} + +.fbToolbarSeparator { + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #d4d0c8 #fff #d4d0c8 #777; + height: 7px; + margin: 6px 3px; + float: left; +} + +.fbBtnSelected { + font-weight: bold; +} + +.fbStatusBar { + color: #aca899; +} + +.fbStatusBar a { + text-decoration: none; + color: black; +} + +.fbStatusBar a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + width: 50px; + padding: 8px 0 4px 5px; + z-index: 6; + background: url(sprite.png) #D4D0C8 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 1024px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #c5c1ba 0 -28px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #c5c1ba 0 -28px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 23px; + padding-left: 4px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 1em; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + margin-left: 6px; + background: #fff; +} + +#fbLargeCommandLine { + display: none; + position: absolute; + z-index: 9; + top: 27px; + right: 0; + width: 294px; + height: 201px; + border-width: 0; + margin: 0; + padding: 2px 0 0 2px; + resize: none; + outline: none; + font-size: 11px; + overflow: auto; + border-top: 1px solid #B9B7AF; + _right: -1px; + _border-left: 1px solid #fff; +} + +#fbLargeCommandButtons { + display: none; + background: #D4D0C8; + bottom: 0; + right: 0; + width: 294px; + height: 21px; + padding-top: 1px; + position: fixed; + border-top: 1px solid #ACA899; + z-index: 9; +} + +#fbSmallCommandLineIcon { + background: url(down.png) no-repeat; + position: absolute; + right: 2px; + bottom: 3px; + + z-index: 99; +} + +#fbSmallCommandLineIcon:hover { + background: url(downHover.png) no-repeat; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: fixed; + _position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 6px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; + outline: none; +} + +#fbLargeCommandLineIcon { + background: url(up.png) no-repeat; + position: absolute; + right: 1px; + bottom: 1px; + z-index: 10; +} + +#fbLargeCommandLineIcon:hover { + background: url(upHover.png) no-repeat; +} + +div.fbFitHeight { + overflow: auto; + position: relative; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +.fbSmallButton { + overflow: hidden; + width: 16px; + height: 16px; + display: block; + text-decoration: none; + cursor: default; +} + +#fbWindowButtons .fbSmallButton { + float: right; +} + +#fbWindow_btClose { + background: url(min.png); +} + +#fbWindow_btClose:hover { + background: url(minHover.png); +} + +#fbWindow_btDetach { + background: url(detach.png); +} + +#fbWindow_btDetach:hover { + background: url(detachHover.png); +} + +#fbWindow_btDeactivate { + background: url(off.png); +} + +#fbWindow_btDeactivate:hover { + background: url(offHover.png); +} + + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + /*display: block; TODO: safe to remove this? */ + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #d4d0c8 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: fixed; + _position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #d4d0c8; + color: #000; + border: 1px solid #777; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 9; + position: absolute; + height: 100%; + top: 28px; +} + +/************************************************************************************************/ +div.lineNo { + font: 1em Monaco, monospace; + position: relative; + float: left; + top: 0; + left: 0; + margin: 0 5px 0 0; + padding: 0 5px 0 10px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +.sourceBox { + position: absolute; +} + +.sourceCode { + font: 1em Monaco, monospace; + overflow: hidden; + white-space: pre; + display: inline; +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* IE6 need this hack */ +* html .selectedElement { + position: relative; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 1em; +} + +/* TODO: remove this? */ +/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to +position. if so, override it at chrome.js initialization when creating the div */ +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + zbackground-color: #FFFFFF; +} +/**/ + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + + /* TODO: xxxpedro make long strings break line */ + /*white-space: pre; */ +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warn { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png) !important; + background-image: url(infoIcon.gif); +} + +.logRow-warn { + background-color: cyan; + background-image: url(warningIcon.png) !important; + background-image: url(warningIcon.gif); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png) !important; + background-image: url(errorIcon.gif); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +/* +//TODO: remove this when console2 is finished +*/ +/* +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +}/**/ + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.html new file mode 100755 index 0000000..4432a32 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.html @@ -0,0 +1,213 @@ + + + + +Firebug Lite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + +
      +   +   +   +
      + + +
      +
      + + + +   + + + + + + + + + Inspect + + + + + Clear + + + + + + + + + + + + + +
      + +
      + + + + + +
       
      + +
      +
      +
      +
      +
      +
      + + +
       
      + + +
      + + +
      +
      +
      + +
      + + + + + +
      + Run + Clear + + +
      + +
      +
      +
      >>>
      + + +
      +
      + + + + 2 errors + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.png new file mode 100755 index 0000000..123545a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/firebug.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/group.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/group.gif new file mode 100755 index 0000000..8db97c2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/group.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/infoIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/infoIcon.gif new file mode 100755 index 0000000..0618e20 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/infoIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/infoIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/infoIcon.png new file mode 100755 index 0000000..da1e533 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/infoIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/loading_16.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/loading_16.gif new file mode 100755 index 0000000..085ccae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/loading_16.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/min.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/min.png new file mode 100755 index 0000000..1034d66 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/min.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/minHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/minHover.png new file mode 100755 index 0000000..b0d1e1a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/minHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/off.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/off.png new file mode 100755 index 0000000..b70b1d2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/off.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/offHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/offHover.png new file mode 100755 index 0000000..f3670f1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/offHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/pixel_transparent.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/pixel_transparent.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/pixel_transparent.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/roundCorner.svg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/roundCorner.svg new file mode 100755 index 0000000..be0291f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/roundCorner.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/search.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/search.gif new file mode 100755 index 0000000..2a62098 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/search.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/search.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/search.png new file mode 100755 index 0000000..fba33b8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/search.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadow.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadow.gif new file mode 100755 index 0000000..af7f537 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadow.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadow2.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadow2.gif new file mode 100755 index 0000000..099cbf3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadow2.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadowAlpha.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadowAlpha.png new file mode 100755 index 0000000..a2561df Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/shadowAlpha.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/sprite.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/sprite.png new file mode 100755 index 0000000..3fe97bb Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/sprite.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverLeft.png new file mode 100755 index 0000000..5852d8d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverMid.png new file mode 100755 index 0000000..e7c9ba7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverRight.png new file mode 100755 index 0000000..3c62c98 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabHoverRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabLeft.png new file mode 100755 index 0000000..3368de7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuCheckbox.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuCheckbox.png new file mode 100755 index 0000000..4726e62 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuCheckbox.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuPin.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuPin.png new file mode 100755 index 0000000..eb4b11e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuPin.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuRadio.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuRadio.png new file mode 100755 index 0000000..55b982d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuRadio.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuTarget.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuTarget.png new file mode 100755 index 0000000..957bd9f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuTarget.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuTargetHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuTargetHover.png new file mode 100755 index 0000000..200a370 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMenuTargetHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMid.png new file mode 100755 index 0000000..b2cfeac Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabRight.png new file mode 100755 index 0000000..8470a95 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tabRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorBorders.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorBorders.gif new file mode 100755 index 0000000..0ee5497 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorBorders.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorBorders.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorBorders.png new file mode 100755 index 0000000..21682c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorBorders.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorCorners.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorCorners.gif new file mode 100755 index 0000000..04f8421 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorCorners.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorCorners.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorCorners.png new file mode 100755 index 0000000..a0f839d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/textEditorCorners.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/titlebarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/titlebarMid.png new file mode 100755 index 0000000..e9a7416 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/titlebarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/toolbarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/toolbarMid.png new file mode 100755 index 0000000..a1257f5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/toolbarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tree_close.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tree_close.gif new file mode 100755 index 0000000..e26728a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tree_close.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tree_open.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tree_open.gif new file mode 100755 index 0000000..edf662f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/tree_open.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/twistyClosed.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/twistyClosed.png new file mode 100755 index 0000000..f80319b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/twistyClosed.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/twistyOpen.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/twistyOpen.png new file mode 100755 index 0000000..8680124 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/twistyOpen.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/up.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/up.png new file mode 100755 index 0000000..2174d03 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/up.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/upActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/upActive.png new file mode 100755 index 0000000..236cf67 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/upActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/upHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/upHover.png new file mode 100755 index 0000000..cd81317 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/upHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/warningIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/warningIcon.gif new file mode 100755 index 0000000..8497278 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/warningIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/warningIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/warningIcon.png new file mode 100755 index 0000000..de51084 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/classic/warningIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/blank.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/blank.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/blank.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/buttonBg.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/buttonBg.png new file mode 100755 index 0000000..f367b42 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/buttonBg.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/buttonBgHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/buttonBgHover.png new file mode 100755 index 0000000..cd37a0d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/buttonBgHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/close.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/close.png new file mode 100755 index 0000000..ada59d8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/close.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/closeHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/closeHover.png new file mode 100755 index 0000000..be0145d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/closeHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/detach.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/detach.png new file mode 100755 index 0000000..25d97e0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/detach.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/detachHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/detachHover.png new file mode 100755 index 0000000..edb8125 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/detachHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disable.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disable.gif new file mode 100755 index 0000000..dd9eb0e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disable.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disable.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disable.png new file mode 100755 index 0000000..c28bcdf Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disable.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disableHover.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disableHover.gif new file mode 100755 index 0000000..70565a8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disableHover.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disableHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disableHover.png new file mode 100755 index 0000000..26fe375 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/disableHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/down.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/down.png new file mode 100755 index 0000000..acbbd30 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/down.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/downActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/downActive.png new file mode 100755 index 0000000..f4312b2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/downActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/downHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/downHover.png new file mode 100755 index 0000000..8144e63 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/downHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon-sm.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon-sm.png new file mode 100755 index 0000000..0c377e3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon-sm.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon.gif new file mode 100755 index 0000000..8ee8116 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon.png new file mode 100755 index 0000000..2d75261 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/errorIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.css new file mode 100755 index 0000000..7af18e6 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.css @@ -0,0 +1,3063 @@ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Loose */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* +.netInfoResponseHeadersTitle, netInfoResponseHeadersBody { + display: none; +} +/**/ + +/* IE6 need a separated rule, otherwise it will not recognize it */ +.collapsed { + display: none; +} + +[collapsed="true"] { + display: none; +} + +#fbCSS { + padding: 0 !important; +} + +.cssPropDisable { + float: left; + display: block; + width: 2em; + cursor: default; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* panelBase */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/************************************************************************************************/ + +.infoTip { + z-index: 2147483647; + position: fixed; + padding: 2px 3px; + border: 1px solid #CBE087; + background: LightYellow; + font-family: Monaco, monospace; + color: #000000; + display: none; + white-space: nowrap; + pointer-events: none; +} + +.infoTip[active="true"] { + display: block; +} + +.infoTipLoading { + width: 16px; + height: 16px; + background: url(chrome://firebug/skin/loading_16.gif) no-repeat; +} + +.infoTipImageBox { + min-width: 100px; + text-align: center; +} + +.infoTipCaption { + font: message-box; +} + +.infoTipLoading > .infoTipImage, +.infoTipLoading > .infoTipCaption { + display: none; +} + +/************************************************************************************************/ + +h1.groupHeader { + padding: 2px 4px; + margin: 0 0 4px 0; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + background: #eee url(group.gif) repeat-x; + font-size: 11px; + font-weight: bold; + _position: relative; +} + +/************************************************************************************************/ + +.inlineEditor, +.fixedWidthEditor { + z-index: 2147483647; + position: absolute; + display: none; +} + +.inlineEditor { + margin-left: -6px; + margin-top: -3px; + /* + _margin-left: -7px; + _margin-top: -5px; + /**/ +} + +.textEditorInner, +.fixedWidthEditor { + margin: 0 0 0 0 !important; + padding: 0; + border: none !important; + font: inherit; + text-decoration: inherit; + background-color: #FFFFFF; +} + +.fixedWidthEditor { + border-top: 1px solid #888888 !important; + border-bottom: 1px solid #888888 !important; +} + +.textEditorInner { + position: relative; + top: -7px; + left: -5px; + + outline: none; + resize: none; + + /* + _border: 1px solid #999 !important; + _padding: 1px !important; + _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040"); + /**/ +} + +.textEditorInner1 { + padding-left: 11px; + background: url(textEditorBorders.png) repeat-y; + _background: url(textEditorBorders.gif) repeat-y; + _overflow: hidden; +} + +.textEditorInner2 { + position: relative; + padding-right: 2px; + background: url(textEditorBorders.png) repeat-y 100% 0; + _background: url(textEditorBorders.gif) repeat-y 100% 0; + _position: fixed; +} + +.textEditorTop1 { + background: url(textEditorCorners.png) no-repeat 100% 0; + margin-left: 11px; + height: 10px; + _background: url(textEditorCorners.gif) no-repeat 100% 0; + _overflow: hidden; +} + +.textEditorTop2 { + position: relative; + left: -11px; + width: 11px; + height: 10px; + background: url(textEditorCorners.png) no-repeat; + _background: url(textEditorCorners.gif) no-repeat; +} + +.textEditorBottom1 { + position: relative; + background: url(textEditorCorners.png) no-repeat 100% 100%; + margin-left: 11px; + height: 12px; + _background: url(textEditorCorners.gif) no-repeat 100% 100%; +} + +.textEditorBottom2 { + position: relative; + left: -11px; + width: 11px; + height: 12px; + background: url(textEditorCorners.png) no-repeat 0 100%; + _background: url(textEditorCorners.gif) no-repeat 0 100%; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* CSS */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-css { + overflow-x: hidden; +} + +.cssSheet > .insertBefore { + height: 1.5em; +} + +.cssRule { + position: relative; + margin: 0; + padding: 1em 0 0 6px; + font-family: Monaco, monospace; + color: #000000; +} + +.cssRule:first-child { + padding-top: 6px; +} + +.cssElementRuleContainer { + position: relative; +} + +.cssHead { + padding-right: 150px; +} + +.cssProp { + /*padding-left: 2em;*/ +} + +.cssPropName { + color: DarkGreen; +} + +.cssPropValue { + margin-left: 8px; + color: DarkBlue; +} + +.cssOverridden span { + text-decoration: line-through; +} + +.cssInheritedRule { +} + +.cssInheritLabel { + margin-right: 0.5em; + font-weight: bold; +} + +.cssRule .objectLink-sourceLink { + top: 0; +} + +.cssProp.editGroup:hover { + background: url(disable.png) no-repeat 2px 1px; + _background: url(disable.gif) no-repeat 2px 1px; +} + +.cssProp.editGroup.editing { + background: none; +} + +.cssProp.disabledStyle { + background: url(disableHover.png) no-repeat 2px 1px; + _background: url(disableHover.gif) no-repeat 2px 1px; + opacity: 1; + color: #CCCCCC; +} + +.disabledStyle .cssPropName, +.disabledStyle .cssPropValue { + color: #CCCCCC; +} + +.cssPropValue.editing + .cssSemi, +.inlineExpander + .cssSemi { + display: none; +} + +.cssPropValue.editing { + white-space: nowrap; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.stylePropName { + font-weight: bold; + padding: 0 4px 4px 4px; + width: 50%; +} + +.stylePropValue { + width: 50%; +} +/* +.useA11y .a11yCSSView .focusRow:focus { + outline: none; + background-color: transparent + } + + .useA11y .a11yCSSView .focusRow:focus .cssSelector, + .useA11y .a11yCSSView .focusRow:focus .cssPropName, + .useA11y .a11yCSSView .focusRow:focus .cssPropValue, + .useA11y .a11yCSSView .computedStyleRow:focus, + .useA11y .a11yCSSView .groupHeader:focus { + outline: 2px solid #FF9933; + outline-offset: -2px; + background-color: #FFFFD6; + } + + .useA11y .a11yCSSView .groupHeader:focus { + outline-offset: -2px; + } +/**/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Net */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-net { + overflow-x: hidden; +} + +.netTable { + width: 100%; +} + +/************************************************************************************************/ + +.hideCategory-undefined .category-undefined, +.hideCategory-html .category-html, +.hideCategory-css .category-css, +.hideCategory-js .category-js, +.hideCategory-image .category-image, +.hideCategory-xhr .category-xhr, +.hideCategory-flash .category-flash, +.hideCategory-txt .category-txt, +.hideCategory-bin .category-bin { + display: none; +} + +/************************************************************************************************/ + +.netHeadRow { + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netHeadCol { + border-bottom: 1px solid #CCCCCC; + padding: 2px 4px 2px 18px; + font-weight: bold; +} + +.netHeadLabel { + white-space: nowrap; + overflow: hidden; +} + +/************************************************************************************************/ +/* Header for Net panel table */ + +.netHeaderRow { + height: 16px; +} + +.netHeaderCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x; + white-space: nowrap; +} + +.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox { + padding: 2px 14px 2px 18px; +} + +.netHeaderCellBox { + padding: 2px 14px 2px 10px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.netHeaderCell:hover:active { + background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x; +} + +.netHeaderSorted { + background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x; +} + +.netHeaderSorted > .netHeaderCellBox { + border-right-color: #6B7C93; + background: url(chrome://firebug/skin/arrowDown.png) no-repeat right; +} + +.netHeaderSorted.sortedAscending > .netHeaderCellBox { + background-image: url(chrome://firebug/skin/arrowUp.png); +} + +.netHeaderSorted:hover:active { + background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x; +} + +/************************************************************************************************/ +/* Breakpoints */ + +.panelNode-net .netRowHeader { + display: block; +} + +.netRowHeader { + cursor: pointer; + display: none; + height: 15px; + margin-right: 0 !important; +} + +/* Display brekpoint disc */ +.netRow .netRowHeader { + background-position: 5px 1px; +} + +.netRow[breakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpoint.png); +} + +.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpointDisabled.png); +} + +.netRow.category-xhr:hover .netRowHeader { + background-color: #F6F6F6; +} + +#netBreakpointBar { + max-width: 38px; +} + +#netHrefCol > .netHeaderCellBox { + border-left: 0px; +} + +.netRow .netRowHeader { + width: 3px; +} + +.netInfoRow .netRowHeader { + display: table-cell; +} + +/************************************************************************************************/ +/* Column visibility */ + +.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"], +.netTable[hiddenCols~=netHrefCol] TD.netHrefCol, +.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"], +.netTable[hiddenCols~=netStatusCol] TD.netStatusCol, +.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"], +.netTable[hiddenCols~=netDomainCol] TD.netDomainCol, +.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"], +.netTable[hiddenCols~=netSizeCol] TD.netSizeCol, +.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"], +.netTable[hiddenCols~=netTimeCol] TD.netTimeCol { + display: none; +} + +/************************************************************************************************/ + +.netRow { + background: LightYellow; +} + +.netRow.loaded { + background: #FFFFFF; +} + +.netRow.loaded:hover { + background: #EFEFEF; +} + +.netCol { + padding: 0; + vertical-align: top; + border-bottom: 1px solid #EFEFEF; + white-space: nowrap; + height: 17px; +} + +.netLabel { + width: 100%; +} + +.netStatusCol { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.responseError > .netStatusCol { + color: red; +} + +.netDomainCol { + padding-left: 5px; +} + +.netSizeCol { + text-align: right; + padding-right: 10px; +} + +.netHrefLabel { + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 10; + position: absolute; + padding-left: 18px; + padding-top: 1px; + max-width: 15%; + font-weight: bold; +} + +.netFullHrefLabel { + display: none; + -moz-user-select: none; + padding-right: 10px; + padding-bottom: 3px; + max-width: 100%; + background: #FFFFFF; + z-index: 200; +} + +.netHrefCol:hover > .netFullHrefLabel { + display: block; +} + +.netRow.loaded:hover .netCol > .netFullHrefLabel { + background-color: #EFEFEF; +} + +.useA11y .a11yShowFullLabel { + display: block; + background-image: none !important; + border: 1px solid #CBE087; + background-color: LightYellow; + font-family: Monaco, monospace; + color: #000000; + font-size: 10px; + z-index: 2147483647; +} + +.netSizeLabel { + padding-left: 6px; +} + +.netStatusLabel, +.netDomainLabel, +.netSizeLabel, +.netBar { + padding: 1px 0 2px 0 !important; +} + +.responseError { + color: red; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.hasHeaders .netHrefLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/************************************************************************************************/ + +.netLoadingIcon { + position: absolute; + border: 0; + margin-left: 14px; + width: 16px; + height: 16px; + background: transparent no-repeat 0 0; + background-image: url(chrome://firebug/skin/loading_16.gif); + display:inline-block; +} + +.loaded .netLoadingIcon { + display: none; +} + +/************************************************************************************************/ + +.netBar, .netSummaryBar { + position: relative; + border-right: 50px solid transparent; +} + +.netResolvingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x; + z-index:60; +} + +.netConnectingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x; + z-index:50; +} + +.netBlockingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x; + z-index:40; +} + +.netSendingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x; + z-index:30; +} + +.netWaitingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x; + z-index:20; + min-width: 1px; +} + +.netReceivingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x; + z-index:10; +} + +.netWindowLoadBar, +.netContentLoadBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 1px; + background-color: red; + z-index: 70; + opacity: 0.5; + display: none; + margin-bottom:-1px; +} + +.netContentLoadBar { + background-color: Blue; +} + +.netTimeLabel { + -moz-box-sizing: padding-box; + position: absolute; + top: 1px; + left: 100%; + padding-left: 6px; + color: #444444; + min-width: 16px; +} + +/* + * Timing info tip is reusing net timeline styles to display the same + * colors for individual request phases. Notice that the info tip must + * respect also loaded and fromCache styles that also modify the + * actual color. These are used both on the same element in case + * of the tooltip. + */ +.loaded .netReceivingBar, +.loaded.netReceivingBar { + background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x; + border-color: #B6B6B6; +} + +.fromCache .netReceivingBar, +.fromCache.netReceivingBar { + background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x; + border-color: #D6D6D6; +} + +.netSummaryRow .netTimeLabel, +.loaded .netTimeLabel { + background: transparent; +} + +/************************************************************************************************/ +/* Time Info tip */ + +.timeInfoTip { + width: 150px; + height: 40px +} + +.timeInfoTipBar, +.timeInfoTipEventBar { + position: relative; + display: block; + margin: 0; + opacity: 1; + height: 15px; + width: 4px; +} + +.timeInfoTipEventBar { + width: 1px !important; +} + +.timeInfoTipCell.startTime { + padding-right: 8px; +} + +.timeInfoTipCell.elapsedTime { + text-align: right; + padding-right: 8px; +} + +/************************************************************************************************/ +/* Size Info tip */ + +.sizeInfoLabelCol { + font-weight: bold; + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; +} + +.sizeInfoSizeCol { + font-weight: bold; +} + +.sizeInfoDetailCol { + color: gray; + text-align: right; +} + +.sizeInfoDescCol { + font-style: italic; +} + +/************************************************************************************************/ +/* Summary */ + +.netSummaryRow .netReceivingBar { + background: #BBBBBB; + border: none; +} + +.netSummaryLabel { + color: #222222; +} + +.netSummaryRow { + background: #BBBBBB !important; + font-weight: bold; +} + +.netSummaryRow .netBar { + border-right-color: #BBBBBB; +} + +.netSummaryRow > .netCol { + border-top: 1px solid #999999; + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 1px; + padding-bottom: 2px; +} + +.netSummaryRow > .netHrefCol:hover { + background: transparent !important; +} + +.netCountLabel { + padding-left: 18px; +} + +.netTotalSizeCol { + text-align: right; + padding-right: 10px; +} + +.netTotalTimeCol { + text-align: right; +} + +.netCacheSizeLabel { + position: absolute; + z-index: 1000; + left: 0; + top: 0; +} + +/************************************************************************************************/ + +.netLimitRow { + background: rgb(255, 255, 225) !important; + font-weight:normal; + color: black; + font-weight:normal; +} + +.netLimitLabel { + padding-left: 18px; +} + +.netLimitRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + vertical-align: middle !important; + padding-top: 2px; + padding-bottom: 2px; +} + +.netLimitButton { + font-size: 11px; + padding-top: 1px; + padding-bottom: 1px; +} + +/************************************************************************************************/ + +.netInfoCol { + border-top: 1px solid #EEEEEE; + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netInfoBody { + margin: 10px 0 4px 10px; +} + +.netInfoTabs { + position: relative; + padding-left: 17px; +} + +.netInfoTab { + position: relative; + top: -3px; + margin-top: 10px; + padding: 4px 6px; + border: 1px solid transparent; + border-bottom: none; + _border: none; + font-weight: bold; + color: #565656; + cursor: pointer; +} + +/*.netInfoTab:hover { + cursor: pointer; +}*/ + +/* replaced by .netInfoTabSelected for IE6 support +.netInfoTab[selected="true"] { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} +/**/ +.netInfoTabSelected { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} + +.logRow-netInfo.error .netInfoTitle { + color: red; +} + +.logRow-netInfo.loading .netInfoResponseText { + font-style: italic; + color: #888888; +} + +.loading .netInfoResponseHeadersTitle { + display: none; +} + +.netInfoResponseSizeLimit { + font-family: Lucida Grande, Tahoma, sans-serif; + padding-top: 10px; + font-size: 11px; +} + +.netInfoText { + display: none; + margin: 0; + border: 1px solid #D7D7D7; + border-right: none; + padding: 8px; + background-color: #FFFFFF; + font-family: Monaco, monospace; + /* white-space: pre; */ + /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */ +} + +/* replaced by .netInfoTextSelected for IE6 support +.netInfoText[selected="true"] { + display: block; +} +/**/ +.netInfoTextSelected { + display: block; +} + +.netInfoParamName { + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + vertical-align: top; + text-align: right; + white-space: nowrap; +} + +.netInfoPostText .netInfoParamName { + width: 1px; /* Google Chrome need this otherwise the first column of + the post variables table will be larger than expected */ +} + +.netInfoParamValue { + width: 100%; +} + +.netInfoHeadersText, +.netInfoPostText, +.netInfoPutText { + padding-top: 0; +} + +.netInfoHeadersGroup, +.netInfoPostParams, +.netInfoPostSource { + margin-bottom: 4px; + border-bottom: 1px solid #D7D7D7; + padding-top: 8px; + padding-bottom: 2px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #565656; +} + +.netInfoPostParamsTable, +.netInfoPostPartsTable, +.netInfoPostJSONTable, +.netInfoPostXMLTable, +.netInfoPostSourceTable { + margin-bottom: 10px; + width: 100%; +} + +.netInfoPostContentType { + color: #bdbdbd; + padding-left: 50px; + font-weight: normal; +} + +.netInfoHtmlPreview { + border: 0; + width: 100%; + height:100%; +} + +/************************************************************************************************/ +/* Request & Response Headers */ + +.netHeadersViewSource { + color: #bdbdbd; + margin-left: 200px; + font-weight: normal; +} + +.netHeadersViewSource:hover { + color: blue; + cursor: pointer; +} + +/************************************************************************************************/ + +.netActivationRow, +.netPageSeparatorRow { + background: rgb(229, 229, 229) !important; + font-weight: normal; + color: black; +} + +.netActivationLabel { + background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px; + padding-left: 22px; +} + +/************************************************************************************************/ + +.netPageSeparatorRow { + height: 5px !important; +} + +.netPageSeparatorLabel { + padding-left: 22px; + height: 5px !important; +} + +.netPageRow { + background-color: rgb(255, 255, 255); +} + +.netPageRow:hover { + background: #EFEFEF; +} + +.netPageLabel { + padding: 1px 0 2px 18px !important; + font-weight: bold; +} + +/************************************************************************************************/ + +.netActivationRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 2px; + padding-bottom: 3px; +} +/* +.useA11y .panelNode-net .a11yFocus:focus, +.useA11y .panelNode-net .focusRow:focus { + outline-offset: -2px; + background-color: #FFFFD6 !important; +} + +.useA11y .panelNode-net .netHeaderCell:focus, +.useA11y .panelNode-net :focus .netHeaderCell, +.useA11y .panelNode-net :focus .netReceivingBar, +.useA11y .netSummaryRow :focus .netBar, +.useA11y .netSummaryRow:focus .netBar { + background-color: #FFFFD6; + background-image: none; + border-color: #FFFFD6; +} +/**/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Windows */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/************************************************************************************************/ +/* Twisties */ + +/* IE6 has problems with > operator, and multiple classes */ +/*.twisty, +.logRow-errorMessage > .hasTwisty > .errorTitle, + /* avoid rule not being parsed IE6 */ +.logRow-spy .spyHead .spyTitle, +.logGroup .logGroupLabel, +.hasChildren .memberLabelCell .memberLabel, +.hasHeaders .netHrefLabel { + background-image: url(tree_open.gif); + background-repeat: no-repeat; + background-position: 2px 2px; +} +/* +.logRow-errorMessage > .hasTwisty.opened > .errorTitle, +/* avoid rule not being parsed IE6 */ +.opened .spyHead .spyTitle, +.opened .logGroupLabel, +.opened .memberLabelCell .memberLabel/*, +.nodeBox.highlightOpen > .nodeLabel > .twisty, +.nodeBox.open > .nodeLabel > .twisty, +.netRow.opened > .netCol > .netHrefLabel /* avoid rule not being parsed IE6 */ { + background-image: url(tree_close.gif); +} + +.twisty { + background-position: 2px 0; +} + + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Console */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-console { + overflow-x: hidden; +} + +.objectLink { + text-decoration: none; +} + +.objectLink:hover { + cursor: pointer; + text-decoration: underline; +} + +.logRow { + position: relative; + margin: 0; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; + overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */ +} + +.useA11y .logRow:focus { + border-bottom: 1px solid #000000 !important; + outline: none !important; + background-color: #FFFFAD !important; +} + +.useA11y .logRow:focus a.objectLink-sourceLink { + background-color: #FFFFAD; +} + +.useA11y .a11yFocus:focus, .useA11y .objectBox:focus { + outline: 2px solid #FF9933; + background-color: #FFFFAD; +} + +.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{ + background-color: #888888 !important; +} + +.useA11y .logGroup.opened > .logRow { + border-bottom: 1px solid #ffffff; +} + +.logGroup { + background: url(group.gif) repeat-x #FFFFFF; + padding: 0 !important; + border: none !important; +} + +.logGroupBody { + display: none; + margin-left: 16px; + border-left: 1px solid #D7D7D7; + border-top: 1px solid #D7D7D7; + background: #FFFFFF; +} + +.logGroup > .logRow { + background-color: transparent !important; + font-weight: bold; +} + +.logGroup.opened > .logRow { + border-bottom: none; +} + +.logGroup.opened > .logGroupBody { + display: block; +} + +/*****************************************************************************************/ + +.logRow-command > .objectBox-text { + font-family: Monaco, monospace; + color: #0000FF; + white-space: pre-wrap; +} + +.logRow-info, +.logRow-warn, +.logRow-error, +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-left: 22px; + background-repeat: no-repeat; + background-position: 4px 2px; +} + +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-top: 0; + padding-bottom: 0; +} + +.logRow-info, +.logRow-info .objectLink-sourceLink { + background-color: #FFFFFF; +} + +.logRow-warn, +.logRow-warningMessage, +.logRow-warn .objectLink-sourceLink, +.logRow-warningMessage .objectLink-sourceLink { + background-color: cyan; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage, +.logRow-error .objectLink-sourceLink, +.logRow-errorMessage .objectLink-sourceLink { + background-color: LightYellow; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + color: #FF0000; +} + +.logRow-info { + /*background-image: url(chrome://firebug/skin/infoIcon.png);*/ +} + +.logRow-warn, +.logRow-warningMessage { + /*background-image: url(chrome://firebug/skin/warningIcon.png);*/ +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + /*background-image: url(chrome://firebug/skin/errorIcon.png);*/ +} + +/*****************************************************************************************/ + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-string, +.objectBox-text, +.objectLink-textNode { + white-space: pre-wrap; +} + +.objectBox-number, +.objectLink-styleRule, +.objectLink-element, +.objectLink-textNode { + color: #000088; +} + +.objectBox-string { + color: #FF0000; +} + +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + color: DarkGreen; +} + +.objectBox-null, +.objectBox-undefined { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-exception { + padding: 0 2px 0 18px; + /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/ + color: red; +} + +.objectLink-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ + +.errorTitle { + margin-top: 0px; + margin-bottom: 1px; + padding-top: 2px; + padding-bottom: 2px; +} + +.errorTrace { + margin-left: 17px; +} + +.errorSourceBox { + margin: 2px 0; +} + +.errorSource-none { + display: none; +} + +.errorSource-syntax > .errorBreak { + visibility: hidden; +} + +.errorSource { + cursor: pointer; + font-family: Monaco, monospace; + color: DarkGreen; +} + +.errorSource:hover { + text-decoration: underline; +} + +.errorBreak { + cursor: pointer; + display: none; + margin: 0 6px 0 0; + width: 13px; + height: 14px; + vertical-align: bottom; + /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/ + opacity: 0.1; +} + +.hasBreakSwitch .errorBreak { + display: inline; +} + +.breakForError .errorBreak { + opacity: 1; +} + +.assertDescription { + margin: 0; +} + +/************************************************************************************************/ + +.logRow-profile > .logRow > .objectBox-text { + font-family: Lucida Grande, Tahoma, sans-serif; + color: #000000; +} + +.logRow-profile > .logRow > .objectBox-text:last-child { + color: #555555; + font-style: italic; +} + +.logRow-profile.opened > .logRow { + padding-bottom: 4px; +} + +.profilerRunning > .logRow { + /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/ + padding-left: 22px !important; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.profileSizer { + width:100%; + overflow-x:auto; + overflow-y: scroll; +} + +.profileTable { + border-bottom: 1px solid #D7D7D7; + padding: 0 0 4px 0; +} + +.profileTable tr[odd="1"] { + background-color: #F5F5F5; + vertical-align:middle; +} + +.profileTable a { + vertical-align:middle; +} + +.profileTable td { + padding: 1px 4px 0 4px; +} + +.headerCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/ +} + +.headerCellBox { + padding: 2px 4px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.headerCell:hover:active { + /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/ +} + +.headerSorted { + /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/ +} + +.headerSorted > .headerCellBox { + border-right-color: #6B7C93; + /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/ +} + +.headerSorted.sortedAscending > .headerCellBox { + /*background-image: url(chrome://firebug/skin/arrowUp.png);*/ +} + +.headerSorted:hover:active { + /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/ +} + +.linkCell { + text-align: right; +} + +.linkCell > .objectLink-sourceLink { + position: static; +} + +/*****************************************************************************************/ + +.logRow-stackTrace { + padding-top: 0; + background: #f8f8f8; +} + +.logRow-stackTrace > .objectBox-stackFrame { + position: relative; + padding-top: 2px; +} + +/************************************************************************************************/ + +.objectLink-object { + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: DarkGreen; + white-space: pre-wrap; +} + +.objectPropValue { + font-weight: normal; + font-style: italic; + color: #555555; +} + +/************************************************************************************************/ + +.selectorTag, +.selectorId, +.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +.selectorHidden > .selectorTag { + color: #5F82D9; +} + +.selectorHidden > .selectorId { + color: #888888; +} + +.selectorHidden > .selectorClass { + color: #D86060; +} + +.selectorValue { + font-family: Lucida Grande, sans-serif; + font-style: italic; + color: #555555; +} + +/*****************************************************************************************/ + +.panelNode.searching .logRow { + display: none; +} + +.logRow.matched { + display: block !important; +} + +.logRow.matching { + position: absolute; + left: -1000px; + top: -1000px; + max-width: 0; + max-height: 0; + overflow: hidden; +} + +/*****************************************************************************************/ + +.arrayLeftBracket, +.arrayRightBracket, +.arrayComma { + font-family: Monaco, monospace; +} + +.arrayLeftBracket, +.arrayRightBracket { + font-weight: bold; +} + +.arrayLeftBracket { + margin-right: 4px; +} + +.arrayRightBracket { + margin-left: 4px; +} + +/*****************************************************************************************/ + +.logRow-dir { + padding: 0; +} + +/************************************************************************************************/ + +/* +.logRow-errorMessage > .hasTwisty > .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup > .logRow +*/ +.logRow-errorMessage .hasTwisty .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup .logRow { + cursor: pointer; + padding-left: 18px; + background-repeat: no-repeat; + background-position: 3px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle { + background-position: 2px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle:hover, +.logRow-spy .spyHead .spyTitle:hover, +.logGroup > .logRow:hover { + text-decoration: underline; +} + +/*****************************************************************************************/ + +.logRow-spy { + padding: 0 !important; +} + +.logRow-spy, +.logRow-spy .objectLink-sourceLink { + background: url(group.gif) repeat-x #FFFFFF; + padding-right: 4px; + right: 0; +} + +.logRow-spy.opened { + padding-bottom: 4px; + border-bottom: none; +} + +.spyTitle { + color: #000000; + font-weight: bold; + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 100; + padding-left: 18px; +} + +.spyCol { + padding: 0; + white-space: nowrap; + height: 16px; +} + +.spyTitleCol:hover > .objectLink-sourceLink, +.spyTitleCol:hover > .spyTime, +.spyTitleCol:hover > .spyStatus, +.spyTitleCol:hover > .spyTitle { + display: none; +} + +.spyFullTitle { + display: none; + -moz-user-select: none; + max-width: 100%; + background-color: Transparent; +} + +.spyTitleCol:hover > .spyFullTitle { + display: block; +} + +.spyStatus { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.spyTime { + margin-left:4px; + margin-right:4px; + color: rgb(128, 128, 128); +} + +.spyIcon { + margin-right: 4px; + margin-left: 4px; + width: 16px; + height: 16px; + vertical-align: middle; + background: transparent no-repeat 0 0; + display: none; +} + +.loading .spyHead .spyRow .spyIcon { + background-image: url(loading_16.gif); + display: block; +} + +.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon { + width: 0; + margin: 0; +} + +.logRow-spy.error .spyHead .spyRow .spyIcon { + background-image: url(errorIcon-sm.png); + display: block; + background-position: 2px 2px; +} + +.logRow-spy .spyHead .netInfoBody { + display: none; +} + +.logRow-spy.opened .spyHead .netInfoBody { + margin-top: 10px; + display: block; +} + +.logRow-spy.error .spyTitle, +.logRow-spy.error .spyStatus, +.logRow-spy.error .spyTime { + color: red; +} + +.logRow-spy.loading .spyResponseText { + font-style: italic; + color: #888888; +} + +/************************************************************************************************/ + +.caption { + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #444444; +} + +.warning { + padding: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #888888; +} + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* DOM */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-dom { + overflow-x: hidden !important; +} + +.domTable { + font-size: 1em; + width: 100%; + table-layout: fixed; + background: #fff; +} + +.domTableIE { + width: auto; +} + +.memberLabelCell { + padding: 2px 0 2px 0; + vertical-align: top; +} + +.memberValueCell { + padding: 1px 0 1px 5px; + display: block; + overflow: hidden; +} + +.memberLabel { + display: block; + cursor: default; + -moz-user-select: none; + overflow: hidden; + /*position: absolute;*/ + padding-left: 18px; + /*max-width: 30%;*/ + /*white-space: nowrap;*/ + background-color: #FFFFFF; + text-decoration: none; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.memberRow.hasChildren .memberLabelCell .memberLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.userLabel { + color: #000000; + font-weight: bold; +} + +.userClassLabel { + color: #E90000; + font-weight: bold; +} + +.userFunctionLabel { + color: #025E2A; + font-weight: bold; +} + +.domLabel { + color: #000000; +} + +.domFunctionLabel { + color: #025E2A; +} + +.ordinalLabel { + color: SlateBlue; + font-weight: bold; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +.scopesRow { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 5px solid #BEBEBE; + color: #666666; +} +.scopesLabel { + background-color: LightYellow; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchEditCell { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 1px solid #BEBEBE; + color: #666666; +} + +.editor-watchNewRow, +.editor-memberRow { + font-family: Monaco, monospace !important; +} + +.editor-memberRow { + padding: 1px 0 !important; +} + +.editor-watchRow { + padding-bottom: 0 !important; +} + +.watchRow > .memberLabelCell { + font-family: Monaco, monospace; + padding-top: 1px; + padding-bottom: 1px; +} + +.watchRow > .memberLabelCell > .memberLabel { + background-color: transparent; +} + +.watchRow > .memberValueCell { + padding-top: 2px; + padding-bottom: 2px; +} + +.watchRow > .memberLabelCell, +.watchRow > .memberValueCell { + background-color: #F5F5F5; + border-bottom: 1px solid #BEBEBE; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchToolbox { + z-index: 2147483647; + position: absolute; + right: 0; + padding: 1px 2px; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* FROM ORIGINAL FIREBUG */ + + + + +/************************************************************************************************ + CSS Not organized +*************************************************************************************************/ +#fbConsole { + overflow-x: hidden !important; +} + +#fbCSS { + font: 1em Monaco, monospace; + padding: 0 7px; +} + +#fbstylesheetButtons select, #fbScriptButtons select { + font: 11px Lucida Grande, Tahoma, sans-serif; + margin-top: 1px; + padding-left: 3px; + background: #fafafa; + border: 1px inset #fff; + width: 220px; + outline: none; +} + +.Selector { margin-top:10px } +.CSSItem {margin-left: 4% } +.CSSText { padding-left:20px; } +.CSSProperty { color:#005500; } +.CSSValue { padding-left:5px; color:#000088; } + + +/************************************************************************************************ + Not organized +*************************************************************************************************/ + +#fbHTMLStatusBar { + display: inline; +} + +.fbToolbarButtons { + display: none; +} + +.fbStatusSeparator{ + display: block; + float: left; + padding-top: 4px; +} + +#fbStatusBarBox { + display: none; +} + +#fbToolbarContent { + display: block; + position: absolute; + _position: absolute; + top: 0; + padding-top: 5px; + height: 23px; + clip: rect(0, 2048px, 27px, 0); +} + +.fbTabMenuTarget { + display: none !important; + float: left; + width: 10px; + height: 10px; + margin-top: 6px; + background: url(tabMenuTarget.png); +} + +.fbTabMenuTarget:hover { + background: url(tabMenuTargetHover.png); +} + +.fbShadow { + float: left; + background: url(shadowAlpha.png) no-repeat bottom right !important; + background: url(shadow2.gif) no-repeat bottom right; + margin: 10px 0 0 10px !important; + margin: 10px 0 0 5px; +} + +.fbShadowContent { + display: block; + position: relative; + background-color: #fff; + border: 1px solid #a9a9a9; + top: -6px; + left: -6px; +} + +.fbMenu { + display: none; + position: absolute; + font-size: 11px; + z-index: 2147483647; +} + +.fbMenuContent { + padding: 2px; +} + +.fbMenuSeparator { + display: block; + position: relative; + padding: 1px 18px 0; + text-decoration: none; + color: #000; + cursor: default; + background: #ACA899; + margin: 4px 0; +} + +.fbMenuOption +{ + display: block; + position: relative; + padding: 2px 18px; + text-decoration: none; + color: #000; + cursor: default; +} + +.fbMenuOption:hover +{ + color: #fff; + background: #316AC5; +} + +.fbMenuGroup { + background: transparent url(tabMenuPin.png) no-repeat right 0; +} + +.fbMenuGroup:hover { + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuGroupSelected { + color: #fff; + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuChecked { + background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0; +} + +.fbMenuChecked:hover { + background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px; +} + +.fbMenuRadioSelected { + background: transparent url(tabMenuRadio.png) no-repeat 4px 0; +} + +.fbMenuRadioSelected:hover { + background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px; +} + +.fbMenuShortcut { + padding-right: 85px; +} + +.fbMenuShortcutKey { + position: absolute; + right: 0; + top: 2px; + width: 77px; +} + +#fbFirebugMenu { + top: 22px; + left: 0; +} + +.fbMenuDisabled { + color: #ACA899 !important; +} + +#fbFirebugSettingsMenu { + left: 245px; + top: 99px; +} + +#fbConsoleMenu { + top: 42px; + left: 48px; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; + float: left; + height: 20px; + width: 20px; + color: #000; + margin-right: 2px; + text-decoration: none; + cursor: default; +} + +.fbIconButton:hover { + position: relative; + top: -1px; + left: -1px; + margin-right: 0; + _margin-right: 1px; + color: #333; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbIconPressed { + position: relative; + margin-right: 0; + _margin-right: 1px; + top: 0 !important; + left: 0 !important; + height: 19px; + color: #333 !important; + border: 1px solid #bbb !important; + border-bottom: 1px solid #cfcfcf !important; + border-right: 1px solid #ddd !important; +} + + + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +.fbBody { + margin: 0; + padding: 0; + overflow: hidden; + + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px !important; + background: #fff url(search.gif) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat !important; + background: url(errorIcon.gif) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + position: absolute; + _position: static; + top: 0; + left: 0; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; + overflow: hidden; +} + +#fbTop { + height: 50px; +} + +#fbToolbar { + background: url(sprite.png) #eee 0 0; + height: 27px; + font-size: 11px; +} + +#fbPanelBarBox { + background: url(sprite.png) #d9d9d9 0 -27px; + height: 23px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 0 5px 0; +} + +#fbToolbarIcon a { + background: url(sprite.png) 0 -135px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} +/* +#fbStatusBarBox a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 5px; + margin: 0 0 0 1px; + cursor: default; +} + +#fbStatusBarBox a:hover { + color: #333; + padding: 3px 4px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} +/**/ + +.fbButton { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 6px 4px 7px; + cursor: default; +} + +.fbButton:hover { + color: #333; + padding: 3px 5px 3px 6px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbBtnPressed { + background: #ECEBE3; + padding: 3px 4px 2px 6px !important; + margin: 1px 0 0 1px !important; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +#fbStatusBarBox { + top: 4px; + cursor: default; +} + +.fbToolbarSeparator { + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 6px 3px; + float: left; +} + +.fbBtnSelected { + font-weight: bold; +} + +.fbStatusBar { + color: #aca899; +} + +.fbStatusBar a { + text-decoration: none; + color: black; +} + +.fbStatusBar a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + width: 50px; + padding: 7px 0 4px 5px; + z-index: 6; + background: url(sprite.png) #eee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 1024px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #d9d9d9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #d9d9d9 0 -27px; + position: absolute; + height: 23px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 23px; + padding-left: 4px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 1em; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + margin-left: 6px; + background: #fff; +} + +#fbLargeCommandLine { + display: none; + position: absolute; + z-index: 9; + top: 27px; + right: 0; + width: 294px; + height: 201px; + border-width: 0; + margin: 0; + padding: 2px 0 0 2px; + resize: none; + outline: none; + font-size: 11px; + overflow: auto; + border-top: 1px solid #B9B7AF; + _right: -1px; + _border-left: 1px solid #fff; +} + +#fbLargeCommandButtons { + display: none; + background: #EEEEEE; + bottom: 0; + right: 0; + width: 294px; + height: 21px; + padding-top: 1px; + position: fixed; + border-top: 1px solid #ACA899; + z-index: 9; +} + +#fbSmallCommandLineIcon { + background: url(down.png) no-repeat; + position: absolute; + right: 2px; + bottom: 3px; + + z-index: 99; +} + +#fbSmallCommandLineIcon:hover { + background: url(downHover.png) no-repeat; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: fixed; + _position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 7px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; + outline: none; +} + +#fbLargeCommandLineIcon { + background: url(up.png) no-repeat; + position: absolute; + right: 1px; + bottom: 1px; + z-index: 10; +} + +#fbLargeCommandLineIcon:hover { + background: url(upHover.png) no-repeat; +} + +div.fbFitHeight { + overflow: auto; + position: relative; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +.fbSmallButton { + overflow: hidden; + width: 16px; + height: 16px; + display: block; + text-decoration: none; + cursor: default; +} + +#fbWindowButtons .fbSmallButton { + float: right; +} + +#fbWindow_btClose { + background: url(min.png); +} + +#fbWindow_btClose:hover { + background: url(minHover.png); +} + +#fbWindow_btDetach { + background: url(detach.png); +} + +#fbWindow_btDetach:hover { + background: url(detachHover.png); +} + +#fbWindow_btDeactivate { + background: url(off.png); +} + +#fbWindow_btDeactivate:hover { + background: url(offHover.png); +} + + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 23px; + color: #565656; +} + +.fbPanelBar span { + /*display: block; TODO: safe to remove this? */ + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 23px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #EEEEEE 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: fixed; + _position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #eee; + color: #000; + border: 1px solid #777; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 9; + position: absolute; + height: 100%; + top: 27px; +} + +/************************************************************************************************/ +div.lineNo { + font: 1em Monaco, monospace; + position: relative; + float: left; + top: 0; + left: 0; + margin: 0 5px 0 0; + padding: 0 5px 0 10px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +.sourceBox { + position: absolute; +} + +.sourceCode { + font: 1em Monaco, monospace; + overflow: hidden; + white-space: pre; + display: inline; +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* IE6 need this hack */ +* html .selectedElement { + position: relative; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 1em; +} + +/* TODO: remove this? */ +/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to +position. if so, override it at chrome.js initialization when creating the div */ +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + zbackground-color: #FFFFFF; +} +/**/ + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + + /* TODO: xxxpedro make long strings break line */ + /*white-space: pre; */ +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warn { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png) !important; + background-image: url(infoIcon.gif); +} + +.logRow-warn { + background-color: cyan; + background-image: url(warningIcon.png) !important; + background-image: url(warningIcon.gif); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png) !important; + background-image: url(errorIcon.gif); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +/* +//TODO: remove this when console2 is finished +*/ +/* +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +}/**/ + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.html new file mode 100755 index 0000000..4432a32 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.html @@ -0,0 +1,213 @@ + + + + +Firebug Lite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + +
      +   +   +   +
      + + +
      +
      + + + +   + + + + + + + + + Inspect + + + + + Clear + + + + + + + + + + + + + +
      + +
      + + + + + +
       
      + +
      +
      +
      +
      +
      +
      + + +
       
      + + +
      + + +
      +
      +
      + +
      + + + + + +
      + Run + Clear + + +
      + +
      +
      +
      >>>
      + + +
      +
      + + + + 2 errors + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.png new file mode 100755 index 0000000..338dc5a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/firebug.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/group.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/group.gif new file mode 100755 index 0000000..8db97c2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/group.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/infoIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/infoIcon.gif new file mode 100755 index 0000000..0618e20 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/infoIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/infoIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/infoIcon.png new file mode 100755 index 0000000..da1e533 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/infoIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/loading_16.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/loading_16.gif new file mode 100755 index 0000000..085ccae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/loading_16.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/min.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/min.png new file mode 100755 index 0000000..1034d66 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/min.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/minHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/minHover.png new file mode 100755 index 0000000..b0d1e1a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/minHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/off.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/off.png new file mode 100755 index 0000000..b70b1d2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/off.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/offHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/offHover.png new file mode 100755 index 0000000..f3670f1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/offHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/pixel_transparent.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/pixel_transparent.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/pixel_transparent.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/roundCorner.svg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/roundCorner.svg new file mode 100755 index 0000000..be0291f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/roundCorner.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/search.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/search.gif new file mode 100755 index 0000000..2a62098 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/search.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/search.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/search.png new file mode 100755 index 0000000..fba33b8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/search.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadow.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadow.gif new file mode 100755 index 0000000..af7f537 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadow.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadow2.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadow2.gif new file mode 100755 index 0000000..099cbf3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadow2.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadowAlpha.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadowAlpha.png new file mode 100755 index 0000000..a2561df Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/shadowAlpha.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/sprite.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/sprite.png new file mode 100755 index 0000000..d117e12 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/sprite.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverLeft.png new file mode 100755 index 0000000..708215d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverMid.png new file mode 100755 index 0000000..6ff9a86 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverRight.png new file mode 100755 index 0000000..9f02130 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabHoverRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabLeft.png new file mode 100755 index 0000000..8c50213 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuCheckbox.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuCheckbox.png new file mode 100755 index 0000000..4726e62 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuCheckbox.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuPin.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuPin.png new file mode 100755 index 0000000..eb4b11e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuPin.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuRadio.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuRadio.png new file mode 100755 index 0000000..55b982d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuRadio.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuTarget.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuTarget.png new file mode 100755 index 0000000..957bd9f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuTarget.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuTargetHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuTargetHover.png new file mode 100755 index 0000000..200a370 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMenuTargetHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMid.png new file mode 100755 index 0000000..0a00b60 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabRight.png new file mode 100755 index 0000000..b43c352 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tabRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorBorders.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorBorders.gif new file mode 100755 index 0000000..0ee5497 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorBorders.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorBorders.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorBorders.png new file mode 100755 index 0000000..21682c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorBorders.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorCorners.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorCorners.gif new file mode 100755 index 0000000..04f8421 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorCorners.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorCorners.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorCorners.png new file mode 100755 index 0000000..a0f839d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/textEditorCorners.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/titlebarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/titlebarMid.png new file mode 100755 index 0000000..5fc63e7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/titlebarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/toolbarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/toolbarMid.png new file mode 100755 index 0000000..8520aab Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/toolbarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tree_close.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tree_close.gif new file mode 100755 index 0000000..e26728a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tree_close.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tree_open.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tree_open.gif new file mode 100755 index 0000000..edf662f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/tree_open.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/twistyClosed.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/twistyClosed.png new file mode 100755 index 0000000..f80319b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/twistyClosed.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/twistyOpen.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/twistyOpen.png new file mode 100755 index 0000000..8680124 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/twistyOpen.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/up.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/up.png new file mode 100755 index 0000000..2174d03 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/up.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/upActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/upActive.png new file mode 100755 index 0000000..236cf67 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/upActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/upHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/upHover.png new file mode 100755 index 0000000..cd81317 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/upHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/warningIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/warningIcon.gif new file mode 100755 index 0000000..8497278 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/warningIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/warningIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/warningIcon.png new file mode 100755 index 0000000..de51084 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/light/warningIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/blank.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/blank.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/blank.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/buttonBg.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/buttonBg.png new file mode 100755 index 0000000..f367b42 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/buttonBg.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/buttonBgHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/buttonBgHover.png new file mode 100755 index 0000000..cd37a0d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/buttonBgHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/detach.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/detach.png new file mode 100755 index 0000000..0ddb9a1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/detach.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/detachHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/detachHover.png new file mode 100755 index 0000000..e419272 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/detachHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disable.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disable.gif new file mode 100755 index 0000000..dd9eb0e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disable.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disable.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disable.png new file mode 100755 index 0000000..c28bcdf Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disable.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disableHover.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disableHover.gif new file mode 100755 index 0000000..70565a8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disableHover.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disableHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disableHover.png new file mode 100755 index 0000000..26fe375 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/disableHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/down.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/down.png new file mode 100755 index 0000000..acbbd30 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/down.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/downActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/downActive.png new file mode 100755 index 0000000..f4312b2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/downActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/downHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/downHover.png new file mode 100755 index 0000000..8144e63 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/downHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon-sm.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon-sm.png new file mode 100755 index 0000000..0c377e3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon-sm.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon.gif new file mode 100755 index 0000000..8ee8116 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon.png new file mode 100755 index 0000000..2d75261 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/errorIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug-1.3a2.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug-1.3a2.css new file mode 100755 index 0000000..b5dd5dd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug-1.3a2.css @@ -0,0 +1,817 @@ +.fbBtnPressed { + background: #ECEBE3; + padding: 3px 6px 2px 7px !important; + margin: 1px 0 0 1px; + _margin: 1px -1px 0 1px; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +.fbToolbarButtons { + display: none; +} + +#fbStatusBarBox { + display: none; +} + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +html, body { + margin: 0; + padding: 0; + overflow: hidden; +} + +body { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + position: fixed; + overflow: hidden; + height: 100%; + width: 100%; + border-collapse: collapse; + background: #fff; +} + +#fbTop { + height: 49px; +} + +#fbToolbar { + position: absolute; + z-index: 5; + width: 100%; + top: 0; + background: url(sprite.png) #f1f2ee 0 0; + height: 27px; + font-size: 11px; + overflow: hidden; +} + +#fbPanelBarBox { + top: 27px; + position: absolute; + z-index: 8; + width: 100%; + background: url(sprite.png) #dbd9c9 0 -27px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 4px 5px 0; +} + +#fbToolbarIcon a { + display: block; + height: 20px; + width: 20px; + background: url(sprite.png) 0 -135px; + text-decoration: none; + cursor: default; +} + +#fbToolbarButtons { + float: left; + padding: 4px 2px 0 5px; +} + +#fbToolbarButtons a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 8px 4px; + cursor: default; +} + +#fbToolbarButtons a:hover { + color: #333; + padding: 3px 7px 3px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +#fbStatusBarBox { + position: relative; + top: 5px; + line-height: 19px; + cursor: default; +} + +.fbToolbarSeparator{ + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 10px 6px 0 0; + float: left; +} + +.fbStatusBar span { + color: #808080; + padding: 0 4px 0 0; +} + +.fbStatusBar span a { + text-decoration: none; + color: black; +} + +.fbStatusBar span a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + _width: 50px; + padding: 5px 0 5px 5px; + z-index: 6; + background: url(sprite.png) #f1f2ee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 255px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 22px; + padding-left: 10px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 11px; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + padding-left: 6px; + background: #fff; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 7px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; +} + +div.fbFitHeight { + overflow: auto; + _position: absolute; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +#fbWindowButtons a { + font-size: 1px; + width: 16px; + height: 16px; + display: block; + float: right; + margin-right: 4px; + text-decoration: none; + cursor: default; +} + +#fbWindow_btClose { + background: url(sprite.png) 0 -119px; +} + +#fbWindow_btClose:hover { + background: url(sprite.png) -16px -119px; +} + +#fbWindow_btDetach { + background: url(sprite.png) -32px -119px; +} + +#fbWindow_btDetach:hover { + background: url(sprite.png) -48px -119px; +} + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + display: block; + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #f1f2ee 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #ece9d8; + color: #000; + border: 1px solid #716f64; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 9; + position: absolute; + height: 100%; + top: 27px; + _width: 6px; +} + +/************************************************************************************************/ +div.lineNo { + font: 11px Monaco, monospace; + float: left; + display: inline; + position: relative; + margin: 0; + padding: 0 5px 0 20px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +pre.nodeCode { + font: 11px Monaco, monospace; + margin: 0; + padding-left: 10px; + overflow: hidden; + /* + _width: 100%; + /**/ +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 11px; +} + +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; +} + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + white-space: pre; +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warning { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png); +} + +.logRow-warning { + background-color: cyan; + background-image: url(warningIcon.png); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +} + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.IE6.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.IE6.css new file mode 100755 index 0000000..14f8aa8 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.IE6.css @@ -0,0 +1,20 @@ +/************************************************************************************************/ +#fbToolbarSearch { + background-image: url(search.gif) !important; +} +/************************************************************************************************/ +.fbErrors { + background-image: url(errorIcon.gif) !important; +} +/************************************************************************************************/ +.logRow-info { + background-image: url(infoIcon.gif) !important; +} + +.logRow-warning { + background-image: url(warningIcon.gif) !important; +} + +.logRow-error { + background-image: url(errorIcon.gif) !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.css b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.css new file mode 100755 index 0000000..92e6c3b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.css @@ -0,0 +1,3140 @@ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Loose */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* +.netInfoResponseHeadersTitle, netInfoResponseHeadersBody { + display: none; +} +/**/ + +/* IE6 need a separated rule, otherwise it will not recognize it */ +.collapsed { + display: none; +} + +[collapsed="true"] { + display: none; +} + +#fbCSS { + padding: 0 !important; +} + +.cssPropDisable { + float: left; + display: block; + width: 2em; + cursor: default; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* panelBase */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/************************************************************************************************/ + +.infoTip { + z-index: 2147483647; + position: fixed; + padding: 2px 3px; + border: 1px solid #CBE087; + background: LightYellow; + font-family: Monaco, monospace; + color: #000000; + display: none; + white-space: nowrap; + pointer-events: none; +} + +.infoTip[active="true"] { + display: block; +} + +.infoTipLoading { + width: 16px; + height: 16px; + background: url(chrome://firebug/skin/loading_16.gif) no-repeat; +} + +.infoTipImageBox { + font-size: 11px; + min-width: 100px; + text-align: center; +} + +.infoTipCaption { + font-size: 11px; + font: Monaco, monospace; +} + +.infoTipLoading > .infoTipImage, +.infoTipLoading > .infoTipCaption { + display: none; +} + +/************************************************************************************************/ + +h1.groupHeader { + padding: 2px 4px; + margin: 0 0 4px 0; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + background: #eee url(group.gif) repeat-x; + font-size: 11px; + font-weight: bold; + _position: relative; +} + +/************************************************************************************************/ + +.inlineEditor, +.fixedWidthEditor { + z-index: 2147483647; + position: absolute; + display: none; +} + +.inlineEditor { + margin-left: -6px; + margin-top: -3px; + /* + _margin-left: -7px; + _margin-top: -5px; + /**/ +} + +.textEditorInner, +.fixedWidthEditor { + margin: 0 0 0 0 !important; + padding: 0; + border: none !important; + font: inherit; + text-decoration: inherit; + background-color: #FFFFFF; +} + +.fixedWidthEditor { + border-top: 1px solid #888888 !important; + border-bottom: 1px solid #888888 !important; +} + +.textEditorInner { + position: relative; + top: -7px; + left: -5px; + + outline: none; + resize: none; + + /* + _border: 1px solid #999 !important; + _padding: 1px !important; + _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040"); + /**/ +} + +.textEditorInner1 { + padding-left: 11px; + background: url(textEditorBorders.png) repeat-y; + _background: url(textEditorBorders.gif) repeat-y; + _overflow: hidden; +} + +.textEditorInner2 { + position: relative; + padding-right: 2px; + background: url(textEditorBorders.png) repeat-y 100% 0; + _background: url(textEditorBorders.gif) repeat-y 100% 0; + _position: fixed; +} + +.textEditorTop1 { + background: url(textEditorCorners.png) no-repeat 100% 0; + margin-left: 11px; + height: 10px; + _background: url(textEditorCorners.gif) no-repeat 100% 0; + _overflow: hidden; +} + +.textEditorTop2 { + position: relative; + left: -11px; + width: 11px; + height: 10px; + background: url(textEditorCorners.png) no-repeat; + _background: url(textEditorCorners.gif) no-repeat; +} + +.textEditorBottom1 { + position: relative; + background: url(textEditorCorners.png) no-repeat 100% 100%; + margin-left: 11px; + height: 12px; + _background: url(textEditorCorners.gif) no-repeat 100% 100%; +} + +.textEditorBottom2 { + position: relative; + left: -11px; + width: 11px; + height: 12px; + background: url(textEditorCorners.png) no-repeat 0 100%; + _background: url(textEditorCorners.gif) no-repeat 0 100%; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* CSS */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-css { + overflow-x: hidden; +} + +.cssSheet > .insertBefore { + height: 1.5em; +} + +.cssRule { + position: relative; + margin: 0; + padding: 1em 0 0 6px; + font-family: Monaco, monospace; + color: #000000; +} + +.cssRule:first-child { + padding-top: 6px; +} + +.cssElementRuleContainer { + position: relative; +} + +.cssHead { + padding-right: 150px; +} + +.cssProp { + /*padding-left: 2em;*/ +} + +.cssPropName { + color: DarkGreen; +} + +.cssPropValue { + margin-left: 8px; + color: DarkBlue; +} + +.cssOverridden span { + text-decoration: line-through; +} + +.cssInheritedRule { +} + +.cssInheritLabel { + margin-right: 0.5em; + font-weight: bold; +} + +.cssRule .objectLink-sourceLink { + top: 0; +} + +.cssProp.editGroup:hover { + background: url(disable.png) no-repeat 2px 1px; + _background: url(disable.gif) no-repeat 2px 1px; +} + +.cssProp.editGroup.editing { + background: none; +} + +.cssProp.disabledStyle { + background: url(disableHover.png) no-repeat 2px 1px; + _background: url(disableHover.gif) no-repeat 2px 1px; + opacity: 1; + color: #CCCCCC; +} + +.disabledStyle .cssPropName, +.disabledStyle .cssPropValue { + color: #CCCCCC; +} + +.cssPropValue.editing + .cssSemi, +.inlineExpander + .cssSemi { + display: none; +} + +.cssPropValue.editing { + white-space: nowrap; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.stylePropName { + font-weight: bold; + padding: 0 4px 4px 4px; + width: 50%; +} + +.stylePropValue { + width: 50%; +} +/* +.useA11y .a11yCSSView .focusRow:focus { + outline: none; + background-color: transparent + } + + .useA11y .a11yCSSView .focusRow:focus .cssSelector, + .useA11y .a11yCSSView .focusRow:focus .cssPropName, + .useA11y .a11yCSSView .focusRow:focus .cssPropValue, + .useA11y .a11yCSSView .computedStyleRow:focus, + .useA11y .a11yCSSView .groupHeader:focus { + outline: 2px solid #FF9933; + outline-offset: -2px; + background-color: #FFFFD6; + } + + .useA11y .a11yCSSView .groupHeader:focus { + outline-offset: -2px; + } +/**/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Net */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* See license.txt for terms of usage */ + +.panelNode-net { + overflow-x: hidden; +} + +.netTable { + width: 100%; +} + +/************************************************************************************************/ + +.hideCategory-undefined .category-undefined, +.hideCategory-html .category-html, +.hideCategory-css .category-css, +.hideCategory-js .category-js, +.hideCategory-image .category-image, +.hideCategory-xhr .category-xhr, +.hideCategory-flash .category-flash, +.hideCategory-txt .category-txt, +.hideCategory-bin .category-bin { + display: none; +} + +/************************************************************************************************/ + +.netHeadRow { + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netHeadCol { + border-bottom: 1px solid #CCCCCC; + padding: 2px 4px 2px 18px; + font-weight: bold; +} + +.netHeadLabel { + white-space: nowrap; + overflow: hidden; +} + +/************************************************************************************************/ +/* Header for Net panel table */ + +.netHeaderRow { + height: 16px; +} + +.netHeaderCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x; + white-space: nowrap; +} + +.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox { + padding: 2px 14px 2px 18px; +} + +.netHeaderCellBox { + padding: 2px 14px 2px 10px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.netHeaderCell:hover:active { + background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x; +} + +.netHeaderSorted { + background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x; +} + +.netHeaderSorted > .netHeaderCellBox { + border-right-color: #6B7C93; + background: url(chrome://firebug/skin/arrowDown.png) no-repeat right; +} + +.netHeaderSorted.sortedAscending > .netHeaderCellBox { + background-image: url(chrome://firebug/skin/arrowUp.png); +} + +.netHeaderSorted:hover:active { + background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x; +} + +/************************************************************************************************/ +/* Breakpoints */ + +.panelNode-net .netRowHeader { + display: block; +} + +.netRowHeader { + cursor: pointer; + display: none; + height: 15px; + margin-right: 0 !important; +} + +/* Display brekpoint disc */ +.netRow .netRowHeader { + background-position: 5px 1px; +} + +.netRow[breakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpoint.png); +} + +.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader { + background-image: url(chrome://firebug/skin/breakpointDisabled.png); +} + +.netRow.category-xhr:hover .netRowHeader { + background-color: #F6F6F6; +} + +#netBreakpointBar { + max-width: 38px; +} + +#netHrefCol > .netHeaderCellBox { + border-left: 0px; +} + +.netRow .netRowHeader { + width: 3px; +} + +.netInfoRow .netRowHeader { + display: table-cell; +} + +/************************************************************************************************/ +/* Column visibility */ + +.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"], +.netTable[hiddenCols~=netHrefCol] TD.netHrefCol, +.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"], +.netTable[hiddenCols~=netStatusCol] TD.netStatusCol, +.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"], +.netTable[hiddenCols~=netDomainCol] TD.netDomainCol, +.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"], +.netTable[hiddenCols~=netSizeCol] TD.netSizeCol, +.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"], +.netTable[hiddenCols~=netTimeCol] TD.netTimeCol { + display: none; +} + +/************************************************************************************************/ + +.netRow { + background: LightYellow; +} + +.netRow.loaded { + background: #FFFFFF; +} + +.netRow.loaded:hover { + background: #EFEFEF; +} + +.netCol { + padding: 0; + vertical-align: top; + border-bottom: 1px solid #EFEFEF; + white-space: nowrap; + height: 17px; +} + +.netLabel { + width: 100%; +} + +.netStatusCol { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.responseError > .netStatusCol { + color: red; +} + +.netDomainCol { + padding-left: 5px; +} + +.netSizeCol { + text-align: right; + padding-right: 10px; +} + +.netHrefLabel { + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 10; + position: absolute; + padding-left: 18px; + padding-top: 1px; + max-width: 15%; + font-weight: bold; +} + +.netFullHrefLabel { + display: none; + -moz-user-select: none; + padding-right: 10px; + padding-bottom: 3px; + max-width: 100%; + background: #FFFFFF; + z-index: 200; +} + +.netHrefCol:hover > .netFullHrefLabel { + display: block; +} + +.netRow.loaded:hover .netCol > .netFullHrefLabel { + background-color: #EFEFEF; +} + +.useA11y .a11yShowFullLabel { + display: block; + background-image: none !important; + border: 1px solid #CBE087; + background-color: LightYellow; + font-family: Monaco, monospace; + color: #000000; + font-size: 10px; + z-index: 2147483647; +} + +.netSizeLabel { + padding-left: 6px; +} + +.netStatusLabel, +.netDomainLabel, +.netSizeLabel, +.netBar { + padding: 1px 0 2px 0 !important; +} + +.responseError { + color: red; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.hasHeaders .netHrefLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/************************************************************************************************/ + +.netLoadingIcon { + position: absolute; + border: 0; + margin-left: 14px; + width: 16px; + height: 16px; + background: transparent no-repeat 0 0; + background-image: url(chrome://firebug/skin/loading_16.gif); + display:inline-block; +} + +.loaded .netLoadingIcon { + display: none; +} + +/************************************************************************************************/ + +.netBar, .netSummaryBar { + position: relative; + border-right: 50px solid transparent; +} + +.netResolvingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x; + z-index:60; +} + +.netConnectingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x; + z-index:50; +} + +.netBlockingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x; + z-index:40; +} + +.netSendingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x; + z-index:30; +} + +.netWaitingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x; + z-index:20; + min-width: 1px; +} + +.netReceivingBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x; + z-index:10; +} + +.netWindowLoadBar, +.netContentLoadBar { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 1px; + background-color: red; + z-index: 70; + opacity: 0.5; + display: none; + margin-bottom:-1px; +} + +.netContentLoadBar { + background-color: Blue; +} + +.netTimeLabel { + -moz-box-sizing: padding-box; + position: absolute; + top: 1px; + left: 100%; + padding-left: 6px; + color: #444444; + min-width: 16px; +} + +/* + * Timing info tip is reusing net timeline styles to display the same + * colors for individual request phases. Notice that the info tip must + * respect also loaded and fromCache styles that also modify the + * actual color. These are used both on the same element in case + * of the tooltip. + */ +.loaded .netReceivingBar, +.loaded.netReceivingBar { + background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x; + border-color: #B6B6B6; +} + +.fromCache .netReceivingBar, +.fromCache.netReceivingBar { + background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x; + border-color: #D6D6D6; +} + +.netSummaryRow .netTimeLabel, +.loaded .netTimeLabel { + background: transparent; +} + +/************************************************************************************************/ +/* Time Info tip */ + +.timeInfoTip { + width: 150px; + height: 40px +} + +.timeInfoTipBar, +.timeInfoTipEventBar { + position: relative; + display: block; + margin: 0; + opacity: 1; + height: 15px; + width: 4px; +} + +.timeInfoTipEventBar { + width: 1px !important; +} + +.timeInfoTipCell.startTime { + padding-right: 8px; +} + +.timeInfoTipCell.elapsedTime { + text-align: right; + padding-right: 8px; +} + +/************************************************************************************************/ +/* Size Info tip */ + +.sizeInfoLabelCol { + font-weight: bold; + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; +} + +.sizeInfoSizeCol { + font-weight: bold; +} + +.sizeInfoDetailCol { + color: gray; + text-align: right; +} + +.sizeInfoDescCol { + font-style: italic; +} + +/************************************************************************************************/ +/* Summary */ + +.netSummaryRow .netReceivingBar { + background: #BBBBBB; + border: none; +} + +.netSummaryLabel { + color: #222222; +} + +.netSummaryRow { + background: #BBBBBB !important; + font-weight: bold; +} + +.netSummaryRow .netBar { + border-right-color: #BBBBBB; +} + +.netSummaryRow > .netCol { + border-top: 1px solid #999999; + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 1px; + padding-bottom: 2px; +} + +.netSummaryRow > .netHrefCol:hover { + background: transparent !important; +} + +.netCountLabel { + padding-left: 18px; +} + +.netTotalSizeCol { + text-align: right; + padding-right: 10px; +} + +.netTotalTimeCol { + text-align: right; +} + +.netCacheSizeLabel { + position: absolute; + z-index: 1000; + left: 0; + top: 0; +} + +/************************************************************************************************/ + +.netLimitRow { + background: rgb(255, 255, 225) !important; + font-weight:normal; + color: black; + font-weight:normal; +} + +.netLimitLabel { + padding-left: 18px; +} + +.netLimitRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + vertical-align: middle !important; + padding-top: 2px; + padding-bottom: 2px; +} + +.netLimitButton { + font-size: 11px; + padding-top: 1px; + padding-bottom: 1px; +} + +/************************************************************************************************/ + +.netInfoCol { + border-top: 1px solid #EEEEEE; + background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; +} + +.netInfoBody { + margin: 10px 0 4px 10px; +} + +.netInfoTabs { + position: relative; + padding-left: 17px; +} + +.netInfoTab { + position: relative; + top: -3px; + margin-top: 10px; + padding: 4px 6px; + border: 1px solid transparent; + border-bottom: none; + _border: none; + font-weight: bold; + color: #565656; + cursor: pointer; +} + +/*.netInfoTab:hover { + cursor: pointer; +}*/ + +/* replaced by .netInfoTabSelected for IE6 support +.netInfoTab[selected="true"] { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} +/**/ +.netInfoTabSelected { + cursor: default !important; + border: 1px solid #D7D7D7 !important; + border-bottom: none !important; + -moz-border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; + background-color: #FFFFFF; +} + +.logRow-netInfo.error .netInfoTitle { + color: red; +} + +.logRow-netInfo.loading .netInfoResponseText { + font-style: italic; + color: #888888; +} + +.loading .netInfoResponseHeadersTitle { + display: none; +} + +.netInfoResponseSizeLimit { + font-family: Lucida Grande, Tahoma, sans-serif; + padding-top: 10px; + font-size: 11px; +} + +.netInfoText { + display: none; + margin: 0; + border: 1px solid #D7D7D7; + border-right: none; + padding: 8px; + background-color: #FFFFFF; + font-family: Monaco, monospace; + white-space: pre-wrap; + /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */ +} + +/* replaced by .netInfoTextSelected for IE6 support +.netInfoText[selected="true"] { + display: block; +} +/**/ +.netInfoTextSelected { + display: block; +} + +.netInfoParamName { + padding-right: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + vertical-align: top; + text-align: right; + white-space: nowrap; +} + +.netInfoPostText .netInfoParamName { + width: 1px; /* Google Chrome need this otherwise the first column of + the post variables table will be larger than expected */ +} + +.netInfoParamValue { + width: 100%; +} + +.netInfoHeadersText, +.netInfoPostText, +.netInfoPutText { + padding-top: 0; +} + +.netInfoHeadersGroup, +.netInfoPostParams, +.netInfoPostSource { + margin-bottom: 4px; + border-bottom: 1px solid #D7D7D7; + padding-top: 8px; + padding-bottom: 2px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #565656; +} + +.netInfoPostParamsTable, +.netInfoPostPartsTable, +.netInfoPostJSONTable, +.netInfoPostXMLTable, +.netInfoPostSourceTable { + margin-bottom: 10px; + width: 100%; +} + +.netInfoPostContentType { + color: #bdbdbd; + padding-left: 50px; + font-weight: normal; +} + +.netInfoHtmlPreview { + border: 0; + width: 100%; + height:100%; +} + +/************************************************************************************************/ +/* Request & Response Headers */ + +.netHeadersViewSource { + color: #bdbdbd; + margin-left: 200px; + font-weight: normal; +} + +.netHeadersViewSource:hover { + color: blue; + cursor: pointer; +} + +/************************************************************************************************/ + +.netActivationRow, +.netPageSeparatorRow { + background: rgb(229, 229, 229) !important; + font-weight: normal; + color: black; +} + +.netActivationLabel { + background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px; + padding-left: 22px; +} + +/************************************************************************************************/ + +.netPageSeparatorRow { + height: 5px !important; +} + +.netPageSeparatorLabel { + padding-left: 22px; + height: 5px !important; +} + +.netPageRow { + background-color: rgb(255, 255, 255); +} + +.netPageRow:hover { + background: #EFEFEF; +} + +.netPageLabel { + padding: 1px 0 2px 18px !important; + font-weight: bold; +} + +/************************************************************************************************/ + +.netActivationRow > .netCol { + border-bottom: 2px solid; + -moz-border-bottom-colors: #EFEFEF #999999; + padding-top: 2px; + padding-bottom: 3px; +} +/* +.useA11y .panelNode-net .a11yFocus:focus, +.useA11y .panelNode-net .focusRow:focus { + outline-offset: -2px; + background-color: #FFFFD6 !important; +} + +.useA11y .panelNode-net .netHeaderCell:focus, +.useA11y .panelNode-net :focus .netHeaderCell, +.useA11y .panelNode-net :focus .netReceivingBar, +.useA11y .netSummaryRow :focus .netBar, +.useA11y .netSummaryRow:focus .netBar { + background-color: #FFFFD6; + background-image: none; + border-color: #FFFFD6; +} +/**/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Windows */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/************************************************************************************************/ +/* Twisties */ + +.twisty, +.logRow-errorMessage > .hasTwisty > .errorTitle, +.logRow-log > .objectBox-array.hasTwisty, +.logRow-spy .spyHead .spyTitle, +.logGroup > .logRow, +.memberRow.hasChildren > .memberLabelCell > .memberLabel, +.hasHeaders .netHrefLabel, +.netPageRow > .netCol > .netPageTitle { + background-image: url(tree_open.gif); + background-repeat: no-repeat; + background-position: 2px 2px; + min-height: 12px; +} + +.logRow-errorMessage > .hasTwisty.opened > .errorTitle, +.logRow-log > .objectBox-array.hasTwisty.opened, +.logRow-spy.opened .spyHead .spyTitle, +.logGroup.opened > .logRow, +.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel, +.nodeBox.highlightOpen > .nodeLabel > .twisty, +.nodeBox.open > .nodeLabel > .twisty, +.netRow.opened > .netCol > .netHrefLabel, +.netPageRow.opened > .netCol > .netPageTitle { + background-image: url(tree_close.gif); +} + +.twisty { + background-position: 4px 4px; +} + + + +/************************************************************************************************/ +/* Twisties IE6 */ + +/* IE6 has problems with > operator, and multiple classes */ + +* html .logRow-spy .spyHead .spyTitle, +* html .logGroup .logGroupLabel, +* html .hasChildren .memberLabelCell .memberLabel, +* html .hasHeaders .netHrefLabel { + background-image: url(tree_open.gif); + background-repeat: no-repeat; + background-position: 2px 2px; +} + +* html .opened .spyHead .spyTitle, +* html .opened .logGroupLabel, +* html .opened .memberLabelCell .memberLabel { + background-image: url(tree_close.gif); + background-repeat: no-repeat; + background-position: 2px 2px; +} + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* Console */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-console { + overflow-x: hidden; +} + +.objectLink { + text-decoration: none; +} + +.objectLink:hover { + cursor: pointer; + text-decoration: underline; +} + +.logRow { + position: relative; + margin: 0; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; + overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */ +} + +.useA11y .logRow:focus { + border-bottom: 1px solid #000000 !important; + outline: none !important; + background-color: #FFFFAD !important; +} + +.useA11y .logRow:focus a.objectLink-sourceLink { + background-color: #FFFFAD; +} + +.useA11y .a11yFocus:focus, .useA11y .objectBox:focus { + outline: 2px solid #FF9933; + background-color: #FFFFAD; +} + +.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{ + background-color: #888888 !important; +} + +.useA11y .logGroup.opened > .logRow { + border-bottom: 1px solid #ffffff; +} + +.logGroup { + background: url(group.gif) repeat-x #FFFFFF; + padding: 0 !important; + border: none !important; +} + +.logGroupBody { + display: none; + margin-left: 16px; + border-left: 1px solid #D7D7D7; + border-top: 1px solid #D7D7D7; + background: #FFFFFF; +} + +.logGroup > .logRow { + background-color: transparent !important; + font-weight: bold; +} + +.logGroup.opened > .logRow { + border-bottom: none; +} + +.logGroup.opened > .logGroupBody { + display: block; +} + +/*****************************************************************************************/ + +.logRow-command > .objectBox-text { + font-family: Monaco, monospace; + color: #0000FF; + white-space: pre-wrap; +} + +.logRow-info, +.logRow-warn, +.logRow-error, +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-left: 22px; + background-repeat: no-repeat; + background-position: 4px 2px; +} + +.logRow-assert, +.logRow-warningMessage, +.logRow-errorMessage { + padding-top: 0; + padding-bottom: 0; +} + +.logRow-info, +.logRow-info .objectLink-sourceLink { + background-color: #FFFFFF; +} + +.logRow-warn, +.logRow-warningMessage, +.logRow-warn .objectLink-sourceLink, +.logRow-warningMessage .objectLink-sourceLink { + background-color: cyan; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage, +.logRow-error .objectLink-sourceLink, +.logRow-errorMessage .objectLink-sourceLink { + background-color: LightYellow; +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + color: #FF0000; +} + +.logRow-info { + /*background-image: url(chrome://firebug/skin/infoIcon.png);*/ +} + +.logRow-warn, +.logRow-warningMessage { + /*background-image: url(chrome://firebug/skin/warningIcon.png);*/ +} + +.logRow-error, +.logRow-assert, +.logRow-errorMessage { + /*background-image: url(chrome://firebug/skin/errorIcon.png);*/ +} + +/*****************************************************************************************/ + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-string, +.objectBox-text, +.objectLink-textNode { + white-space: pre-wrap; +} + +.objectBox-number, +.objectLink-styleRule, +.objectLink-element, +.objectLink-textNode { + color: #000088; +} + +.objectBox-string { + color: #FF0000; +} + +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + color: DarkGreen; +} + +.objectBox-null, +.objectBox-undefined { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-exception { + padding: 0 2px 0 18px; + /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/ + color: red; +} + +.objectLink-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ + +.errorTitle { + margin-top: 0px; + margin-bottom: 1px; + padding-top: 2px; + padding-bottom: 2px; +} + +.errorTrace { + margin-left: 17px; +} + +.errorSourceBox { + margin: 2px 0; +} + +.errorSource-none { + display: none; +} + +.errorSource-syntax > .errorBreak { + visibility: hidden; +} + +.errorSource { + cursor: pointer; + font-family: Monaco, monospace; + color: DarkGreen; +} + +.errorSource:hover { + text-decoration: underline; +} + +.errorBreak { + cursor: pointer; + display: none; + margin: 0 6px 0 0; + width: 13px; + height: 14px; + vertical-align: bottom; + /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/ + opacity: 0.1; +} + +.hasBreakSwitch .errorBreak { + display: inline; +} + +.breakForError .errorBreak { + opacity: 1; +} + +.assertDescription { + margin: 0; +} + +/************************************************************************************************/ + +.logRow-profile > .logRow > .objectBox-text { + font-family: Lucida Grande, Tahoma, sans-serif; + color: #000000; +} + +.logRow-profile > .logRow > .objectBox-text:last-child { + color: #555555; + font-style: italic; +} + +.logRow-profile.opened > .logRow { + padding-bottom: 4px; +} + +.profilerRunning > .logRow { + /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/ + padding-left: 22px !important; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.profileSizer { + width:100%; + overflow-x:auto; + overflow-y: scroll; +} + +.profileTable { + border-bottom: 1px solid #D7D7D7; + padding: 0 0 4px 0; +} + +.profileTable tr[odd="1"] { + background-color: #F5F5F5; + vertical-align:middle; +} + +.profileTable a { + vertical-align:middle; +} + +.profileTable td { + padding: 1px 4px 0 4px; +} + +.headerCell { + cursor: pointer; + -moz-user-select: none; + border-bottom: 1px solid #9C9C9C; + padding: 0 !important; + font-weight: bold; + /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/ +} + +.headerCellBox { + padding: 2px 4px; + border-left: 1px solid #D9D9D9; + border-right: 1px solid #9C9C9C; +} + +.headerCell:hover:active { + /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/ +} + +.headerSorted { + /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/ +} + +.headerSorted > .headerCellBox { + border-right-color: #6B7C93; + /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/ +} + +.headerSorted.sortedAscending > .headerCellBox { + /*background-image: url(chrome://firebug/skin/arrowUp.png);*/ +} + +.headerSorted:hover:active { + /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/ +} + +.linkCell { + text-align: right; +} + +.linkCell > .objectLink-sourceLink { + position: static; +} + +/*****************************************************************************************/ + +.logRow-stackTrace { + padding-top: 0; + background: #f8f8f8; +} + +.logRow-stackTrace > .objectBox-stackFrame { + position: relative; + padding-top: 2px; +} + +/************************************************************************************************/ + +.objectLink-object { + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: DarkGreen; + white-space: pre-wrap; +} + +/* xxxpedro reps object representation .................................... */ +.objectProp-object { + color: DarkGreen; +} + +.objectProps { + color: #000; + font-weight: normal; +} + +.objectPropName { + /*font-style: italic;*/ + color: #777; +} + +/* +.objectProps .objectProp-string, +.objectProps .objectProp-number, +.objectProps .objectProp-object +{ + font-style: italic; +} +/**/ + +.objectProps .objectProp-string +{ + /*font-family: Monaco, monospace;*/ + color: #f55; +} +.objectProps .objectProp-number +{ + /*font-family: Monaco, monospace;*/ + color: #55a; +} +.objectProps .objectProp-object +{ + /*font-family: Lucida Grande,sans-serif;*/ + color: #585; +} +/* xxxpedro reps object representation .................................... */ + +/************************************************************************************************/ + +.selectorTag, +.selectorId, +.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +.selectorHidden > .selectorTag { + color: #5F82D9; +} + +.selectorHidden > .selectorId { + color: #888888; +} + +.selectorHidden > .selectorClass { + color: #D86060; +} + +.selectorValue { + font-family: Lucida Grande, sans-serif; + font-style: italic; + color: #555555; +} + +/*****************************************************************************************/ + +.panelNode.searching .logRow { + display: none; +} + +.logRow.matched { + display: block !important; +} + +.logRow.matching { + position: absolute; + left: -1000px; + top: -1000px; + max-width: 0; + max-height: 0; + overflow: hidden; +} + +/*****************************************************************************************/ + +.objectLeftBrace, +.objectRightBrace, +.objectEqual, +.objectComma, +.arrayLeftBracket, +.arrayRightBracket, +.arrayComma { + font-family: Monaco, monospace; +} + +.objectLeftBrace, +.objectRightBrace, +.arrayLeftBracket, +.arrayRightBracket { + font-weight: bold; +} + +.objectLeftBrace, +.arrayLeftBracket { + margin-right: 4px; +} + +.objectRightBrace, +.arrayRightBracket { + margin-left: 4px; +} + +/*****************************************************************************************/ + +.logRow-dir { + padding: 0; +} + +/************************************************************************************************/ + +/* +.logRow-errorMessage > .hasTwisty > .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup > .logRow +*/ +.logRow-errorMessage .hasTwisty .errorTitle, +.logRow-spy .spyHead .spyTitle, +.logGroup .logRow { + cursor: pointer; + padding-left: 18px; + background-repeat: no-repeat; + background-position: 3px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle { + background-position: 2px 3px; +} + +.logRow-errorMessage > .hasTwisty > .errorTitle:hover, +.logRow-spy .spyHead .spyTitle:hover, +.logGroup > .logRow:hover { + text-decoration: underline; +} + +/*****************************************************************************************/ + +.logRow-spy { + padding: 0 !important; +} + +.logRow-spy, +.logRow-spy .objectLink-sourceLink { + background: url(group.gif) repeat-x #FFFFFF; + padding-right: 4px; + right: 0; +} + +.logRow-spy.opened { + padding-bottom: 4px; + border-bottom: none; +} + +.spyTitle { + color: #000000; + font-weight: bold; + -moz-box-sizing: padding-box; + overflow: hidden; + z-index: 100; + padding-left: 18px; +} + +.spyCol { + padding: 0; + white-space: nowrap; + height: 16px; +} + +.spyTitleCol:hover > .objectLink-sourceLink, +.spyTitleCol:hover > .spyTime, +.spyTitleCol:hover > .spyStatus, +.spyTitleCol:hover > .spyTitle { + display: none; +} + +.spyFullTitle { + display: none; + -moz-user-select: none; + max-width: 100%; + background-color: Transparent; +} + +.spyTitleCol:hover > .spyFullTitle { + display: block; +} + +.spyStatus { + padding-left: 10px; + color: rgb(128, 128, 128); +} + +.spyTime { + margin-left:4px; + margin-right:4px; + color: rgb(128, 128, 128); +} + +.spyIcon { + margin-right: 4px; + margin-left: 4px; + width: 16px; + height: 16px; + vertical-align: middle; + background: transparent no-repeat 0 0; + display: none; +} + +.loading .spyHead .spyRow .spyIcon { + background-image: url(loading_16.gif); + display: block; +} + +.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon { + width: 0; + margin: 0; +} + +.logRow-spy.error .spyHead .spyRow .spyIcon { + background-image: url(errorIcon-sm.png); + display: block; + background-position: 2px 2px; +} + +.logRow-spy .spyHead .netInfoBody { + display: none; +} + +.logRow-spy.opened .spyHead .netInfoBody { + margin-top: 10px; + display: block; +} + +.logRow-spy.error .spyTitle, +.logRow-spy.error .spyStatus, +.logRow-spy.error .spyTime { + color: red; +} + +.logRow-spy.loading .spyResponseText { + font-style: italic; + color: #888888; +} + +/************************************************************************************************/ + +.caption { + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #444444; +} + +.warning { + padding: 10px; + font-family: Lucida Grande, Tahoma, sans-serif; + font-weight: bold; + color: #888888; +} + + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* DOM */ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + + +/* See license.txt for terms of usage */ + +.panelNode-dom { + overflow-x: hidden !important; +} + +.domTable { + font-size: 1em; + width: 100%; + table-layout: fixed; + background: #fff; +} + +.domTableIE { + width: auto; +} + +.memberLabelCell { + padding: 2px 0 2px 0; + vertical-align: top; +} + +.memberValueCell { + padding: 1px 0 1px 5px; + display: block; + overflow: hidden; +} + +.memberLabel { + display: block; + cursor: default; + -moz-user-select: none; + overflow: hidden; + /*position: absolute;*/ + padding-left: 18px; + /*max-width: 30%;*/ + /*white-space: nowrap;*/ + background-color: #FFFFFF; + text-decoration: none; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.memberRow.hasChildren .memberLabelCell .memberLabel:hover { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.userLabel { + color: #000000; + font-weight: bold; +} + +.userClassLabel { + color: #E90000; + font-weight: bold; +} + +.userFunctionLabel { + color: #025E2A; + font-weight: bold; +} + +.domLabel { + color: #000000; +} + +.domFunctionLabel { + color: #025E2A; +} + +.ordinalLabel { + color: SlateBlue; + font-weight: bold; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +.scopesRow { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 5px solid #BEBEBE; + color: #666666; +} +.scopesLabel { + background-color: LightYellow; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchEditCell { + padding: 2px 18px; + background-color: LightYellow; + border-bottom: 1px solid #BEBEBE; + color: #666666; +} + +.editor-watchNewRow, +.editor-memberRow { + font-family: Monaco, monospace !important; +} + +.editor-memberRow { + padding: 1px 0 !important; +} + +.editor-watchRow { + padding-bottom: 0 !important; +} + +.watchRow > .memberLabelCell { + font-family: Monaco, monospace; + padding-top: 1px; + padding-bottom: 1px; +} + +.watchRow > .memberLabelCell > .memberLabel { + background-color: transparent; +} + +.watchRow > .memberValueCell { + padding-top: 2px; + padding-bottom: 2px; +} + +.watchRow > .memberLabelCell, +.watchRow > .memberValueCell { + background-color: #F5F5F5; + border-bottom: 1px solid #BEBEBE; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.watchToolbox { + z-index: 2147483647; + position: absolute; + right: 0; + padding: 1px 2px; +} + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* FROM ORIGINAL FIREBUG */ + + + + +/************************************************************************************************ + CSS Not organized +*************************************************************************************************/ +#fbConsole { + overflow-x: hidden !important; +} + +#fbCSS { + font: 1em Monaco, monospace; + padding: 0 7px; +} + +#fbstylesheetButtons select, #fbScriptButtons select { + font: 11px Lucida Grande, Tahoma, sans-serif; + margin-top: 1px; + padding-left: 3px; + background: #fafafa; + border: 1px inset #fff; + width: 220px; + outline: none; +} + +.Selector { margin-top:10px } +.CSSItem {margin-left: 4% } +.CSSText { padding-left:20px; } +.CSSProperty { color:#005500; } +.CSSValue { padding-left:5px; color:#000088; } + + +/************************************************************************************************ + Not organized +*************************************************************************************************/ + +#fbHTMLStatusBar { + display: inline; +} + +.fbToolbarButtons { + display: none; +} + +.fbStatusSeparator{ + display: block; + float: left; + padding-top: 4px; +} + +#fbStatusBarBox { + display: none; +} + +#fbToolbarContent { + display: block; + position: absolute; + _position: absolute; + top: 0; + padding-top: 4px; + height: 23px; + clip: rect(0, 2048px, 27px, 0); +} + +.fbTabMenuTarget { + display: none !important; + float: left; + width: 10px; + height: 10px; + margin-top: 6px; + background: url(tabMenuTarget.png); +} + +.fbTabMenuTarget:hover { + background: url(tabMenuTargetHover.png); +} + +.fbShadow { + float: left; + background: url(shadowAlpha.png) no-repeat bottom right !important; + background: url(shadow2.gif) no-repeat bottom right; + margin: 10px 0 0 10px !important; + margin: 10px 0 0 5px; +} + +.fbShadowContent { + display: block; + position: relative; + background-color: #fff; + border: 1px solid #a9a9a9; + top: -6px; + left: -6px; +} + +.fbMenu { + display: none; + position: absolute; + font-size: 11px; + z-index: 2147483647; +} + +.fbMenuContent { + padding: 2px; +} + +.fbMenuSeparator { + display: block; + position: relative; + padding: 1px 18px 0; + text-decoration: none; + color: #000; + cursor: default; + background: #ACA899; + margin: 4px 0; +} + +.fbMenuOption +{ + display: block; + position: relative; + padding: 2px 18px; + text-decoration: none; + color: #000; + cursor: default; +} + +.fbMenuOption:hover +{ + color: #fff; + background: #316AC5; +} + +.fbMenuGroup { + background: transparent url(tabMenuPin.png) no-repeat right 0; +} + +.fbMenuGroup:hover { + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuGroupSelected { + color: #fff; + background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; +} + +.fbMenuChecked { + background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0; +} + +.fbMenuChecked:hover { + background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px; +} + +.fbMenuRadioSelected { + background: transparent url(tabMenuRadio.png) no-repeat 4px 0; +} + +.fbMenuRadioSelected:hover { + background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px; +} + +.fbMenuShortcut { + padding-right: 85px; +} + +.fbMenuShortcutKey { + position: absolute; + right: 0; + top: 2px; + width: 77px; +} + +#fbFirebugMenu { + top: 22px; + left: 0; +} + +.fbMenuDisabled { + color: #ACA899 !important; +} + +#fbFirebugSettingsMenu { + left: 245px; + top: 99px; +} + +#fbConsoleMenu { + top: 42px; + left: 48px; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; +} + +.fbIconButton { + display: block; + float: left; + height: 20px; + width: 20px; + color: #000; + margin-right: 2px; + text-decoration: none; + cursor: default; +} + +.fbIconButton:hover { + position: relative; + top: -1px; + left: -1px; + margin-right: 0; + _margin-right: 1px; + color: #333; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbIconPressed { + position: relative; + margin-right: 0; + _margin-right: 1px; + top: 0 !important; + left: 0 !important; + height: 19px; + color: #333 !important; + border: 1px solid #bbb !important; + border-bottom: 1px solid #cfcfcf !important; + border-right: 1px solid #ddd !important; +} + + + +/************************************************************************************************ + Error Popup +*************************************************************************************************/ +#fbErrorPopup { + position: absolute; + right: 0; + bottom: 0; + height: 19px; + width: 75px; + background: url(sprite.png) #f1f2ee 0 0; + z-index: 999; +} + +#fbErrorPopupContent { + position: absolute; + right: 0; + top: 1px; + height: 18px; + width: 75px; + _width: 74px; + border-left: 1px solid #aca899; +} + +#fbErrorIndicator { + position: absolute; + top: 2px; + right: 5px; +} + + + + + + + + + + +.fbBtnInspectActive { + background: #aaa; + color: #fff !important; +} + +/************************************************************************************************ + General +*************************************************************************************************/ +.fbBody { + margin: 0; + padding: 0; + overflow: hidden; + + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + background: #fff; +} + +.clear { + clear: both; +} + +/************************************************************************************************ + Mini Chrome +*************************************************************************************************/ +#fbMiniChrome { + display: none; + right: 0; + height: 27px; + background: url(sprite.png) #f1f2ee 0 0; + margin-left: 1px; +} + +#fbMiniContent { + display: block; + position: relative; + left: -1px; + right: 0; + top: 1px; + height: 25px; + border-left: 1px solid #aca899; +} + +#fbToolbarSearch { + float: right; + border: 1px solid #ccc; + margin: 0 5px 0 0; + background: #fff url(search.png) no-repeat 4px 2px !important; + background: #fff url(search.gif) no-repeat 4px 2px; + padding-left: 20px; + font-size: 11px; +} + +#fbToolbarErrors { + float: right; + margin: 1px 4px 0 0; + font-size: 11px; +} + +#fbLeftToolbarErrors { + float: left; + margin: 7px 0px 0 5px; + font-size: 11px; +} + +.fbErrors { + padding-left: 20px; + height: 14px; + background: url(errorIcon.png) no-repeat !important; + background: url(errorIcon.gif) no-repeat; + color: #f00; + font-weight: bold; +} + +#fbMiniErrors { + display: inline; + display: none; + float: right; + margin: 5px 2px 0 5px; +} + +#fbMiniIcon { + float: right; + margin: 3px 4px 0; + height: 20px; + width: 20px; + float: right; + background: url(sprite.png) 0 -135px; + cursor: pointer; +} + + +/************************************************************************************************ + Master Layout +*************************************************************************************************/ +#fbChrome { + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + position: absolute; + _position: static; + top: 0; + left: 0; + height: 100%; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + background: #fff; + overflow: hidden; +} + +#fbChrome > tbody > tr > td { + padding: 0; +} + +#fbTop { + height: 49px; +} + +#fbToolbar { + background: url(sprite.png) #f1f2ee 0 0; + height: 27px; + font-size: 11px; +} + +#fbPanelBarBox { + background: url(sprite.png) #dbd9c9 0 -27px; + height: 22px; +} + +#fbContent { + height: 100%; + vertical-align: top; +} + +#fbBottom { + height: 18px; + background: #fff; +} + +/************************************************************************************************ + Sub-Layout +*************************************************************************************************/ + +/* fbToolbar +*************************************************************************************************/ +#fbToolbarIcon { + float: left; + padding: 0 5px 0; +} + +#fbToolbarIcon a { + background: url(sprite.png) 0 -135px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} + +#fbToolbarButtons { + padding: 0 2px 0 5px; +} +/* +#fbStatusBarBox a { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 5px; + margin: 0 0 0 1px; + cursor: default; +} + +#fbStatusBarBox a:hover { + color: #333; + padding: 3px 4px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} +/**/ + +.fbButton { + text-decoration: none; + display: block; + float: left; + color: #000; + padding: 4px 6px 4px 7px; + cursor: default; +} + +.fbButton:hover { + color: #333; + background: #f5f5ef url(buttonBg.png); + padding: 3px 5px 3px 6px; + border: 1px solid #fff; + border-bottom: 1px solid #bbb; + border-right: 1px solid #bbb; +} + +.fbBtnPressed { + background: #e3e3db url(buttonBgHover.png) !important; + padding: 3px 4px 2px 6px !important; + margin: 1px 0 0 1px !important; + border: 1px solid #ACA899 !important; + border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; +} + +#fbStatusBarBox { + top: 4px; + cursor: default; +} + +.fbToolbarSeparator { + overflow: hidden; + border: 1px solid; + border-color: transparent #fff transparent #777; + _border-color: #eee #fff #eee #777; + height: 7px; + margin: 6px 3px; + float: left; +} + +.fbBtnSelected { + font-weight: bold; +} + +.fbStatusBar { + color: #aca899; +} + +.fbStatusBar a { + text-decoration: none; + color: black; +} + +.fbStatusBar a:hover { + color: blue; + cursor: pointer; +} + + +#fbWindowButtons { + position: absolute; + white-space: nowrap; + right: 0; + top: 0; + height: 17px; + width: 48px; + padding: 5px; + z-index: 6; + background: url(sprite.png) #f1f2ee 0 0; +} + +/* fbPanelBarBox +*************************************************************************************************/ + +#fbPanelBar1 { + width: 1024px; /* fixed width to avoid tabs breaking line */ + z-index: 8; + left: 0; + white-space: nowrap; + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + left: 4px; +} + +#fbPanelBar2Box { + background: url(sprite.png) #dbd9c9 0 -27px; + position: absolute; + height: 22px; + width: 300px; /* fixed width to avoid tabs breaking line */ + z-index: 9; + right: 0; +} + +#fbPanelBar2 { + position: absolute; + width: 290px; /* fixed width to avoid tabs breaking line */ + height: 22px; + padding-left: 4px; +} + +/* body +*************************************************************************************************/ +.fbPanel { + display: none; +} + +#fbPanelBox1, #fbPanelBox2 { + max-height: inherit; + height: 100%; + font-size: 1em; +} + +#fbPanelBox2 { + background: #fff; +} + +#fbPanelBox2 { + width: 300px; + background: #fff; +} + +#fbPanel2 { + margin-left: 6px; + background: #fff; +} + +#fbLargeCommandLine { + display: none; + position: absolute; + z-index: 9; + top: 27px; + right: 0; + width: 294px; + height: 201px; + border-width: 0; + margin: 0; + padding: 2px 0 0 2px; + resize: none; + outline: none; + font-size: 11px; + overflow: auto; + border-top: 1px solid #B9B7AF; + _right: -1px; + _border-left: 1px solid #fff; +} + +#fbLargeCommandButtons { + display: none; + background: #ECE9D8; + bottom: 0; + right: 0; + width: 294px; + height: 21px; + padding-top: 1px; + position: fixed; + border-top: 1px solid #ACA899; + z-index: 9; +} + +#fbSmallCommandLineIcon { + background: url(down.png) no-repeat; + position: absolute; + right: 2px; + bottom: 3px; + + z-index: 99; +} + +#fbSmallCommandLineIcon:hover { + background: url(downHover.png) no-repeat; +} + +.hide { + overflow: hidden !important; + position: fixed !important; + display: none !important; + visibility: hidden !important; +} + +/* fbBottom +*************************************************************************************************/ + +#fbCommand { + height: 18px; +} + +#fbCommandBox { + position: fixed; + _position: absolute; + width: 100%; + height: 18px; + bottom: 0; + overflow: hidden; + z-index: 9; + background: #fff; + border: 0; + border-top: 1px solid #ccc; +} + +#fbCommandIcon { + position: absolute; + color: #00f; + top: 2px; + left: 6px; + display: inline; + font: 11px Monaco, monospace; + z-index: 10; +} + +#fbCommandLine { + position: absolute; + width: 100%; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 2px 0 2px 32px; + font: 11px Monaco, monospace; + z-index: 9; + outline: none; +} + +#fbLargeCommandLineIcon { + background: url(up.png) no-repeat; + position: absolute; + right: 1px; + bottom: 1px; + z-index: 10; +} + +#fbLargeCommandLineIcon:hover { + background: url(upHover.png) no-repeat; +} + +div.fbFitHeight { + overflow: auto; + position: relative; +} + + +/************************************************************************************************ + Layout Controls +*************************************************************************************************/ + +/* fbToolbar buttons +*************************************************************************************************/ +.fbSmallButton { + overflow: hidden; + width: 16px; + height: 16px; + display: block; + text-decoration: none; + cursor: default; +} + +#fbWindowButtons .fbSmallButton { + float: right; +} + +#fbWindow_btClose { + background: url(min.png); +} + +#fbWindow_btClose:hover { + background: url(minHover.png); +} + +#fbWindow_btDetach { + background: url(detach.png); +} + +#fbWindow_btDetach:hover { + background: url(detachHover.png); +} + +#fbWindow_btDeactivate { + background: url(off.png); +} + +#fbWindow_btDeactivate:hover { + background: url(offHover.png); +} + + +/* fbPanelBarBox tabs +*************************************************************************************************/ +.fbTab { + text-decoration: none; + display: none; + float: left; + width: auto; + float: left; + cursor: default; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + font-weight: bold; + height: 22px; + color: #565656; +} + +.fbPanelBar span { + /*display: block; TODO: safe to remove this? */ + float: left; +} + +.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { + height: 22px; + width: 8px; +} + +.fbPanelBar .fbTabText { + padding: 4px 1px 0; +} + +a.fbTab:hover { + background: url(sprite.png) 0 -73px; +} + +a.fbTab:hover .fbTabL { + background: url(sprite.png) -16px -96px; +} + +a.fbTab:hover .fbTabR { + background: url(sprite.png) -24px -96px; +} + +.fbSelectedTab { + background: url(sprite.png) #f1f2ee 0 -50px !important; + color: #000; +} + +.fbSelectedTab .fbTabL { + background: url(sprite.png) 0 -96px !important; +} + +.fbSelectedTab .fbTabR { + background: url(sprite.png) -8px -96px !important; +} + +/* splitters +*************************************************************************************************/ +#fbHSplitter { + position: fixed; + _position: absolute; + left: 0; + top: 0; + width: 100%; + height: 5px; + overflow: hidden; + cursor: n-resize !important; + background: url(pixel_transparent.gif); + z-index: 9; +} + +#fbHSplitter.fbOnMovingHSplitter { + height: 100%; + z-index: 100; +} + +.fbVSplitter { + background: #ece9d8; + color: #000; + border: 1px solid #716f64; + border-width: 0 1px; + border-left-color: #aca899; + width: 4px; + cursor: e-resize; + overflow: hidden; + right: 294px; + text-decoration: none; + z-index: 10; + position: absolute; + height: 100%; + top: 27px; +} + +/************************************************************************************************/ +div.lineNo { + font: 1em Monaco, monospace; + position: relative; + float: left; + top: 0; + left: 0; + margin: 0 5px 0 0; + padding: 0 5px 0 10px; + background: #eee; + color: #888; + border-right: 1px solid #ccc; + text-align: right; +} + +.sourceBox { + position: absolute; +} + +.sourceCode { + font: 1em Monaco, monospace; + overflow: hidden; + white-space: pre; + display: inline; +} + +/************************************************************************************************/ +.nodeControl { + margin-top: 3px; + margin-left: -14px; + float: left; + width: 9px; + height: 9px; + overflow: hidden; + cursor: default; + background: url(tree_open.gif); + _float: none; + _display: inline; + _position: absolute; +} + +div.nodeMaximized { + background: url(tree_close.gif); +} + +div.objectBox-element { + padding: 1px 3px; +} +.objectBox-selector{ + cursor: default; +} + +.selectedElement{ + background: highlight; + /* background: url(roundCorner.svg); Opera */ + color: #fff !important; +} +.selectedElement span{ + color: #fff !important; +} + +/* IE6 need this hack */ +* html .selectedElement { + position: relative; +} + +/* Webkit CSS Hack - bug in "highlight" named color */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .selectedElement{ + background: #316AC5; + color: #fff !important; + } +} + +/************************************************************************************************/ +/************************************************************************************************/ +.logRow * { + font-size: 1em; +} + +/* TODO: remove this? */ +/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to +position. if so, override it at chrome.js initialization when creating the div */ +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + zbackground-color: #FFFFFF; +} +/**/ + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-string, +.objectBox-text, +.objectBox-number, +.objectBox-function, +.objectLink-element, +.objectLink-textNode, +.objectLink-function, +.objectBox-stackTrace, +.objectLink-profile { + font-family: Monaco, monospace; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + color: red; + + /* TODO: xxxpedro make long strings break line */ + /*white-space: pre; */ +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; + font-family: Lucida Grande, sans-serif; +} + +.objectBox-array { + color: #000; +} + +/************************************************************************************************/ +.logRow-info,.logRow-error,.logRow-warn { + background: #fff no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png) !important; + background-image: url(infoIcon.gif); +} + +.logRow-warn { + background-color: cyan; + background-image: url(warningIcon.png) !important; + background-image: url(warningIcon.gif); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png) !important; + background-image: url(errorIcon.gif); + color: #f00; +} + +.errorMessage { + vertical-align: top; + color: #f00; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ +/* +//TODO: remove this when console2 is finished +*/ +/* +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +}/**/ + +/************************************************************************************************/ +.selectorTag,.selectorId,.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + padding-left: 26px; +} + +.nodeTag { + color: blue; + cursor: pointer; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText,.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; + font-family: Monaco, monospace; +} + +.nodeComment { + color: DarkGreen; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +.nodeHidden, .nodeHidden * { + color: #888888; +} + +.nodeHidden .nodeTag { + color: #5F82D9; +} + +.nodeHidden .nodeValue { + color: #D86060; +} + +.selectedElement .nodeHidden, .selectedElement .nodeHidden * { + color: SkyBlue !important; +} + + +/************************************************************************************************/ +.log-object { + /* + _position: relative; + _height: 100%; + /**/ +} + +.property { + position: relative; + clear: both; + height: 15px; +} + +.propertyNameCell { + vertical-align: top; + float: left; + width: 28%; + position: absolute; + left: 0; + z-index: 0; +} + +.propertyValueCell { + float: right; + width: 68%; + background: #fff; + position: absolute; + padding-left: 5px; + display: table-cell; + right: 0; + z-index: 1; + /* + _position: relative; + /**/ +} + +.propertyName { + font-weight: bold; +} + +.FirebugPopup { + height: 100% !important; +} + +.FirebugPopup #fbWindowButtons { + display: none !important; +} + +.FirebugPopup #fbHSplitter { + display: none !important; +} diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.html b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.html new file mode 100755 index 0000000..4432a32 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.html @@ -0,0 +1,213 @@ + + + + +Firebug Lite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + +
      +   +   +   +
      + + +
      +
      + + + +   + + + + + + + + + Inspect + + + + + Clear + + + + + + + + + + + + + +
      + +
      + + + + + +
       
      + +
      +
      +
      +
      +
      +
      + + +
       
      + + +
      + + +
      +
      +
      + +
      + + + + + +
      + Run + Clear + + +
      + +
      +
      +
      >>>
      + + +
      +
      + + + + 2 errors + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.png new file mode 100755 index 0000000..e10affe Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/firebug.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/group.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/group.gif new file mode 100755 index 0000000..8db97c2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/group.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/infoIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/infoIcon.gif new file mode 100755 index 0000000..0618e20 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/infoIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/infoIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/infoIcon.png new file mode 100755 index 0000000..da1e533 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/infoIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/loading_16.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/loading_16.gif new file mode 100755 index 0000000..085ccae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/loading_16.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/min.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/min.png new file mode 100755 index 0000000..1034d66 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/min.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/minHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/minHover.png new file mode 100755 index 0000000..b0d1e1a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/minHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/off.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/off.png new file mode 100755 index 0000000..b70b1d2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/off.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/offHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/offHover.png new file mode 100755 index 0000000..f3670f1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/offHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/pixel_transparent.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/pixel_transparent.gif new file mode 100755 index 0000000..6865c96 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/pixel_transparent.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/roundCorner.svg b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/roundCorner.svg new file mode 100755 index 0000000..be0291f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/roundCorner.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/search.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/search.gif new file mode 100755 index 0000000..2a62098 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/search.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/search.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/search.png new file mode 100755 index 0000000..fba33b8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/search.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadow.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadow.gif new file mode 100755 index 0000000..af7f537 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadow.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadow2.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadow2.gif new file mode 100755 index 0000000..099cbf3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadow2.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadowAlpha.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadowAlpha.png new file mode 100755 index 0000000..a2561df Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/shadowAlpha.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/sprite.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/sprite.png new file mode 100755 index 0000000..33d2c4d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/sprite.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverLeft.png new file mode 100755 index 0000000..0fb24d0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverMid.png new file mode 100755 index 0000000..fbccab5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverRight.png new file mode 100755 index 0000000..3db0f36 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabHoverRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabLeft.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabLeft.png new file mode 100755 index 0000000..a6cc9e9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabLeft.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuCheckbox.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuCheckbox.png new file mode 100755 index 0000000..4726e62 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuCheckbox.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuPin.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuPin.png new file mode 100755 index 0000000..eb4b11e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuPin.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuRadio.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuRadio.png new file mode 100755 index 0000000..55b982d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuRadio.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuTarget.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuTarget.png new file mode 100755 index 0000000..957bd9f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuTarget.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuTargetHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuTargetHover.png new file mode 100755 index 0000000..200a370 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMenuTargetHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMid.png new file mode 100755 index 0000000..68986c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabRight.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabRight.png new file mode 100755 index 0000000..5011307 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tabRight.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorBorders.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorBorders.gif new file mode 100755 index 0000000..0ee5497 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorBorders.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorBorders.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorBorders.png new file mode 100755 index 0000000..21682c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorBorders.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorCorners.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorCorners.gif new file mode 100755 index 0000000..04f8421 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorCorners.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorCorners.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorCorners.png new file mode 100755 index 0000000..a0f839d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/textEditorCorners.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/titlebarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/titlebarMid.png new file mode 100755 index 0000000..10998ae Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/titlebarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/toolbarMid.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/toolbarMid.png new file mode 100755 index 0000000..aa21dee Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/toolbarMid.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tree_close.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tree_close.gif new file mode 100755 index 0000000..e26728a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tree_close.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tree_open.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tree_open.gif new file mode 100755 index 0000000..edf662f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/tree_open.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/up.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/up.png new file mode 100755 index 0000000..2174d03 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/up.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/upActive.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/upActive.png new file mode 100755 index 0000000..236cf67 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/upActive.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/upHover.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/upHover.png new file mode 100755 index 0000000..cd81317 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/upHover.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/warningIcon.gif b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/warningIcon.gif new file mode 100755 index 0000000..8497278 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/warningIcon.gif differ diff --git a/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/warningIcon.png b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/warningIcon.png new file mode 100755 index 0000000..de51084 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/lib/firebug-lite/skin/xp/warningIcon.png differ diff --git a/php/kindeditor_demo/kindeditor/lib/jquery.min.js b/php/kindeditor_demo/kindeditor/lib/jquery.min.js new file mode 100755 index 0000000..16ad06c --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.2 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
      a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="
      "+""+"
      ",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="
      t
      ",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
      ",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( +a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

      ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
      ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
      ","
      "]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f +.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
      ").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/lib/qunit/qunit.css b/php/kindeditor_demo/kindeditor/lib/qunit/qunit.css new file mode 100755 index 0000000..b3c6db5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/qunit/qunit.css @@ -0,0 +1,225 @@ +/** + * QUnit - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2011 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699a4; + background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; + + border-radius: 15px 15px 0 0; + -moz-border-radius: 15px 15px 0 0; + -webkit-border-top-right-radius: 15px; + -webkit-border-top-left-radius: 15px; +} + +#qunit-header a { + text-decoration: none; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #eee; +} + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2b81af; + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #fff; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests ol { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #fff; + + border-radius: 15px; + -moz-border-radius: 15px; + -webkit-border-radius: 15px; + + box-shadow: inset 0px 2px 13px #999; + -moz-box-shadow: inset 0px 2px 13px #999; + -webkit-box-shadow: inset 0px 2px 13px #999; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + margin: 0.5em; + padding: 0.4em 0.5em 0.4em 0.5em; + background-color: #fff; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #5E740B; + background-color: #fff; + border-left: 26px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #fff; + border-left: 26px solid #EE5757; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 15px 15px; + -moz-border-radius: 0 0 15px 15px; + -webkit-border-bottom-right-radius: 15px; + -webkit-border-bottom-left-radius: 15px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; +} diff --git a/php/kindeditor_demo/kindeditor/lib/qunit/qunit.js b/php/kindeditor_demo/kindeditor/lib/qunit/qunit.js new file mode 100755 index 0000000..9ca4b91 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/lib/qunit/qunit.js @@ -0,0 +1,1448 @@ +/** + * QUnit - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2011 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +(function(window) { + +var defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + try { + return !!sessionStorage.getItem; + } catch(e){ + return false; + } + })() +}; + +var testId = 0; + +var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { + this.name = name; + this.testName = testName; + this.expected = expected; + this.testEnvironmentArg = testEnvironmentArg; + this.async = async; + this.callback = callback; + this.assertions = []; +}; +Test.prototype = { + init: function() { + var tests = id("qunit-tests"); + if (tests) { + var b = document.createElement("strong"); + b.innerHTML = "Running " + this.name; + var li = document.createElement("li"); + li.appendChild( b ); + li.className = "running"; + li.id = this.id = "test-output" + testId++; + tests.appendChild( li ); + } + }, + setup: function() { + if (this.module != config.previousModule) { + if ( config.previousModule ) { + QUnit.moduleDone( { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + } ); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + QUnit.moduleStart( { + name: this.module + } ); + } + + config.current = this; + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment); + if (this.testEnvironmentArg) { + extend(this.testEnvironment, this.testEnvironmentArg); + } + + QUnit.testStart( { + name: this.testName + } ); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + try { + if ( !config.pollution ) { + saveGlobal(); + } + + this.testEnvironment.setup.call(this.testEnvironment); + } catch(e) { + QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); + } + }, + run: function() { + if ( this.async ) { + QUnit.stop(); + } + + if ( config.notrycatch ) { + this.callback.call(this.testEnvironment); + return; + } + //try { + this.callback.call(this.testEnvironment); + /*} catch(e) { + fail("Test " + this.testName + " died, exception and test follows", e, this.callback); + QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + start(); + } + }*/ + }, + teardown: function() { + try { + this.testEnvironment.teardown.call(this.testEnvironment); + checkPollution(); + } catch(e) { + QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); + } + }, + finish: function() { + if ( this.expected && this.expected != this.assertions.length ) { + QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); + } + + var good = 0, bad = 0, + tests = id("qunit-tests"); + + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + var ol = document.createElement("ol"); + + for ( var i = 0; i < this.assertions.length; i++ ) { + var assertion = this.assertions[i]; + + var li = document.createElement("li"); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if (bad) { + sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); + } else { + sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); + } + } + + if (bad == 0) { + ol.style.display = "none"; + } + + var b = document.createElement("strong"); + b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + var a = document.createElement("a"); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); + + addEvent(b, "click", function() { + var next = b.nextSibling.nextSibling, + display = next.style.display; + next.style.display = display === "none" ? "block" : "none"; + }); + + addEvent(b, "dblclick", function(e) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); + } + }); + + var li = id(this.id); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( ol ); + + } else { + for ( var i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + try { + QUnit.reset(); + } catch(e) { + fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); + } + + QUnit.testDone( { + name: this.testName, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length + } ); + }, + + queue: function() { + var test = this; + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + // defer when previous test run passed, if storage is available + var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); + if (bad) { + run(); + } else { + synchronize(run); + }; + } + +}; + +var QUnit = { + + // call on start of module test to prepend name to all tests + module: function(name, testEnvironment) { + config.currentModule = name; + config.currentModuleTestEnviroment = testEnvironment; + }, + + asyncTest: function(testName, expected, callback) { + if ( arguments.length === 2 ) { + callback = expected; + expected = 0; + } + + QUnit.test(testName, expected, callback, true); + }, + + test: function(testName, expected, callback, async) { + var name = '' + testName + '', testEnvironmentArg; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + // is 2nd argument a testEnvironment? + if ( expected && typeof expected === 'object') { + testEnvironmentArg = expected; + expected = null; + } + + if ( config.currentModule ) { + name = '' + config.currentModule + ": " + name; + } + + if ( !validTest(config.currentModule + ": " + testName) ) { + return; + } + + var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); + test.module = config.currentModule; + test.moduleTestEnvironment = config.currentModuleTestEnviroment; + test.queue(); + }, + + /** + * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + */ + expect: function(asserts) { + config.current.expected = asserts; + }, + + /** + * Asserts true. + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function(a, msg) { + a = !!a; + var details = { + result: a, + message: msg + }; + msg = escapeHtml(msg); + QUnit.log(details); + config.current.assertions.push({ + result: a, + message: msg + }); + }, + + /** + * Checks that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * + * Prefered to ok( actual == expected, message ) + * + * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); + * + * @param Object actual + * @param Object expected + * @param String message (optional) + */ + equal: function(actual, expected, message) { + QUnit.push(expected == actual, actual, expected, message); + }, + + notEqual: function(actual, expected, message) { + QUnit.push(expected != actual, actual, expected, message); + }, + + deepEqual: function(actual, expected, message) { + QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); + }, + + notDeepEqual: function(actual, expected, message) { + QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); + }, + + strictEqual: function(actual, expected, message) { + QUnit.push(expected === actual, actual, expected, message); + }, + + notStrictEqual: function(actual, expected, message) { + QUnit.push(expected !== actual, actual, expected, message); + }, + + raises: function(block, expected, message) { + var actual, ok = false; + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + if (actual) { + // we don't want to validate thrown error + if (!expected) { + ok = true; + // expected is a regexp + } else if (QUnit.objectType(expected) === "regexp") { + ok = expected.test(actual); + // expected is a constructor + } else if (actual instanceof expected) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if (expected.call({}, actual) === true) { + ok = true; + } + } + + QUnit.ok(ok, message); + }, + + start: function() { + config.semaphore--; + if (config.semaphore > 0) { + // don't start until equal number of stop-calls + return; + } + if (config.semaphore < 0) { + // ignore if start is called more often then stop + config.semaphore = 0; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.timeout ) { + clearTimeout(config.timeout); + } + + config.blocking = false; + process(); + }, 13); + } else { + config.blocking = false; + process(); + } + }, + + stop: function(timeout) { + config.semaphore++; + config.blocking = true; + + if ( timeout && defined.setTimeout ) { + clearTimeout(config.timeout); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + QUnit.start(); + }, timeout); + } + } +}; + +// Backwards compatibility, deprecated +QUnit.equals = QUnit.equal; +QUnit.same = QUnit.deepEqual; + +// Maintain internal state +var config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + noglobals: false, + notrycatch: false +}; + +// Load paramaters +(function() { + var location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( var i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + if ( current[ 0 ] in config ) { + config[ current[ 0 ] ] = current[ 1 ]; + } + } + } + + QUnit.urlParams = urlParams; + config.filter = urlParams.filter; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = !!(location.protocol === 'file:'); +})(); + +// Expose the API as global variables, unless an 'exports' +// object exists, in that case we assume we're in CommonJS +if ( typeof exports === "undefined" || typeof require === "undefined" ) { + extend(window, QUnit); + window.QUnit = QUnit; +} else { + extend(exports, QUnit); + exports.QUnit = QUnit; +} + +// define these after exposing globals to keep them in these QUnit namespace only +extend(QUnit, { + config: config, + + // Initialize the configuration options + init: function() { + extend(config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date, + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 0 + }); + + var tests = id( "qunit-tests" ), + banner = id( "qunit-banner" ), + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = 'Running...
       '; + } + }, + + /** + * Resets the test setup. Useful for tests that modify the DOM. + * + * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. + */ + reset: function() { + if ( window.jQuery ) { + jQuery( "#qunit-fixture" ).html( config.fixture ); + } else { + var main = id( 'qunit-fixture' ); + if ( main ) { + main.innerHTML = config.fixture; + } + } + }, + + /** + * Trigger an event on an element. + * + * @example triggerEvent( document.body, "click" ); + * + * @param DOMElement elem + * @param String type + */ + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent("MouseEvents"); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + elem.dispatchEvent( event ); + + } else if ( elem.fireEvent ) { + elem.fireEvent("on"+type); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) == type; + }, + + objectType: function( obj ) { + if (typeof obj === "undefined") { + return "undefined"; + + // consider: typeof null === object + } + if (obj === null) { + return "null"; + } + + var type = Object.prototype.toString.call( obj ) + .match(/^\[object\s(.*)\]$/)[1] || ''; + + switch (type) { + case 'Number': + if (isNaN(obj)) { + return "nan"; + } else { + return "number"; + } + case 'String': + case 'Boolean': + case 'Array': + case 'Date': + case 'RegExp': + case 'Function': + return type.toLowerCase(); + } + if (typeof obj === "object") { + return "object"; + } + return undefined; + }, + + push: function(result, actual, expected, message) { + var details = { + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeHtml(message) || (result ? "okay" : "failed"); + message = '' + message + ""; + expected = escapeHtml(QUnit.jsDump.parse(expected)); + actual = escapeHtml(QUnit.jsDump.parse(actual)); + var output = message + '
      '; + if (actual != expected) { + output += ''; + output += ''; + } + if (!result) { + var source = sourceFromStacktrace(); + if (source) { + details.source = source; + output += ''; + } + } + output += "
      Expected:
      ' + expected + '
      Result:
      ' + actual + '
      Diff:
      ' + QUnit.diff(expected, actual) +'
      Source:
      ' + escapeHtml(source) + '
      "; + + QUnit.log(details); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var querystring = "?", + key; + for ( key in params ) { + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.pathname + querystring.slice( 0, -1 ); + }, + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: function() {}, + // done: { failed, passed, total, runtime } + done: function() {}, + // log: { result, actual, expected, message } + log: function() {}, + // testStart: { name } + testStart: function() {}, + // testDone: { name, failed, passed, total } + testDone: function() {}, + // moduleStart: { name } + moduleStart: function() {}, + // moduleDone: { name, failed, passed, total } + moduleDone: function() {} +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +addEvent(window, "load", function() { + QUnit.begin({}); + + // Initialize the config, saving the execution queue + var oldconfig = extend({}, config); + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + var userAgent = id("qunit-userAgent"); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + var banner = id("qunit-header"); + if ( banner ) { + banner.innerHTML = ' ' + banner.innerHTML + ' ' + + '' + + ''; + addEvent( banner, "change", function( event ) { + var params = {}; + params[ event.target.name ] = event.target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + } + + var toolbar = id("qunit-testrunner-toolbar"); + if ( toolbar ) { + var filter = document.createElement("input"); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + addEvent( filter, "click", function() { + var ol = document.getElementById("qunit-tests"); + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace(/ hidepass /, " "); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem("qunit-filter-passed-tests", "true"); + } else { + sessionStorage.removeItem("qunit-filter-passed-tests"); + } + } + }); + if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { + filter.checked = true; + var ol = document.getElementById("qunit-tests"); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + var label = document.createElement("label"); + label.setAttribute("for", "qunit-filter-pass"); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + } + + var main = id('qunit-fixture'); + if ( main ) { + config.fixture = main.innerHTML; + } + + if (config.autostart) { + QUnit.start(); + } +}); + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + QUnit.moduleDone( { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + } ); + } + + var banner = id("qunit-banner"), + tests = id("qunit-tests"), + runtime = +new Date - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + 'Tests completed in ', + runtime, + ' milliseconds.
      ', + '', + passed, + ' tests of ', + config.stats.all, + ' passed, ', + config.stats.bad, + ' failed.' + ].join(''); + + if ( banner ) { + banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = (config.stats.bad ? "\u2716" : "\u2714") + " " + document.title; + } + + QUnit.done( { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + } ); +} + +function validTest( name ) { + var filter = config.filter, + run = false; + + if ( !filter ) { + return true; + } + + var not = filter.charAt( 0 ) === "!"; + if ( not ) { + filter = filter.slice( 1 ); + } + + if ( name.indexOf( filter ) !== -1 ) { + return !not; + } + + if ( not ) { + run = true; + } + + return run; +} + +// so far supports only Firefox, Chrome and Opera (buggy) +// could be extended in the future to use something like https://github.com/csnover/TraceKit +function sourceFromStacktrace() { + try { + throw new Error(); + } catch ( e ) { + if (e.stacktrace) { + // Opera + return e.stacktrace.split("\n")[6]; + } else if (e.stack) { + // Firefox, Chrome + return e.stack.split("\n")[4]; + } + } +} + +function escapeHtml(s) { + if (!s) { + return ""; + } + s = s + ""; + return s.replace(/[\&"<>\\]/g, function(s) { + switch(s) { + case "&": return "&"; + case "\\": return "\\\\"; + case '"': return '\"'; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); +} + +function synchronize( callback ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process(); + } +} + +function process() { + var start = (new Date()).getTime(); + + while ( config.queue.length && !config.blocking ) { + if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { + config.queue.shift()(); + } else { + window.setTimeout( process, 13 ); + break; + } + } + if (!config.blocking && !config.queue.length) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + config.pollution.push( key ); + } + } +} + +function checkPollution( name ) { + var old = config.pollution; + saveGlobal(); + + var newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + var deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var result = a.slice(); + for ( var i = 0; i < result.length; i++ ) { + for ( var j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice(i, 1); + i--; + break; + } + } + } + return result; +} + +function fail(message, exception, callback) { + if ( typeof console !== "undefined" && console.error && console.warn ) { + console.error(message); + console.error(exception); + console.warn(callback.toString()); + + } else if ( window.opera && opera.postError ) { + opera.postError(message, exception, callback.toString); + } +} + +function extend(a, b) { + for ( var prop in b ) { + if ( b[prop] === undefined ) { + delete a[prop]; + } else { + a[prop] = b[prop]; + } + } + + return a; +} + +function addEvent(elem, type, fn) { + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, fn ); + } else { + fn(); + } +} + +function id(name) { + return !!(typeof document !== "undefined" && document && document.getElementById) && + document.getElementById( name ); +} + +// Test for equality any JavaScript type. +// Discussions and reference: http://philrathe.com/articles/equiv +// Test suites: http://philrathe.com/tests/equiv +// Author: Philippe Rathé +QUnit.equiv = function () { + + var innerEquiv; // the real equiv function + var callers = []; // stack to decide between skip/abort functions + var parents = []; // stack to avoiding loops from circular referencing + + // Call the o related callback with the given arguments. + function bindCallbacks(o, callbacks, args) { + var prop = QUnit.objectType(o); + if (prop) { + if (QUnit.objectType(callbacks[prop]) === "function") { + return callbacks[prop].apply(callbacks, args); + } else { + return callbacks[prop]; // or undefined + } + } + } + + var callbacks = function () { + + // for string, boolean, number and null + function useStrictEquality(b, a) { + if (b instanceof a.constructor || a instanceof b.constructor) { + // to catch short annotaion VS 'new' annotation of a declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function (b) { + return isNaN(b); + }, + + "date": function (b, a) { + return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function (b, a) { + return QUnit.objectType(b) === "regexp" && + a.source === b.source && // the regex itself + a.global === b.global && // and its modifers (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function () { + var caller = callers[callers.length - 1]; + return caller !== Object && + typeof caller !== "undefined"; + }, + + "array": function (b, a) { + var i, j, loop; + var len; + + // b could be an object literal here + if ( ! (QUnit.objectType(b) === "array")) { + return false; + } + + len = a.length; + if (len !== b.length) { // safe and faster + return false; + } + + //track reference to avoid circular references + parents.push(a); + for (i = 0; i < len; i++) { + loop = false; + for(j=0;j= 0) { + type = "array"; + } else { + type = typeof obj; + } + return type; + }, + separator:function() { + return this.multiline ? this.HTML ? '
      ' : '\n' : this.HTML ? ' ' : ' '; + }, + indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing + if ( !this.multiline ) + return ''; + var chr = this.indentChar; + if ( this.HTML ) + chr = chr.replace(/\t/g,' ').replace(/ /g,' '); + return Array( this._depth_ + (extra||0) ).join(chr); + }, + up:function( a ) { + this._depth_ += a || 1; + }, + down:function( a ) { + this._depth_ -= a || 1; + }, + setParser:function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote:quote, + literal:literal, + join:join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers:{ + window: '[Window]', + document: '[Document]', + error:'[ERROR]', //when no parser is found, shouldn't happen + unknown: '[Unknown]', + 'null':'null', + 'undefined':'undefined', + 'function':function( fn ) { + var ret = 'function', + name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE + if ( name ) + ret += ' ' + name; + ret += '('; + + ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); + return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); + }, + array: array, + nodelist: array, + arguments: array, + object:function( map ) { + var ret = [ ]; + QUnit.jsDump.up(); + for ( var key in map ) + ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); + QUnit.jsDump.down(); + return join( '{', ret, '}' ); + }, + node:function( node ) { + var open = QUnit.jsDump.HTML ? '<' : '<', + close = QUnit.jsDump.HTML ? '>' : '>'; + + var tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for ( var a in QUnit.jsDump.DOMAttrs ) { + var val = node[QUnit.jsDump.DOMAttrs[a]]; + if ( val ) + ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); + } + return ret + close + open + '/' + tag + close; + }, + functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function + var l = fn.length; + if ( !l ) return ''; + + var args = Array(l); + while ( l-- ) + args[l] = String.fromCharCode(97+l);//97 is 'a' + return ' ' + args.join(', ') + ' '; + }, + key:quote, //object calls it internally, the key part of an item in a map + functionCode:'[code]', //function calls it internally, it's the content of the function + attribute:quote, //node calls it internally, it's an html attribute value + string:quote, + date:quote, + regexp:literal, //regex + number:literal, + 'boolean':literal + }, + DOMAttrs:{//attributes to dump from nodes, name=>realName + id:'id', + name:'name', + 'class':'className' + }, + HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) + indentChar:' ',//indentation unit + multiline:true //if true, items in a collection, are separated by a \n, else just a space. + }; + + return jsDump; +})(); + +// from Sizzle.js +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +}; + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + function diff(o, n){ + var ns = new Object(); + var os = new Object(); + + for (var i = 0; i < n.length; i++) { + if (ns[n[i]] == null) + ns[n[i]] = { + rows: new Array(), + o: null + }; + ns[n[i]].rows.push(i); + } + + for (var i = 0; i < o.length; i++) { + if (os[o[i]] == null) + os[o[i]] = { + rows: new Array(), + n: null + }; + os[o[i]].rows.push(i); + } + + for (var i in ns) { + if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { + n[ns[i].rows[0]] = { + text: n[ns[i].rows[0]], + row: os[i].rows[0] + }; + o[os[i].rows[0]] = { + text: o[os[i].rows[0]], + row: ns[i].rows[0] + }; + } + } + + for (var i = 0; i < n.length - 1; i++) { + if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && + n[i + 1] == o[n[i].row + 1]) { + n[i + 1] = { + text: n[i + 1], + row: n[i].row + 1 + }; + o[n[i].row + 1] = { + text: o[n[i].row + 1], + row: i + 1 + }; + } + } + + for (var i = n.length - 1; i > 0; i--) { + if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && + n[i - 1] == o[n[i].row - 1]) { + n[i - 1] = { + text: n[i - 1], + row: n[i].row - 1 + }; + o[n[i].row - 1] = { + text: o[n[i].row - 1], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function(o, n){ + o = o.replace(/\s+$/, ''); + n = n.replace(/\s+$/, ''); + var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); + + var str = ""; + + var oSpace = o.match(/\s+/g); + if (oSpace == null) { + oSpace = [" "]; + } + else { + oSpace.push(" "); + } + var nSpace = n.match(/\s+/g); + if (nSpace == null) { + nSpace = [" "]; + } + else { + nSpace.push(" "); + } + + if (out.n.length == 0) { + for (var i = 0; i < out.o.length; i++) { + str += '' + out.o[i] + oSpace[i] + ""; + } + } + else { + if (out.n[0].text == null) { + for (n = 0; n < out.o.length && out.o[n].text == null; n++) { + str += '' + out.o[n] + oSpace[n] + ""; + } + } + + for (var i = 0; i < out.n.length; i++) { + if (out.n[i].text == null) { + str += '' + out.n[i] + nSpace[i] + ""; + } + else { + var pre = ""; + + for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { + pre += '' + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +})(); + +})(this); diff --git a/php/kindeditor_demo/kindeditor/license.txt b/php/kindeditor_demo/kindeditor/license.txt new file mode 100755 index 0000000..4362b49 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/license.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/php/kindeditor_demo/kindeditor/package.json b/php/kindeditor_demo/kindeditor/package.json new file mode 100755 index 0000000..03181c2 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/package.json @@ -0,0 +1,11 @@ +{ + "name" : "KindEditor", + "version" : "4.1.11", + "filename" : "kindeditor", + "devDependencies" : { + "grunt": "~0.4.1", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-uglify": "~0.2.7", + "grunt-contrib-compress": "~0.5.3" + } +} diff --git a/php/kindeditor_demo/kindeditor/php/JSON.php b/php/kindeditor_demo/kindeditor/php/JSON.php new file mode 100755 index 0000000..0cddbdd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/php/JSON.php @@ -0,0 +1,806 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 3); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 5); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_SUPPRESS_ERRORS', 32); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); + + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } +} + +if (class_exists('PEAR_Error')) { + + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } + +} else { + + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } + +} + +?> diff --git a/php/kindeditor_demo/kindeditor/php/demo.php b/php/kindeditor_demo/kindeditor/php/demo.php new file mode 100755 index 0000000..c63f07a --- /dev/null +++ b/php/kindeditor_demo/kindeditor/php/demo.php @@ -0,0 +1,53 @@ + + + + + + KindEditor PHP + + + + + + + + + +
      + +
      + (提交快捷键: Ctrl + Enter) +
      + + + diff --git a/php/kindeditor_demo/kindeditor/php/file_manager_json.php b/php/kindeditor_demo/kindeditor/php/file_manager_json.php new file mode 100755 index 0000000..8ce443f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/php/file_manager_json.php @@ -0,0 +1,137 @@ + 2); //文件夹是否包含文件 + $file_list[$i]['filesize'] = 0; //文件大小 + $file_list[$i]['is_photo'] = false; //是否图片 + $file_list[$i]['filetype'] = ''; //文件类别,用扩展名判断 + } else { + $file_list[$i]['is_dir'] = false; + $file_list[$i]['has_file'] = false; + $file_list[$i]['filesize'] = filesize($file); + $file_list[$i]['dir_path'] = ''; + $file_ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); + $file_list[$i]['is_photo'] = in_array($file_ext, $ext_arr); + $file_list[$i]['filetype'] = $file_ext; + } + $file_list[$i]['filename'] = $filename; //文件名,包含扩展名 + $file_list[$i]['datetime'] = date('Y-m-d H:i:s', filemtime($file)); //文件最后修改时间 + $i++; + } + closedir($handle); +} + +//排序 +function cmp_func($a, $b) { + global $order; + if ($a['is_dir'] && !$b['is_dir']) { + return -1; + } else if (!$a['is_dir'] && $b['is_dir']) { + return 1; + } else { + if ($order == 'size') { + if ($a['filesize'] > $b['filesize']) { + return 1; + } else if ($a['filesize'] < $b['filesize']) { + return -1; + } else { + return 0; + } + } else if ($order == 'type') { + return strcmp($a['filetype'], $b['filetype']); + } else { + return strcmp($a['filename'], $b['filename']); + } + } +} +usort($file_list, 'cmp_func'); + +$result = array(); +//相对于根目录的上一级目录 +$result['moveup_dir_path'] = $moveup_dir_path; +//相对于根目录的当前目录 +$result['current_dir_path'] = $current_dir_path; +//当前目录的URL +$result['current_url'] = $current_url; +//文件数 +$result['total_count'] = count($file_list); +//文件列表数组 +$result['file_list'] = $file_list; + +//输出JSON字符串 +header('Content-type: application/json; charset=UTF-8'); +$json = new Services_JSON(); +echo $json->encode($result); diff --git a/php/kindeditor_demo/kindeditor/php/upload_json.php b/php/kindeditor_demo/kindeditor/php/upload_json.php new file mode 100755 index 0000000..bca41f9 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/php/upload_json.php @@ -0,0 +1,140 @@ + array('gif', 'jpg', 'jpeg', 'png', 'bmp'), + 'flash' => array('swf', 'flv'), + 'media' => array('swf', 'flv', 'mp3', 'wav', 'wma', 'wmv', 'mid', 'avi', 'mpg', 'asf', 'rm', 'rmvb'), + 'file' => array('doc', 'docx', 'xls', 'xlsx', 'ppt', 'htm', 'html', 'txt', 'zip', 'rar', 'gz', 'bz2'), +); +//最大文件大小 +$max_size = 1000000; + +//$save_path = realpath($save_path) . '/'; + +//PHP上传失败 +if (!empty($_FILES['imgFile']['error'])) { + switch($_FILES['imgFile']['error']){ + case '1': + $error = '超过php.ini允许的大小。'; + break; + case '2': + $error = '超过表单允许的大小。'; + break; + case '3': + $error = '图片只有部分被上传。'; + break; + case '4': + $error = '请选择图片。'; + break; + case '6': + $error = '找不到临时目录。'; + break; + case '7': + $error = '写文件到硬盘出错。'; + break; + case '8': + $error = 'File upload stopped by extension。'; + break; + case '999': + default: + $error = '未知错误。'; + } + alert($error); +} + +//有上传文件时 +if (empty($_FILES) === false) { + //原文件名 + $file_name = $_FILES['imgFile']['name']; + //服务器上临时文件名 + $tmp_name = $_FILES['imgFile']['tmp_name']; + //文件大小 + $file_size = $_FILES['imgFile']['size']; + //alert($save_path);die; + //检查文件名 + if (!$file_name) { + alert("请选择文件。"); + } + //检查目录 + if (@is_dir($save_path) === false) { + alert("上传目录不存在。"); + } + //检查目录写权限 + if (@is_writable($save_path) === false) { + alert("上传目录没有写权限。"); + } + //检查是否已上传 + if (@is_uploaded_file($tmp_name) === false) { + alert("上传失败。"); + } + //检查文件大小 + if ($file_size > $max_size) { + alert("上传文件大小超过限制。"); + } + //检查目录名 + $dir_name = empty($_GET['dir']) ? 'image' : trim($_GET['dir']); + if (empty($ext_arr[$dir_name])) { + alert("目录名不正确。"); + } + //获得文件扩展名 + $temp_arr = explode(".", $file_name); + $file_ext = array_pop($temp_arr); + $file_ext = trim($file_ext); + $file_ext = strtolower($file_ext); + //检查扩展名 + if (in_array($file_ext, $ext_arr[$dir_name]) === false) { + alert("上传文件扩展名是不允许的扩展名。\n只允许" . implode(",", $ext_arr[$dir_name]) . "格式。"); + } + //创建文件夹 + if ($dir_name !== '') { + $save_path .= $dir_name . "/"; + $save_url .= $dir_name . "/"; + if (!file_exists($save_path)) { + mkdir($save_path); + } + } + $ymd = date("Ymd"); + $save_path .= $ymd . "/"; + $save_url .= $ymd . "/"; + if (!file_exists($save_path)) { + mkdir($save_path); + } + //新文件名 + $new_file_name = date("YmdHis") . '_' . rand(10000, 99999) . '.' . $file_ext; + //移动文件 + $file_path = $save_path . $new_file_name; + if (move_uploaded_file($tmp_name, $file_path) === false) { + alert("上传文件失败。"); + } + @chmod($file_path, 0644); + $file_url = $save_url . $new_file_name; + + header('Content-type: text/html; charset=UTF-8'); + $json = new Services_JSON(); + echo $json->encode(array('error' => 0, 'url' => $file_url)); + exit; +} + +function alert($msg) { + header('Content-type: text/html; charset=UTF-8'); + $json = new Services_JSON(); + echo $json->encode(array('error' => 1, 'message' => $msg)); + exit; +} diff --git a/php/kindeditor_demo/kindeditor/plugins/anchor/anchor.js b/php/kindeditor_demo/kindeditor/plugins/anchor/anchor.js new file mode 100755 index 0000000..55ab894 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/anchor/anchor.js @@ -0,0 +1,46 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('anchor', function(K) { + var self = this, name = 'anchor', lang = self.lang(name + '.'); + self.plugin.anchor = { + edit : function() { + var html = ['
      ', + '
      ', + '', + '', + '
      ', + '
      '].join(''); + var dialog = self.createDialog({ + name : name, + width : 300, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + self.insertHtml('').hideDialog().focus(); + } + } + }); + var div = dialog.div, + nameBox = K('input[name="name"]', div); + var img = self.plugin.getSelectedAnchor(); + if (img) { + nameBox.val(unescape(img.attr('data-ke-name'))); + } + nameBox[0].focus(); + nameBox[0].select(); + }, + 'delete' : function() { + self.plugin.getSelectedAnchor().remove(); + } + }; + self.clickToolbar(name, self.plugin.anchor.edit); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/autoheight/autoheight.js b/php/kindeditor_demo/kindeditor/plugins/autoheight/autoheight.js new file mode 100755 index 0000000..546578b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/autoheight/autoheight.js @@ -0,0 +1,54 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('autoheight', function(K) { + var self = this; + + if (!self.autoHeightMode) { + return; + } + + var minHeight; + + function hideScroll() { + var edit = self.edit; + var body = edit.doc.body; + edit.iframe[0].scroll = 'no'; + body.style.overflowY = 'hidden'; + } + + function resetHeight() { + var edit = self.edit; + var body = edit.doc.body; + edit.iframe.height(minHeight); + self.resize(null, Math.max((K.IE ? body.scrollHeight : body.offsetHeight) + 76, minHeight)); + } + + function init() { + minHeight = K.removeUnit(self.height); + + self.edit.afterChange(resetHeight); + hideScroll(); + resetHeight(); + } + + if (self.isCreated) { + init(); + } else { + self.afterCreate(init); + } +}); + +/* +* 如何实现真正的自动高度? +* 修改编辑器高度之后,再次获取body内容高度时,最小值只会是当前iframe的设置高度,这样就导致高度只增不减。 +* 所以每次获取body内容高度之前,先将iframe的高度重置为最小高度,这样就能获取body的实际高度。 +* 由此就实现了真正的自动高度 +* 测试:chrome、firefox、IE9、IE8 +* */ diff --git a/php/kindeditor_demo/kindeditor/plugins/baidumap/baidumap.js b/php/kindeditor_demo/kindeditor/plugins/baidumap/baidumap.js new file mode 100755 index 0000000..12751c4 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/baidumap/baidumap.js @@ -0,0 +1,93 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +// Baidu Maps: http://dev.baidu.com/wiki/map/index.php?title=%E9%A6%96%E9%A1%B5 + +KindEditor.plugin('baidumap', function(K) { + var self = this, name = 'baidumap', lang = self.lang(name + '.'); + var mapWidth = K.undef(self.mapWidth, 558); + var mapHeight = K.undef(self.mapHeight, 360); + self.clickToolbar(name, function() { + var html = ['
      ', + '
      ', + // left start + '
      ', + lang.address + ' ', + '', + '', + '', + '
      ', + // right start + '
      ', + ' ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      '].join(''); + var dialog = self.createDialog({ + name : name, + width : mapWidth + 42, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var map = win.map; + var centerObj = map.getCenter(); + var center = centerObj.lng + ',' + centerObj.lat; + var zoom = map.getZoom(); + var url = [checkbox[0].checked ? self.pluginsPath + 'baidumap/index.html' : 'http://api.map.baidu.com/staticimage', + '?center=' + encodeURIComponent(center), + '&zoom=' + encodeURIComponent(zoom), + '&width=' + mapWidth, + '&height=' + mapHeight, + '&markers=' + encodeURIComponent(center), + '&markerStyles=' + encodeURIComponent('l,A')].join(''); + if (checkbox[0].checked) { + self.insertHtml(''); + } else { + self.exec('insertimage', url); + } + self.hideDialog().focus(); + } + }, + beforeRemove : function() { + searchBtn.remove(); + if (doc) { + doc.write(''); + } + iframe.remove(); + } + }); + var div = dialog.div, + addressBox = K('[name="address"]', div), + searchBtn = K('[name="searchBtn"]', div), + checkbox = K('[name="insertDynamicMap"]', dialog.div), + win, doc; + var iframe = K(''); + function ready() { + win = iframe[0].contentWindow; + doc = K.iframeDoc(iframe); + } + iframe.bind('load', function() { + iframe.unbind('load'); + if (K.IE) { + ready(); + } else { + setTimeout(ready, 0); + } + }); + K('.ke-map', div).replaceWith(iframe); + // search map + searchBtn.click(function() { + win.search(addressBox.val()); + }); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/baidumap/index.html b/php/kindeditor_demo/kindeditor/plugins/baidumap/index.html new file mode 100755 index 0000000..e106d1a --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/baidumap/index.html @@ -0,0 +1,83 @@ + + + + + + +百度地图API自定义地图 + + + + + + + +
      + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/plugins/baidumap/map.html b/php/kindeditor_demo/kindeditor/plugins/baidumap/map.html new file mode 100755 index 0000000..b65ea1d --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/baidumap/map.html @@ -0,0 +1,43 @@ + + + + + Baidu Maps + + + + + +
      + + diff --git a/php/kindeditor_demo/kindeditor/plugins/clearhtml/clearhtml.js b/php/kindeditor_demo/kindeditor/plugins/clearhtml/clearhtml.js new file mode 100755 index 0000000..96ee5fe --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/clearhtml/clearhtml.js @@ -0,0 +1,29 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('clearhtml', function(K) { + var self = this, name = 'clearhtml'; + self.clickToolbar(name, function() { + self.focus(); + var html = self.html(); + html = html.replace(/(]*>)([\s\S]*?)(<\/script>)/ig, ''); + html = html.replace(/(]*>)([\s\S]*?)(<\/style>)/ig, ''); + html = K.formatHtml(html, { + a : ['href', 'target'], + embed : ['src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess'], + img : ['src', 'width', 'height', 'border', 'alt', 'title', '.width', '.height'], + table : ['border'], + 'td,th' : ['rowspan', 'colspan'], + 'div,hr,br,tbody,tr,p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [] + }); + self.html(html); + self.cmd.selection(true); + self.addBookmark(); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/code/code.js b/php/kindeditor_demo/kindeditor/plugins/code/code.js new file mode 100755 index 0000000..67fde02 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/code/code.js @@ -0,0 +1,62 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +// google code prettify: http://google-code-prettify.googlecode.com/ +// http://google-code-prettify.googlecode.com/ + +KindEditor.plugin('code', function(K) { + var self = this, name = 'code'; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = ['
      ', + '
      ', + '', + '
      ', + '', + '
      '].join(''), + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var type = K('.ke-code-type', dialog.div).val(), + code = textarea.val(), + cls = type === '' ? '' : ' lang-' + type, + html = '
      \n' + K.escape(code) + '
      '; + if (K.trim(code) === '') { + alert(lang.pleaseInput); + textarea[0].focus(); + return; + } + self.insertHtml(html).hideDialog().focus(); + } + } + }), + textarea = K('textarea', dialog.div); + textarea[0].focus(); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/code/prettify.css b/php/kindeditor_demo/kindeditor/plugins/code/prettify.css new file mode 100755 index 0000000..b8287e5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/code/prettify.css @@ -0,0 +1,13 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} + +pre.prettyprint { + border: 0; + border-left: 3px solid rgb(204, 204, 204); + margin-left: 2em; + padding: 0.5em; + font-size: 110%; + display: block; + font-family: "Consolas", "Monaco", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; + margin: 1em 0px; + white-space: pre; +} diff --git a/php/kindeditor_demo/kindeditor/plugins/code/prettify.js b/php/kindeditor_demo/kindeditor/plugins/code/prettify.js new file mode 100755 index 0000000..eef5ad7 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/code/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('emoticons', function(K) { + var self = this, name = 'emoticons', + path = (self.emoticonsPath || self.pluginsPath + 'emoticons/images/'), + allowPreview = self.allowPreviewEmoticons === undefined ? true : self.allowPreviewEmoticons, + currentPageNum = 1; + self.clickToolbar(name, function() { + var rows = 5, cols = 9, total = 135, startNum = 0, + cells = rows * cols, pages = Math.ceil(total / cells), + colsHalf = Math.floor(cols / 2), + wrapperDiv = K('
      '), + elements = [], + menu = self.createMenu({ + name : name, + beforeRemove : function() { + removeEvent(); + } + }); + menu.div.append(wrapperDiv); + var previewDiv, previewImg; + if (allowPreview) { + previewDiv = K('
      ').css('right', 0); + previewImg = K(''); + wrapperDiv.append(previewDiv); + previewDiv.append(previewImg); + } + function bindCellEvent(cell, j, num) { + if (previewDiv) { + cell.mouseover(function() { + if (j > colsHalf) { + previewDiv.css('left', 0); + previewDiv.css('right', ''); + } else { + previewDiv.css('left', ''); + previewDiv.css('right', 0); + } + previewImg.attr('src', path + num + '.gif'); + K(this).addClass('ke-on'); + }); + } else { + cell.mouseover(function() { + K(this).addClass('ke-on'); + }); + } + cell.mouseout(function() { + K(this).removeClass('ke-on'); + }); + cell.click(function(e) { + self.insertHtml('').hideMenu().focus(); + e.stop(); + }); + } + function createEmoticonsTable(pageNum, parentDiv) { + var table = document.createElement('table'); + parentDiv.append(table); + if (previewDiv) { + K(table).mouseover(function() { + previewDiv.show('block'); + }); + K(table).mouseout(function() { + previewDiv.hide(); + }); + elements.push(K(table)); + } + table.className = 'ke-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + var num = (pageNum - 1) * cells + startNum; + for (var i = 0; i < rows; i++) { + var row = table.insertRow(i); + for (var j = 0; j < cols; j++) { + var cell = K(row.insertCell(j)); + cell.addClass('ke-cell'); + bindCellEvent(cell, j, num); + var span = K('') + .css('background-position', '-' + (24 * num) + 'px 0px') + .css('background-image', 'url(' + path + 'static.gif)'); + cell.append(span); + elements.push(cell); + num++; + } + } + return table; + } + var table = createEmoticonsTable(currentPageNum, wrapperDiv); + function removeEvent() { + K.each(elements, function() { + this.unbind(); + }); + } + var pageDiv; + function bindPageEvent(el, pageNum) { + el.click(function(e) { + removeEvent(); + table.parentNode.removeChild(table); + pageDiv.remove(); + table = createEmoticonsTable(pageNum, wrapperDiv); + createPageTable(pageNum); + currentPageNum = pageNum; + e.stop(); + }); + } + function createPageTable(currentPageNum) { + pageDiv = K('
      '); + wrapperDiv.append(pageDiv); + for (var pageNum = 1; pageNum <= pages; pageNum++) { + if (currentPageNum !== pageNum) { + var a = K('
      [' + pageNum + ']'); + bindPageEvent(a, pageNum); + pageDiv.append(a); + elements.push(a); + } else { + pageDiv.append(K('@[' + pageNum + ']')); + } + pageDiv.append(K('@ ')); + } + } + createPageTable(currentPageNum); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/0.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/0.gif new file mode 100755 index 0000000..5be27cb Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/0.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/1.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/1.gif new file mode 100755 index 0000000..a2644a9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/1.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/10.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/10.gif new file mode 100755 index 0000000..905c15b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/10.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/100.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/100.gif new file mode 100755 index 0000000..92ad35d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/100.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/101.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/101.gif new file mode 100755 index 0000000..1f27663 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/101.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/102.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/102.gif new file mode 100755 index 0000000..748ded1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/102.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/103.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/103.gif new file mode 100755 index 0000000..be9eaa0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/103.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/104.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/104.gif new file mode 100755 index 0000000..d7c2066 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/104.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/105.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/105.gif new file mode 100755 index 0000000..2f353ca Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/105.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/106.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/106.gif new file mode 100755 index 0000000..5193534 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/106.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/107.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/107.gif new file mode 100755 index 0000000..70d38d3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/107.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/108.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/108.gif new file mode 100755 index 0000000..749d500 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/108.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/109.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/109.gif new file mode 100755 index 0000000..6f57d56 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/109.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/11.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/11.gif new file mode 100755 index 0000000..b512dd5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/11.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/110.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/110.gif new file mode 100755 index 0000000..e253abc Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/110.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/111.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/111.gif new file mode 100755 index 0000000..0c56723 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/111.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/112.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/112.gif new file mode 100755 index 0000000..c8ddce8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/112.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/113.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/113.gif new file mode 100755 index 0000000..2727104 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/113.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/114.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/114.gif new file mode 100755 index 0000000..53918e2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/114.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/115.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/115.gif new file mode 100755 index 0000000..4db3369 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/115.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/116.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/116.gif new file mode 100755 index 0000000..57326bd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/116.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/117.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/117.gif new file mode 100755 index 0000000..14611b6 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/117.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/118.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/118.gif new file mode 100755 index 0000000..8c25500 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/118.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/119.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/119.gif new file mode 100755 index 0000000..65bb468 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/119.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/12.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/12.gif new file mode 100755 index 0000000..547529c Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/12.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/120.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/120.gif new file mode 100755 index 0000000..5ce77c0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/120.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/121.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/121.gif new file mode 100755 index 0000000..a021aba Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/121.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/122.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/122.gif new file mode 100755 index 0000000..9a79e11 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/122.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/123.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/123.gif new file mode 100755 index 0000000..b9480be Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/123.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/124.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/124.gif new file mode 100755 index 0000000..7fed477 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/124.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/125.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/125.gif new file mode 100755 index 0000000..e2c3c11 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/125.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/126.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/126.gif new file mode 100755 index 0000000..24105c9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/126.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/127.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/127.gif new file mode 100755 index 0000000..0cead36 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/127.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/128.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/128.gif new file mode 100755 index 0000000..3185861 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/128.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/129.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/129.gif new file mode 100755 index 0000000..ffd7c6b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/129.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/13.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/13.gif new file mode 100755 index 0000000..3475300 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/13.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/130.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/130.gif new file mode 100755 index 0000000..d828e3d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/130.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/131.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/131.gif new file mode 100755 index 0000000..dcb096f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/131.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/132.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/132.gif new file mode 100755 index 0000000..1b272a6 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/132.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/133.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/133.gif new file mode 100755 index 0000000..0d0e864 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/133.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/134.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/134.gif new file mode 100755 index 0000000..cf48356 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/134.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/14.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/14.gif new file mode 100755 index 0000000..6a788f8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/14.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/15.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/15.gif new file mode 100755 index 0000000..debab8e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/15.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/16.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/16.gif new file mode 100755 index 0000000..ed5d29f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/16.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/17.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/17.gif new file mode 100755 index 0000000..85886fe Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/17.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/18.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/18.gif new file mode 100755 index 0000000..b6af218 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/18.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/19.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/19.gif new file mode 100755 index 0000000..e045ff2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/19.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/2.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/2.gif new file mode 100755 index 0000000..40cfda4 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/2.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/20.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/20.gif new file mode 100755 index 0000000..efd650f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/20.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/21.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/21.gif new file mode 100755 index 0000000..cb8cf6d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/21.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/22.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/22.gif new file mode 100755 index 0000000..96b04df Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/22.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/23.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/23.gif new file mode 100755 index 0000000..96516b8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/23.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/24.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/24.gif new file mode 100755 index 0000000..5f925c7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/24.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/25.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/25.gif new file mode 100755 index 0000000..97f8b1a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/25.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/26.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/26.gif new file mode 100755 index 0000000..a7cded7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/26.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/27.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/27.gif new file mode 100755 index 0000000..bb46890 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/27.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/28.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/28.gif new file mode 100755 index 0000000..f59dd58 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/28.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/29.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/29.gif new file mode 100755 index 0000000..3c5227e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/29.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/3.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/3.gif new file mode 100755 index 0000000..6d6f762 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/3.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/30.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/30.gif new file mode 100755 index 0000000..e24a180 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/30.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/31.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/31.gif new file mode 100755 index 0000000..073e743 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/31.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/32.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/32.gif new file mode 100755 index 0000000..772eff2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/32.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/33.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/33.gif new file mode 100755 index 0000000..217c1c5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/33.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/34.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/34.gif new file mode 100755 index 0000000..e9d4213 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/34.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/35.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/35.gif new file mode 100755 index 0000000..d6da2c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/35.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/36.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/36.gif new file mode 100755 index 0000000..c1e6ac9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/36.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/37.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/37.gif new file mode 100755 index 0000000..92efec6 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/37.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/38.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/38.gif new file mode 100755 index 0000000..489f0f9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/38.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/39.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/39.gif new file mode 100755 index 0000000..734f6d8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/39.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/4.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/4.gif new file mode 100755 index 0000000..6ccdaa2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/4.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/40.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/40.gif new file mode 100755 index 0000000..24a8eb6 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/40.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/41.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/41.gif new file mode 100755 index 0000000..99139e1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/41.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/42.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/42.gif new file mode 100755 index 0000000..f60897e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/42.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/43.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/43.gif new file mode 100755 index 0000000..4350491 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/43.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/44.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/44.gif new file mode 100755 index 0000000..650d3dd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/44.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/45.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/45.gif new file mode 100755 index 0000000..5c8e071 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/45.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/46.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/46.gif new file mode 100755 index 0000000..f3cb074 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/46.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/47.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/47.gif new file mode 100755 index 0000000..5b3057a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/47.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/48.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/48.gif new file mode 100755 index 0000000..27a30c1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/48.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/49.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/49.gif new file mode 100755 index 0000000..dcfa48a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/49.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/5.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/5.gif new file mode 100755 index 0000000..ab0b81b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/5.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/50.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/50.gif new file mode 100755 index 0000000..029cf0f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/50.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/51.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/51.gif new file mode 100755 index 0000000..69f183f Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/51.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/52.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/52.gif new file mode 100755 index 0000000..d41e8aa Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/52.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/53.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/53.gif new file mode 100755 index 0000000..56352dd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/53.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/54.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/54.gif new file mode 100755 index 0000000..b28d848 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/54.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/55.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/55.gif new file mode 100755 index 0000000..e18da84 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/55.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/56.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/56.gif new file mode 100755 index 0000000..edf96f0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/56.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/57.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/57.gif new file mode 100755 index 0000000..3f0e2b9 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/57.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/58.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/58.gif new file mode 100755 index 0000000..47b1aaa Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/58.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/59.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/59.gif new file mode 100755 index 0000000..918288b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/59.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/6.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/6.gif new file mode 100755 index 0000000..ceab122 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/6.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/60.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/60.gif new file mode 100755 index 0000000..66d2113 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/60.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/61.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/61.gif new file mode 100755 index 0000000..034933e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/61.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/62.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/62.gif new file mode 100755 index 0000000..8d5c4fd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/62.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/63.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/63.gif new file mode 100755 index 0000000..d58fcf6 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/63.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/64.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/64.gif new file mode 100755 index 0000000..c4e00bd Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/64.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/65.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/65.gif new file mode 100755 index 0000000..da23bfa Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/65.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/66.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/66.gif new file mode 100755 index 0000000..310ec65 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/66.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/67.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/67.gif new file mode 100755 index 0000000..51761ba Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/67.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/68.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/68.gif new file mode 100755 index 0000000..345cb43 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/68.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/69.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/69.gif new file mode 100755 index 0000000..e0f28a0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/69.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/7.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/7.gif new file mode 100755 index 0000000..2f45399 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/7.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/70.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/70.gif new file mode 100755 index 0000000..24284cf Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/70.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/71.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/71.gif new file mode 100755 index 0000000..a0ccf2e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/71.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/72.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/72.gif new file mode 100755 index 0000000..7e113ee Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/72.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/73.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/73.gif new file mode 100755 index 0000000..c0293c3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/73.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/74.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/74.gif new file mode 100755 index 0000000..1c52bde Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/74.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/75.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/75.gif new file mode 100755 index 0000000..9cb9aa7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/75.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/76.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/76.gif new file mode 100755 index 0000000..27019f8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/76.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/77.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/77.gif new file mode 100755 index 0000000..8f882f5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/77.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/78.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/78.gif new file mode 100755 index 0000000..d0d0856 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/78.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/79.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/79.gif new file mode 100755 index 0000000..61652a7 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/79.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/8.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/8.gif new file mode 100755 index 0000000..f6c8834 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/8.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/80.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/80.gif new file mode 100755 index 0000000..9a77936 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/80.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/81.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/81.gif new file mode 100755 index 0000000..2329101 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/81.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/82.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/82.gif new file mode 100755 index 0000000..644748a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/82.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/83.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/83.gif new file mode 100755 index 0000000..fbf275b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/83.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/84.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/84.gif new file mode 100755 index 0000000..076f0c6 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/84.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/85.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/85.gif new file mode 100755 index 0000000..d254af4 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/85.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/86.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/86.gif new file mode 100755 index 0000000..8f09d33 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/86.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/87.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/87.gif new file mode 100755 index 0000000..df70756 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/87.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/88.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/88.gif new file mode 100755 index 0000000..4d8b15e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/88.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/89.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/89.gif new file mode 100755 index 0000000..05726dc Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/89.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/9.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/9.gif new file mode 100755 index 0000000..c2d8450 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/9.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/90.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/90.gif new file mode 100755 index 0000000..adaf20e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/90.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/91.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/91.gif new file mode 100755 index 0000000..608d0ad Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/91.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/92.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/92.gif new file mode 100755 index 0000000..b909e16 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/92.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/93.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/93.gif new file mode 100755 index 0000000..7f71a8c Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/93.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/94.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/94.gif new file mode 100755 index 0000000..4f26d7d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/94.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/95.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/95.gif new file mode 100755 index 0000000..5ef6d38 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/95.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/96.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/96.gif new file mode 100755 index 0000000..2b709e1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/96.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/97.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/97.gif new file mode 100755 index 0000000..cf29be8 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/97.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/98.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/98.gif new file mode 100755 index 0000000..c70e7d3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/98.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/99.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/99.gif new file mode 100755 index 0000000..05c1863 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/99.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/emoticons/images/static.gif b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/static.gif new file mode 100755 index 0000000..b8c444b Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/emoticons/images/static.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/filemanager/filemanager.js b/php/kindeditor_demo/kindeditor/plugins/filemanager/filemanager.js new file mode 100755 index 0000000..dfe2e2b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/filemanager/filemanager.js @@ -0,0 +1,189 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('filemanager', function(K) { + var self = this, name = 'filemanager', + fileManagerJson = K.undef(self.fileManagerJson, self.basePath + 'php/file_manager_json.php'), + imgPath = self.pluginsPath + name + '/images/', + lang = self.lang(name + '.'); + function makeFileTitle(filename, filesize, datetime) { + return filename + ' (' + Math.ceil(filesize / 1024) + 'KB, ' + datetime + ')'; + } + function bindTitle(el, data) { + if (data.is_dir) { + el.attr('title', data.filename); + } else { + el.attr('title', makeFileTitle(data.filename, data.filesize, data.datetime)); + } + } + self.plugin.filemanagerDialog = function(options) { + var width = K.undef(options.width, 650), + height = K.undef(options.height, 510), + dirName = K.undef(options.dirName, ''), + viewType = K.undef(options.viewType, 'VIEW').toUpperCase(), // "LIST" or "VIEW" + clickFn = options.clickFn; + var html = [ + '
      ', + // header start + '
      ', + // left start + '
      ', + ' ', + '' + lang.moveup + '', + '
      ', + // right start + '
      ', + lang.viewType + ' ', + lang.orderType + ' ', + '
      ', + '
      ', + '
      ', + // body start + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : width, + height : height, + title : self.lang(name), + body : html + }), + div = dialog.div, + bodyDiv = K('.ke-plugin-filemanager-body', div), + moveupImg = K('[name="moveupImg"]', div), + moveupLink = K('[name="moveupLink"]', div), + viewServerBtn = K('[name="viewServer"]', div), + viewTypeBox = K('[name="viewType"]', div), + orderTypeBox = K('[name="orderType"]', div); + function reloadPage(path, order, func) { + var param = 'path=' + path + '&order=' + order + '&dir=' + dirName; + dialog.showLoading(self.lang('ajaxLoading')); + K.ajax(K.addParam(fileManagerJson, param + '&' + new Date().getTime()), function(data) { + dialog.hideLoading(); + func(data); + }); + } + var elList = []; + function bindEvent(el, result, data, createFunc) { + var fileUrl = K.formatUrl(result.current_url + data.filename, 'absolute'), + dirPath = encodeURIComponent(result.current_dir_path + data.filename + '/'); + if (data.is_dir) { + el.click(function(e) { + reloadPage(dirPath, orderTypeBox.val(), createFunc); + }); + } else if (data.is_photo) { + el.click(function(e) { + clickFn.call(this, fileUrl, data.filename); + }); + } else { + el.click(function(e) { + clickFn.call(this, fileUrl, data.filename); + }); + } + elList.push(el); + } + function createCommon(result, createFunc) { + // remove events + K.each(elList, function() { + this.unbind(); + }); + moveupLink.unbind(); + viewTypeBox.unbind(); + orderTypeBox.unbind(); + // add events + if (result.current_dir_path) { + moveupLink.click(function(e) { + reloadPage(result.moveup_dir_path, orderTypeBox.val(), createFunc); + }); + } + function changeFunc() { + if (viewTypeBox.val() == 'VIEW') { + reloadPage(result.current_dir_path, orderTypeBox.val(), createView); + } else { + reloadPage(result.current_dir_path, orderTypeBox.val(), createList); + } + } + viewTypeBox.change(changeFunc); + orderTypeBox.change(changeFunc); + bodyDiv.html(''); + } + function createList(result) { + createCommon(result, createList); + var table = document.createElement('table'); + table.className = 'ke-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + bodyDiv.append(table); + var fileList = result.file_list; + for (var i = 0, len = fileList.length; i < len; i++) { + var data = fileList[i], row = K(table.insertRow(i)); + row.mouseover(function(e) { + K(this).addClass('ke-on'); + }) + .mouseout(function(e) { + K(this).removeClass('ke-on'); + }); + var iconUrl = imgPath + (data.is_dir ? 'folder-16.gif' : 'file-16.gif'), + img = K('' + data.filename + ''), + cell0 = K(row[0].insertCell(0)).addClass('ke-cell ke-name').append(img).append(document.createTextNode(' ' + data.filename)); + if (!data.is_dir || data.has_file) { + row.css('cursor', 'pointer'); + cell0.attr('title', data.filename); + bindEvent(cell0, result, data, createList); + } else { + cell0.attr('title', lang.emptyFolder); + } + K(row[0].insertCell(1)).addClass('ke-cell ke-size').html(data.is_dir ? '-' : Math.ceil(data.filesize / 1024) + 'KB'); + K(row[0].insertCell(2)).addClass('ke-cell ke-datetime').html(data.datetime); + } + } + function createView(result) { + createCommon(result, createView); + var fileList = result.file_list; + for (var i = 0, len = fileList.length; i < len; i++) { + var data = fileList[i], + div = K('
      '); + bodyDiv.append(div); + var photoDiv = K('
      ') + .mouseover(function(e) { + K(this).addClass('ke-on'); + }) + .mouseout(function(e) { + K(this).removeClass('ke-on'); + }); + div.append(photoDiv); + var fileUrl = result.current_url + data.filename, + iconUrl = data.is_dir ? imgPath + 'folder-64.gif' : (data.is_photo ? fileUrl : imgPath + 'file-64.gif'); + var img = K('' + data.filename + ''); + if (!data.is_dir || data.has_file) { + photoDiv.css('cursor', 'pointer'); + bindTitle(photoDiv, data); + bindEvent(photoDiv, result, data, createView); + } else { + photoDiv.attr('title', lang.emptyFolder); + } + photoDiv.append(img); + div.append('
      ' + data.filename + '
      '); + } + } + viewTypeBox.val(viewType); + reloadPage('', orderTypeBox.val(), viewType == 'VIEW' ? createView : createList); + return dialog; + } + +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/filemanager/images/file-16.gif b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/file-16.gif new file mode 100755 index 0000000..2cf6e47 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/file-16.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/filemanager/images/file-64.gif b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/file-64.gif new file mode 100755 index 0000000..2e211da Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/file-64.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/filemanager/images/folder-16.gif b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/folder-16.gif new file mode 100755 index 0000000..850b5a3 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/folder-16.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/filemanager/images/folder-64.gif b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/folder-64.gif new file mode 100755 index 0000000..e8a1b09 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/folder-64.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/filemanager/images/go-up.gif b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/go-up.gif new file mode 100755 index 0000000..92ae23d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/filemanager/images/go-up.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/fixtoolbar/fixtoolbar.js b/php/kindeditor_demo/kindeditor/plugins/fixtoolbar/fixtoolbar.js new file mode 100755 index 0000000..7a16fca --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/fixtoolbar/fixtoolbar.js @@ -0,0 +1,35 @@ +/** + * Created by chenyihong on 14/12/4. + */ + +KindEditor.plugin('fixtoolbar', function (K) { + var self = this; + if (!self.fixToolBar) { + return; + } + + function init() { + var toolbar = K('.ke-toolbar'); + var originY = toolbar.pos().y; + K(window).bind('scroll', function () { + if (toolbar.css('position') == 'fixed') { + if(document.body.scrollTop - originY < 0){ + toolbar.css('position', 'static'); + toolbar.css('top', 'auto'); + } + } else { + if (toolbar.pos().y - document.body.scrollTop < 0) { + toolbar.css('position', 'fixed'); + toolbar.css('top', 0); + } + } + }); + } + + if (self.isCreated) { + init(); + } else { + self.afterCreate(init); + } + +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/flash/flash.js b/php/kindeditor_demo/kindeditor/plugins/flash/flash.js new file mode 100755 index 0000000..1e2e622 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/flash/flash.js @@ -0,0 +1,161 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('flash', function(K) { + var self = this, name = 'flash', lang = self.lang(name + '.'), + allowFlashUpload = K.undef(self.allowFlashUpload, true), + allowFileManager = K.undef(self.allowFileManager, false), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'); + self.plugin.flash = { + edit : function() { + var html = [ + '
      ', + //url + '
      ', + '', + '  ', + '  ', + '', + '', + '', + '
      ', + //width + '
      ', + '', + ' ', + '
      ', + //height + '
      ', + '', + ' ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()), + width = widthBox.val(), + height = heightBox.val(); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + var html = K.mediaImg(self.themesPath + 'common/blank.gif', { + src : url, + type : K.mediaType('.swf'), + width : width, + height : height, + quality : 'high' + }); + self.insertHtml(html).hideDialog().focus(); + } + } + }), + div = dialog.div, + urlBox = K('[name="url"]', div), + viewServerBtn = K('[name="viewServer"]', div), + widthBox = K('[name="width"]', div), + heightBox = K('[name="height"]', div); + urlBox.val('http://'); + + if (allowFlashUpload) { + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + extraParams : extraParams, + url : K.addParam(uploadJson, 'dir=flash'), + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + urlBox.val(url); + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + alert(self.lang('uploadSuccess')); + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + }); + } else { + K('.ke-upload-button', div).hide(); + } + + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'LIST', + dirName : 'flash', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + + var img = self.plugin.getSelectedFlash(); + if (img) { + var attrs = K.mediaAttrs(img.attr('data-ke-tag')); + urlBox.val(attrs.src); + widthBox.val(K.removeUnit(img.css('width')) || attrs.width || 0); + heightBox.val(K.removeUnit(img.css('height')) || attrs.height || 0); + } + urlBox[0].focus(); + urlBox[0].select(); + }, + 'delete' : function() { + self.plugin.getSelectedFlash().remove(); + // [IE] 删除图片后立即点击图片按钮出错 + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.flash.edit); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/image/image.js b/php/kindeditor_demo/kindeditor/plugins/image/image.js new file mode 100755 index 0000000..4b82431 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/image/image.js @@ -0,0 +1,328 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('image', function(K) { + var self = this, name = 'image', + allowImageUpload = K.undef(self.allowImageUpload, true), + allowImageRemote = K.undef(self.allowImageRemote, true), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + allowFileManager = K.undef(self.allowFileManager, false), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'), + imageTabIndex = K.undef(self.imageTabIndex, 0), + imgPath = self.pluginsPath + 'image/images/', + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + fillDescAfterUploadImage = K.undef(self.fillDescAfterUploadImage, false), + lang = self.lang(name + '.'); + + self.plugin.imageDialog = function(options) { + var imageUrl = options.imageUrl, + imageWidth = K.undef(options.imageWidth, ''), + imageHeight = K.undef(options.imageHeight, ''), + imageTitle = K.undef(options.imageTitle, ''), + imageAlign = K.undef(options.imageAlign, ''), + showRemote = K.undef(options.showRemote, true), + showLocal = K.undef(options.showLocal, true), + tabIndex = K.undef(options.tabIndex, 0), + clickFn = options.clickFn; + var target = 'kindeditor_upload_iframe_' + new Date().getTime(); + var hiddenElements = []; + for(var k in extraParams){ + hiddenElements.push(''); + } + var html = [ + '
      ', + //tabs + '
      ', + //remote image - start + '', + //remote image - end + //local upload - start + '', + //local upload - end + '
      ' + ].join(''); + var dialogWidth = showLocal || allowFileManager ? 450 : 400, + dialogHeight = showLocal && showRemote ? 300 : 250; + var dialog = self.createDialog({ + name : name, + width : dialogWidth, + height : dialogHeight, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + // Bugfix: http://code.google.com/p/kindeditor/issues/detail?id=319 + if (dialog.isLoading) { + return; + } + // insert local image + if (showLocal && showRemote && tabs && tabs.selectedIndex === 1 || !showRemote) { + if (uploadbutton.fileBox.val() == '') { + alert(self.lang('pleaseSelectFile')); + return; + } + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + localUrlBox.val(''); + return; + } + // insert remote image + var url = K.trim(urlBox.val()), + width = widthBox.val(), + height = heightBox.val(), + title = titleBox.val(), + align = ''; + alignBox.each(function() { + if (this.checked) { + align = this.value; + return false; + } + }); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + clickFn.call(self, url, title, width, height, 0, align); + } + }, + beforeRemove : function() { + viewServerBtn.unbind(); + widthBox.unbind(); + heightBox.unbind(); + refreshBtn.unbind(); + } + }), + div = dialog.div; + + var urlBox = K('[name="url"]', div), + localUrlBox = K('[name="localUrl"]', div), + viewServerBtn = K('[name="viewServer"]', div), + widthBox = K('.tab1 [name="width"]', div), + heightBox = K('.tab1 [name="height"]', div), + refreshBtn = K('.ke-refresh-btn', div), + titleBox = K('.tab1 [name="title"]', div), + alignBox = K('.tab1 [name="align"]', div); + + var tabs; + if (showRemote && showLocal) { + tabs = K.tabs({ + src : K('.tabs', div), + afterSelect : function(i) {} + }); + tabs.add({ + title : lang.remoteImage, + panel : K('.tab1', div) + }); + tabs.add({ + title : lang.localImage, + panel : K('.tab2', div) + }); + tabs.select(tabIndex); + } else if (showRemote) { + K('.tab1', div).show(); + } else if (showLocal) { + K('.tab2', div).show(); + } + + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + form : K('.ke-form', div), + target : target, + width: 60, + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + if (!fillDescAfterUploadImage) { + clickFn.call(self, url, data.title, data.width, data.height, data.border, data.align); + } else { + K(".ke-dialog-row #remoteUrl", div).val(url); + K(".ke-tabs-li", div)[0].click(); + K(".ke-refresh-btn", div).click(); + } + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + localUrlBox.val(uploadbutton.fileBox.val()); + }); + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'VIEW', + dirName : 'image', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + var originalWidth = 0, originalHeight = 0; + function setSize(width, height) { + widthBox.val(width); + heightBox.val(height); + originalWidth = width; + originalHeight = height; + } + refreshBtn.click(function(e) { + var tempImg = K('', document).css({ + position : 'absolute', + visibility : 'hidden', + top : 0, + left : '-1000px' + }); + tempImg.bind('load', function() { + setSize(tempImg.width(), tempImg.height()); + tempImg.remove(); + }); + K(document.body).append(tempImg); + }); + widthBox.change(function(e) { + if (originalWidth > 0) { + heightBox.val(Math.round(originalHeight / originalWidth * parseInt(this.value, 10))); + } + }); + heightBox.change(function(e) { + if (originalHeight > 0) { + widthBox.val(Math.round(originalWidth / originalHeight * parseInt(this.value, 10))); + } + }); + urlBox.val(options.imageUrl); + setSize(options.imageWidth, options.imageHeight); + titleBox.val(options.imageTitle); + alignBox.each(function() { + if (this.value === options.imageAlign) { + this.checked = true; + return false; + } + }); + if (showRemote && tabIndex === 0) { + urlBox[0].focus(); + urlBox[0].select(); + } + return dialog; + }; + self.plugin.image = { + edit : function() { + var img = self.plugin.getSelectedImage(); + self.plugin.imageDialog({ + imageUrl : img ? img.attr('data-ke-src') : 'http://', + imageWidth : img ? img.width() : '', + imageHeight : img ? img.height() : '', + imageTitle : img ? img.attr('title') : '', + imageAlign : img ? img.attr('align') : '', + showRemote : allowImageRemote, + showLocal : allowImageUpload, + tabIndex: img ? 0 : imageTabIndex, + clickFn : function(url, title, width, height, border, align) { + if (img) { + img.attr('src', url); + img.attr('data-ke-src', url); + img.attr('width', width); + img.attr('height', height); + img.attr('title', title); + img.attr('align', align); + img.attr('alt', title); + } else { + self.exec('insertimage', url, title, width, height, border, align); + } + // Bugfix: [Firefox] 上传图片后,总是出现正在加载的样式,需要延迟执行hideDialog + setTimeout(function() { + self.hideDialog().focus(); + }, 0); + } + }); + }, + 'delete' : function() { + var target = self.plugin.getSelectedImage(); + if (target.parent().name == 'a') { + target = target.parent(); + } + target.remove(); + // [IE] 删除图片后立即点击图片按钮出错 + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.image.edit); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/image/images/align_left.gif b/php/kindeditor_demo/kindeditor/plugins/image/images/align_left.gif new file mode 100755 index 0000000..ab17f56 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/image/images/align_left.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/image/images/align_right.gif b/php/kindeditor_demo/kindeditor/plugins/image/images/align_right.gif new file mode 100755 index 0000000..e8ebe6a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/image/images/align_right.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/image/images/align_top.gif b/php/kindeditor_demo/kindeditor/plugins/image/images/align_top.gif new file mode 100755 index 0000000..d8826a5 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/image/images/align_top.gif differ diff --git a/php/kindeditor_demo/kindeditor/plugins/image/images/refresh.png b/php/kindeditor_demo/kindeditor/plugins/image/images/refresh.png new file mode 100755 index 0000000..77e12d1 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/image/images/refresh.png differ diff --git a/php/kindeditor_demo/kindeditor/plugins/insertfile/insertfile.js b/php/kindeditor_demo/kindeditor/plugins/insertfile/insertfile.js new file mode 100755 index 0000000..0a4ce9e --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/insertfile/insertfile.js @@ -0,0 +1,138 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('insertfile', function(K) { + var self = this, name = 'insertfile', + allowFileUpload = K.undef(self.allowFileUpload, true), + allowFileManager = K.undef(self.allowFileManager, false), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'), + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + lang = self.lang(name + '.'); + self.plugin.fileDialog = function(options) { + var fileUrl = K.undef(options.fileUrl, 'http://'), + fileTitle = K.undef(options.fileTitle, ''), + clickFn = options.clickFn; + var html = [ + '
      ', + '
      ', + '', + '  ', + '  ', + '', + '', + '', + '
      ', + //title + '
      ', + '', + '
      ', + '
      ', + //form end + '', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()), + title = titleBox.val(); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (K.trim(title) === '') { + title = url; + } + clickFn.call(self, url, title); + } + } + }), + div = dialog.div; + + var urlBox = K('[name="url"]', div), + viewServerBtn = K('[name="viewServer"]', div), + titleBox = K('[name="title"]', div); + + if (allowFileUpload) { + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + url : K.addParam(uploadJson, 'dir=file'), + extraParams : extraParams, + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + urlBox.val(url); + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + alert(self.lang('uploadSuccess')); + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + }); + } else { + K('.ke-upload-button', div).hide(); + } + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'LIST', + dirName : 'file', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + urlBox.val(fileUrl); + titleBox.val(fileTitle); + urlBox[0].focus(); + urlBox[0].select(); + }; + self.clickToolbar(name, function() { + self.plugin.fileDialog({ + clickFn : function(url, title) { + var html = '' + title + ''; + self.insertHtml(html).hideDialog().focus(); + } + }); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/lineheight/lineheight.js b/php/kindeditor_demo/kindeditor/plugins/lineheight/lineheight.js new file mode 100755 index 0000000..2125587 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/lineheight/lineheight.js @@ -0,0 +1,38 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('lineheight', function(K) { + var self = this, name = 'lineheight', lang = self.lang(name + '.'); + self.clickToolbar(name, function() { + var curVal = '', commonNode = self.cmd.commonNode({'*' : '.line-height'}); + if (commonNode) { + curVal = commonNode.css('line-height'); + } + var menu = self.createMenu({ + name : name, + width : 150 + }); + K.each(lang.lineHeight, function(i, row) { + K.each(row, function(key, val) { + menu.addItem({ + title : val, + checked : curVal === key, + click : function() { + self.cmd.toggle('', { + span : '.line-height=' + key + }); + self.updateState(); + self.addBookmark(); + self.hideMenu(); + } + }); + }); + }); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/link/link.js b/php/kindeditor_demo/kindeditor/plugins/link/link.js new file mode 100755 index 0000000..f707bc6 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/link/link.js @@ -0,0 +1,66 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('link', function(K) { + var self = this, name = 'link'; + self.plugin.link = { + edit : function() { + var lang = self.lang(name + '.'), + html = '
      ' + + //url + '
      ' + + '' + + '
      ' + + //type + '
      ' + + '' + + '' + + '
      ' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + self.exec('createlink', url, typeBox.val()).hideDialog().focus(); + } + } + }), + div = dialog.div, + urlBox = K('input[name="url"]', div), + typeBox = K('select[name="type"]', div); + urlBox.val('http://'); + typeBox[0].options[0] = new Option(lang.newWindow, '_blank'); + typeBox[0].options[1] = new Option(lang.selfWindow, ''); + self.cmd.selection(); + var a = self.plugin.getSelectedLink(); + if (a) { + self.cmd.range.selectNode(a[0]); + self.cmd.select(); + urlBox.val(a.attr('data-ke-src')); + typeBox.val(a.attr('target')); + } + urlBox[0].focus(); + urlBox[0].select(); + }, + 'delete' : function() { + self.exec('unlink', null); + } + }; + self.clickToolbar(name, self.plugin.link.edit); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/map/map.html b/php/kindeditor_demo/kindeditor/plugins/map/map.html new file mode 100755 index 0000000..033b60b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/map/map.html @@ -0,0 +1,57 @@ + + + + + + + + + +
      + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/plugins/map/map.js b/php/kindeditor_demo/kindeditor/plugins/map/map.js new file mode 100755 index 0000000..38521cf --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/map/map.js @@ -0,0 +1,137 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +// Google Maps: http://code.google.com/apis/maps/index.html + +KindEditor.plugin('map', function(K) { + var self = this, name = 'map', lang = self.lang(name + '.'); + self.clickToolbar(name, function() { + var html = ['
      ', + '
      ', + lang.address + ' ', + '', + '', + '', + '
      ', + '
      ', + '
      '].join(''); + var dialog = self.createDialog({ + name : name, + width : 600, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var geocoder = win.geocoder, + map = win.map, + center = map.getCenter().lat() + ',' + map.getCenter().lng(), + zoom = map.getZoom(), + maptype = map.getMapTypeId(), + url = 'http://maps.googleapis.com/maps/api/staticmap'; + url += '?center=' + encodeURIComponent(center); + url += '&zoom=' + encodeURIComponent(zoom); + url += '&size=558x360'; + url += '&maptype=' + encodeURIComponent(maptype); + url += '&markers=' + encodeURIComponent(center); + url += '&language=' + self.langType; + url += '&sensor=false'; + self.exec('insertimage', url).hideDialog().focus(); + } + }, + beforeRemove : function() { + searchBtn.remove(); + if (doc) { + doc.write(''); + } + iframe.remove(); + } + }); + var div = dialog.div, + addressBox = K('[name="address"]', div), + searchBtn = K('[name="searchBtn"]', div), + win, doc; + var iframeHtml = ['', + '', + '', + '', + '', + '', + '', + '
      ', + ''].join('\n'); + // TODO:用doc.write(iframeHtml)方式加载时,在IE6上第一次加载报错,暂时使用src方式 + var iframe = K(''); + function ready() { + win = iframe[0].contentWindow; + doc = K.iframeDoc(iframe); + //doc.open(); + //doc.write(iframeHtml); + //doc.close(); + } + iframe.bind('load', function() { + iframe.unbind('load'); + if (K.IE) { + ready(); + } else { + setTimeout(ready, 0); + } + }); + K('.ke-map', div).replaceWith(iframe); + // search map + searchBtn.click(function() { + win.search(addressBox.val()); + }); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/media/media.js b/php/kindeditor_demo/kindeditor/plugins/media/media.js new file mode 100755 index 0000000..ef1887e --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/media/media.js @@ -0,0 +1,170 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('media', function(K) { + var self = this, name = 'media', lang = self.lang(name + '.'), + allowMediaUpload = K.undef(self.allowMediaUpload, true), + allowFileManager = K.undef(self.allowFileManager, false), + formatUploadUrl = K.undef(self.formatUploadUrl, true), + extraParams = K.undef(self.extraFileUploadParams, {}), + filePostName = K.undef(self.filePostName, 'imgFile'), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'); + self.plugin.media = { + edit : function() { + var html = [ + '
      ', + //url + '
      ', + '', + '  ', + '  ', + '', + '', + '', + '
      ', + //width + '
      ', + '', + '', + '
      ', + //height + '
      ', + '', + '', + '
      ', + //autostart + '
      ', + '', + ' ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 450, + height : 230, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var url = K.trim(urlBox.val()), + width = widthBox.val(), + height = heightBox.val(); + if (url == 'http://' || K.invalidUrl(url)) { + alert(self.lang('invalidUrl')); + urlBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + var html = K.mediaImg(self.themesPath + 'common/blank.gif', { + src : url, + type : K.mediaType(url), + width : width, + height : height, + autostart : autostartBox[0].checked ? 'true' : 'false', + loop : 'true' + }); + self.insertHtml(html).hideDialog().focus(); + } + } + }), + div = dialog.div, + urlBox = K('[name="url"]', div), + viewServerBtn = K('[name="viewServer"]', div), + widthBox = K('[name="width"]', div), + heightBox = K('[name="height"]', div), + autostartBox = K('[name="autostart"]', div); + urlBox.val('http://'); + + if (allowMediaUpload) { + var uploadbutton = K.uploadbutton({ + button : K('.ke-upload-button', div)[0], + fieldName : filePostName, + extraParams : extraParams, + url : K.addParam(uploadJson, 'dir=media'), + afterUpload : function(data) { + dialog.hideLoading(); + if (data.error === 0) { + var url = data.url; + if (formatUploadUrl) { + url = K.formatUrl(url, 'absolute'); + } + urlBox.val(url); + if (self.afterUpload) { + self.afterUpload.call(self, url, data, name); + } + alert(self.lang('uploadSuccess')); + } else { + alert(data.message); + } + }, + afterError : function(html) { + dialog.hideLoading(); + self.errorDialog(html); + } + }); + uploadbutton.fileBox.change(function(e) { + dialog.showLoading(self.lang('uploadLoading')); + uploadbutton.submit(); + }); + } else { + K('.ke-upload-button', div).hide(); + } + + if (allowFileManager) { + viewServerBtn.click(function(e) { + self.loadPlugin('filemanager', function() { + self.plugin.filemanagerDialog({ + viewType : 'LIST', + dirName : 'media', + clickFn : function(url, title) { + if (self.dialogs.length > 1) { + K('[name="url"]', div).val(url); + if (self.afterSelectFile) { + self.afterSelectFile.call(self, url); + } + self.hideDialog(); + } + } + }); + }); + }); + } else { + viewServerBtn.hide(); + } + + var img = self.plugin.getSelectedMedia(); + if (img) { + var attrs = K.mediaAttrs(img.attr('data-ke-tag')); + urlBox.val(attrs.src); + widthBox.val(K.removeUnit(img.css('width')) || attrs.width || 0); + heightBox.val(K.removeUnit(img.css('height')) || attrs.height || 0); + autostartBox[0].checked = (attrs.autostart === 'true'); + } + urlBox[0].focus(); + urlBox[0].select(); + }, + 'delete' : function() { + self.plugin.getSelectedMedia().remove(); + // [IE] 删除图片后立即点击图片按钮出错 + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.media.edit); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/multiimage/images/image.png b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/image.png new file mode 100755 index 0000000..fe79cf0 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/image.png differ diff --git a/php/kindeditor_demo/kindeditor/plugins/multiimage/images/select-files-en.png b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/select-files-en.png new file mode 100755 index 0000000..a926a6e Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/select-files-en.png differ diff --git a/php/kindeditor_demo/kindeditor/plugins/multiimage/images/select-files-zh-CN.png b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/select-files-zh-CN.png new file mode 100755 index 0000000..5a31d36 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/select-files-zh-CN.png differ diff --git a/php/kindeditor_demo/kindeditor/plugins/multiimage/images/swfupload.swf b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/swfupload.swf new file mode 100755 index 0000000..e3f7670 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/plugins/multiimage/images/swfupload.swf differ diff --git a/php/kindeditor_demo/kindeditor/plugins/multiimage/multiimage.js b/php/kindeditor_demo/kindeditor/plugins/multiimage/multiimage.js new file mode 100755 index 0000000..bb629c8 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/multiimage/multiimage.js @@ -0,0 +1,1384 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + + +(function(K) { + +function KSWFUpload(options) { + this.init(options); +} +K.extend(KSWFUpload, { + init : function(options) { + var self = this; + options.afterError = options.afterError || function(str) { + alert(str); + }; + self.options = options; + self.progressbars = {}; + // template + self.div = K(options.container).html([ + '
      ', + '
      ', + '
      ', + '', + '
      ', + '
      ' + options.uploadDesc + '
      ', + '', + '', + '', + '
      ', + '
      ', + '
      ' + ].join('')); + self.bodyDiv = K('.ke-swfupload-body', self.div); + + function showError(itemDiv, msg) { + K('.ke-status > div', itemDiv).hide(); + K('.ke-message', itemDiv).addClass('ke-error').show().html(K.escape(msg)); + } + + var settings = { + debug : false, + upload_url : options.uploadUrl, + flash_url : options.flashUrl, + file_post_name : options.filePostName, + button_placeholder : K('.ke-swfupload-button > input', self.div)[0], + button_image_url: options.buttonImageUrl, + button_width: options.buttonWidth, + button_height: options.buttonHeight, + button_cursor : SWFUpload.CURSOR.HAND, + file_types : options.fileTypes, + file_types_description : options.fileTypesDesc, + file_upload_limit : options.fileUploadLimit, + file_size_limit : options.fileSizeLimit, + post_params : options.postParams, + file_queued_handler : function(file) { + file.url = self.options.fileIconUrl; + self.appendFile(file); + }, + file_queue_error_handler : function(file, errorCode, message) { + var errorName = ''; + switch (errorCode) { + case SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED: + errorName = options.queueLimitExceeded; + break; + case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT: + errorName = options.fileExceedsSizeLimit; + break; + case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE: + errorName = options.zeroByteFile; + break; + case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE: + errorName = options.invalidFiletype; + break; + default: + errorName = options.unknownError; + break; + } + K.DEBUG && alert(errorName); + }, + upload_start_handler : function(file) { + var self = this; + var itemDiv = K('div[data-id="' + file.id + '"]', self.bodyDiv); + K('.ke-status > div', itemDiv).hide(); + K('.ke-progressbar', itemDiv).show(); + }, + upload_progress_handler : function(file, bytesLoaded, bytesTotal) { + var percent = Math.round(bytesLoaded * 100 / bytesTotal); + var progressbar = self.progressbars[file.id]; + progressbar.bar.css('width', Math.round(percent * 80 / 100) + 'px'); + progressbar.percent.html(percent + '%'); + }, + upload_error_handler : function(file, errorCode, message) { + if (file && file.filestatus == SWFUpload.FILE_STATUS.ERROR) { + var itemDiv = K('div[data-id="' + file.id + '"]', self.bodyDiv).eq(0); + showError(itemDiv, self.options.errorMessage); + } + }, + upload_success_handler : function(file, serverData) { + var itemDiv = K('div[data-id="' + file.id + '"]', self.bodyDiv).eq(0); + var data = {}; + try { + data = K.json(serverData); + } catch (e) { + self.options.afterError.call(this, '' + serverData + ''); + } + if (data.error !== 0) { + showError(itemDiv, K.DEBUG ? data.message : self.options.errorMessage); + return; + } + file.url = data.url; + K('.ke-img', itemDiv).attr('src', file.url).attr('data-status', file.filestatus).data('data', data); + K('.ke-status > div', itemDiv).hide(); + } + }; + self.swfu = new SWFUpload(settings); + + K('.ke-swfupload-startupload input', self.div).click(function() { + self.swfu.startUpload(); + }); + }, + getUrlList : function() { + var list = []; + K('.ke-img', self.bodyDiv).each(function() { + var img = K(this); + var status = img.attr('data-status'); + if (status == SWFUpload.FILE_STATUS.COMPLETE) { + list.push(img.data('data')); + } + }); + return list; + }, + removeFile : function(fileId) { + var self = this; + self.swfu.cancelUpload(fileId); + var itemDiv = K('div[data-id="' + fileId + '"]', self.bodyDiv); + K('.ke-photo', itemDiv).unbind(); + K('.ke-delete', itemDiv).unbind(); + itemDiv.remove(); + }, + removeFiles : function() { + var self = this; + K('.ke-item', self.bodyDiv).each(function() { + self.removeFile(K(this).attr('data-id')); + }); + }, + appendFile : function(file) { + var self = this; + var itemDiv = K('
      '); + self.bodyDiv.append(itemDiv); + var photoDiv = K('
      ') + .mouseover(function(e) { + K(this).addClass('ke-on'); + }) + .mouseout(function(e) { + K(this).removeClass('ke-on'); + }); + itemDiv.append(photoDiv); + + var img = K('' + file.name + ''); + photoDiv.append(img); + K('').appendTo(photoDiv).click(function() { + self.removeFile(file.id); + }); + var statusDiv = K('
      ').appendTo(photoDiv); + // progressbar + K(['
      ', + '
      ', + '
      0%
      '].join('')).hide().appendTo(statusDiv); + // message + K('
      ' + self.options.pendingMessage + '
      ').appendTo(statusDiv); + + itemDiv.append('
      ' + file.name + '
      '); + + self.progressbars[file.id] = { + bar : K('.ke-progressbar-bar-inner', photoDiv), + percent : K('.ke-progressbar-percent', photoDiv) + }; + }, + remove : function() { + this.removeFiles(); + this.swfu.destroy(); + this.div.html(''); + } +}); + +K.swfupload = function(element, options) { + return new KSWFUpload(element, options); +}; + +})(KindEditor); + +KindEditor.plugin('multiimage', function(K) { + var self = this, name = 'multiimage', + formatUploadUrl = K.undef(self.formatUploadUrl, true), + uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'), + imgPath = self.pluginsPath + 'multiimage/images/', + imageSizeLimit = K.undef(self.imageSizeLimit, '1MB'), + imageFileTypes = K.undef(self.imageFileTypes, '*.jpg;*.gif;*.png'), + imageUploadLimit = K.undef(self.imageUploadLimit, 20), + filePostName = K.undef(self.filePostName, 'imgFile'), + lang = self.lang(name + '.'); + + self.plugin.multiImageDialog = function(options) { + var clickFn = options.clickFn, + uploadDesc = K.tmpl(lang.uploadDesc, {uploadLimit : imageUploadLimit, sizeLimit : imageSizeLimit}); + var html = [ + '
      ', + '
      ', + '
      ', + '
      ' + ].join(''); + var dialog = self.createDialog({ + name : name, + width : 650, + height : 510, + title : self.lang(name), + body : html, + previewBtn : { + name : lang.insertAll, + click : function(e) { + clickFn.call(self, swfupload.getUrlList()); + } + }, + yesBtn : { + name : lang.clearAll, + click : function(e) { + swfupload.removeFiles(); + } + }, + beforeRemove : function() { + // IE9 bugfix: https://github.com/kindsoft/kindeditor/issues/72 + if (!K.IE || K.V <= 8) { + swfupload.remove(); + } + } + }), + div = dialog.div; + + var swfupload = K.swfupload({ + container : K('.swfupload', div), + buttonImageUrl : imgPath + (self.langType == 'zh-CN' ? 'select-files-zh-CN.png' : 'select-files-en.png'), + buttonWidth : self.langType == 'zh-CN' ? 72 : 88, + buttonHeight : 23, + fileIconUrl : imgPath + 'image.png', + uploadDesc : uploadDesc, + startButtonValue : lang.startUpload, + uploadUrl : K.addParam(uploadJson, 'dir=image'), + flashUrl : imgPath + 'swfupload.swf', + filePostName : filePostName, + fileTypes : '*.jpg;*.jpeg;*.gif;*.png;*.bmp', + fileTypesDesc : 'Image Files', + fileUploadLimit : imageUploadLimit, + fileSizeLimit : imageSizeLimit, + postParams : K.undef(self.extraFileUploadParams, {}), + queueLimitExceeded : lang.queueLimitExceeded, + fileExceedsSizeLimit : lang.fileExceedsSizeLimit, + zeroByteFile : lang.zeroByteFile, + invalidFiletype : lang.invalidFiletype, + unknownError : lang.unknownError, + pendingMessage : lang.pending, + errorMessage : lang.uploadError, + afterError : function(html) { + self.errorDialog(html); + } + }); + + return dialog; + }; + self.clickToolbar(name, function() { + self.plugin.multiImageDialog({ + clickFn : function (urlList) { + if (urlList.length === 0) { + return; + } + K.each(urlList, function(i, data) { + if (self.afterUpload) { + self.afterUpload.call(self, data.url, data, 'multiimage'); + } + self.exec('insertimage', data.url, data.title, data.width, data.height, data.border, data.align); + }); + // Bugfix: [Firefox] 上传图片后,总是出现正在加载的样式,需要延迟执行hideDialog + setTimeout(function() { + self.hideDialog().focus(); + }, 0); + } + }); + }); +}); + + +/** + * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com + * + * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/ + * + * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilz閚 and Mammon Media and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ + + +/* ******************* */ +/* Constructor & Init */ +/* ******************* */ + +(function() { + +window.SWFUpload = function (settings) { + this.initSWFUpload(settings); +}; + +SWFUpload.prototype.initSWFUpload = function (settings) { + try { + this.customSettings = {}; // A container where developers can place their own settings associated with this instance. + this.settings = settings; + this.eventQueue = []; + this.movieName = "KindEditor_SWFUpload_" + SWFUpload.movieCount++; + this.movieElement = null; + + + // Setup global control tracking + SWFUpload.instances[this.movieName] = this; + + // Load the settings. Load the Flash movie. + this.initSettings(); + this.loadFlash(); + this.displayDebugInfo(); + } catch (ex) { + delete SWFUpload.instances[this.movieName]; + throw ex; + } +}; + +/* *************** */ +/* Static Members */ +/* *************** */ +SWFUpload.instances = {}; +SWFUpload.movieCount = 0; +SWFUpload.version = "2.2.0 2009-03-25"; +SWFUpload.QUEUE_ERROR = { + QUEUE_LIMIT_EXCEEDED : -100, + FILE_EXCEEDS_SIZE_LIMIT : -110, + ZERO_BYTE_FILE : -120, + INVALID_FILETYPE : -130 +}; +SWFUpload.UPLOAD_ERROR = { + HTTP_ERROR : -200, + MISSING_UPLOAD_URL : -210, + IO_ERROR : -220, + SECURITY_ERROR : -230, + UPLOAD_LIMIT_EXCEEDED : -240, + UPLOAD_FAILED : -250, + SPECIFIED_FILE_ID_NOT_FOUND : -260, + FILE_VALIDATION_FAILED : -270, + FILE_CANCELLED : -280, + UPLOAD_STOPPED : -290 +}; +SWFUpload.FILE_STATUS = { + QUEUED : -1, + IN_PROGRESS : -2, + ERROR : -3, + COMPLETE : -4, + CANCELLED : -5 +}; +SWFUpload.BUTTON_ACTION = { + SELECT_FILE : -100, + SELECT_FILES : -110, + START_UPLOAD : -120 +}; +SWFUpload.CURSOR = { + ARROW : -1, + HAND : -2 +}; +SWFUpload.WINDOW_MODE = { + WINDOW : "window", + TRANSPARENT : "transparent", + OPAQUE : "opaque" +}; + +// Private: takes a URL, determines if it is relative and converts to an absolute URL +// using the current site. Only processes the URL if it can, otherwise returns the URL untouched +SWFUpload.completeURL = function(url) { + if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) { + return url; + } + + var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : ""); + + var indexSlash = window.location.pathname.lastIndexOf("/"); + if (indexSlash <= 0) { + path = "/"; + } else { + path = window.location.pathname.substr(0, indexSlash) + "/"; + } + + return /*currentURL +*/ path + url; + +}; + + +/* ******************** */ +/* Instance Members */ +/* ******************** */ + +// Private: initSettings ensures that all the +// settings are set, getting a default value if one was not assigned. +SWFUpload.prototype.initSettings = function () { + this.ensureDefault = function (settingName, defaultValue) { + this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName]; + }; + + // Upload backend settings + this.ensureDefault("upload_url", ""); + this.ensureDefault("preserve_relative_urls", false); + this.ensureDefault("file_post_name", "Filedata"); + this.ensureDefault("post_params", {}); + this.ensureDefault("use_query_string", false); + this.ensureDefault("requeue_on_error", false); + this.ensureDefault("http_success", []); + this.ensureDefault("assume_success_timeout", 0); + + // File Settings + this.ensureDefault("file_types", "*.*"); + this.ensureDefault("file_types_description", "All Files"); + this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited" + this.ensureDefault("file_upload_limit", 0); + this.ensureDefault("file_queue_limit", 0); + + // Flash Settings + this.ensureDefault("flash_url", "swfupload.swf"); + this.ensureDefault("prevent_swf_caching", true); + + // Button Settings + this.ensureDefault("button_image_url", ""); + this.ensureDefault("button_width", 1); + this.ensureDefault("button_height", 1); + this.ensureDefault("button_text", ""); + this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;"); + this.ensureDefault("button_text_top_padding", 0); + this.ensureDefault("button_text_left_padding", 0); + this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES); + this.ensureDefault("button_disabled", false); + this.ensureDefault("button_placeholder_id", ""); + this.ensureDefault("button_placeholder", null); + this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW); + this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW); + + // Debug Settings + this.ensureDefault("debug", false); + this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API + + // Event Handlers + this.settings.return_upload_start_handler = this.returnUploadStart; + this.ensureDefault("swfupload_loaded_handler", null); + this.ensureDefault("file_dialog_start_handler", null); + this.ensureDefault("file_queued_handler", null); + this.ensureDefault("file_queue_error_handler", null); + this.ensureDefault("file_dialog_complete_handler", null); + + this.ensureDefault("upload_start_handler", null); + this.ensureDefault("upload_progress_handler", null); + this.ensureDefault("upload_error_handler", null); + this.ensureDefault("upload_success_handler", null); + this.ensureDefault("upload_complete_handler", null); + + this.ensureDefault("debug_handler", this.debugMessage); + + this.ensureDefault("custom_settings", {}); + + // Other settings + this.customSettings = this.settings.custom_settings; + + // Update the flash url if needed + if (!!this.settings.prevent_swf_caching) { + this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime(); + } + + if (!this.settings.preserve_relative_urls) { + //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it + this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url); + this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url); + } + + delete this.ensureDefault; +}; + +// Private: loadFlash replaces the button_placeholder element with the flash movie. +SWFUpload.prototype.loadFlash = function () { + var targetElement, tempParent; + + // Make sure an element with the ID we are going to use doesn't already exist + if (document.getElementById(this.movieName) !== null) { + throw "ID " + this.movieName + " is already in use. The Flash Object could not be added"; + } + + // Get the element where we will be placing the flash movie + targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder; + + if (targetElement == undefined) { + throw "Could not find the placeholder element: " + this.settings.button_placeholder_id; + } + + // Append the container and load the flash + tempParent = document.createElement("div"); + tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers) + targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement); + + // Fix IE Flash/Form bug + if (window[this.movieName] == undefined) { + window[this.movieName] = this.getMovieElement(); + } + +}; + +// Private: getFlashHTML generates the object tag needed to embed the flash in to the document +SWFUpload.prototype.getFlashHTML = function () { + // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay + // Fix bug for IE9 + // http://www.kindsoft.net/view.php?bbsid=7&postid=5825&pagenum=1 + var classid = ''; + if (KindEditor.IE && KindEditor.V > 8) { + classid = ' classid = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"'; + } + return ['', + '', + '', + '', + '', + '', + '', + ''].join(""); +}; + +// Private: getFlashVars builds the parameter string that will be passed +// to flash in the flashvars param. +SWFUpload.prototype.getFlashVars = function () { + // Build a string from the post param object + var paramString = this.buildParamString(); + var httpSuccessString = this.settings.http_success.join(","); + + // Build the parameter string + return ["movieName=", encodeURIComponent(this.movieName), + "&uploadURL=", encodeURIComponent(this.settings.upload_url), + "&useQueryString=", encodeURIComponent(this.settings.use_query_string), + "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error), + "&httpSuccess=", encodeURIComponent(httpSuccessString), + "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout), + "&params=", encodeURIComponent(paramString), + "&filePostName=", encodeURIComponent(this.settings.file_post_name), + "&fileTypes=", encodeURIComponent(this.settings.file_types), + "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description), + "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit), + "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit), + "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit), + "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled), + "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url), + "&buttonWidth=", encodeURIComponent(this.settings.button_width), + "&buttonHeight=", encodeURIComponent(this.settings.button_height), + "&buttonText=", encodeURIComponent(this.settings.button_text), + "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding), + "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding), + "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style), + "&buttonAction=", encodeURIComponent(this.settings.button_action), + "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled), + "&buttonCursor=", encodeURIComponent(this.settings.button_cursor) + ].join(""); +}; + +// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload +// The element is cached after the first lookup +SWFUpload.prototype.getMovieElement = function () { + if (this.movieElement == undefined) { + this.movieElement = document.getElementById(this.movieName); + } + + if (this.movieElement === null) { + throw "Could not find Flash element"; + } + + return this.movieElement; +}; + +// Private: buildParamString takes the name/value pairs in the post_params setting object +// and joins them up in to a string formatted "name=value&name=value" +SWFUpload.prototype.buildParamString = function () { + var postParams = this.settings.post_params; + var paramStringPairs = []; + + if (typeof(postParams) === "object") { + for (var name in postParams) { + if (postParams.hasOwnProperty(name)) { + paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString())); + } + } + } + + return paramStringPairs.join("&"); +}; + +// Public: Used to remove a SWFUpload instance from the page. This method strives to remove +// all references to the SWF, and other objects so memory is properly freed. +// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state. +// Credits: Major improvements provided by steffen +SWFUpload.prototype.destroy = function () { + try { + // Make sure Flash is done before we try to remove it + this.cancelUpload(null, false); + + + // Remove the SWFUpload DOM nodes + var movieElement = null; + movieElement = this.getMovieElement(); + + if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE + // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround) + for (var i in movieElement) { + try { + if (typeof(movieElement[i]) === "function") { + movieElement[i] = null; + } + } catch (ex1) {} + } + + // Remove the Movie Element from the page + try { + movieElement.parentNode.removeChild(movieElement); + } catch (ex) {} + } + + // Remove IE form fix reference + window[this.movieName] = null; + + // Destroy other references + SWFUpload.instances[this.movieName] = null; + delete SWFUpload.instances[this.movieName]; + + this.movieElement = null; + this.settings = null; + this.customSettings = null; + this.eventQueue = null; + this.movieName = null; + + + return true; + } catch (ex2) { + return false; + } +}; + + +// Public: displayDebugInfo prints out settings and configuration +// information about this SWFUpload instance. +// This function (and any references to it) can be deleted when placing +// SWFUpload in production. +SWFUpload.prototype.displayDebugInfo = function () { + this.debug( + [ + "---SWFUpload Instance Info---\n", + "Version: ", SWFUpload.version, "\n", + "Movie Name: ", this.movieName, "\n", + "Settings:\n", + "\t", "upload_url: ", this.settings.upload_url, "\n", + "\t", "flash_url: ", this.settings.flash_url, "\n", + "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n", + "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n", + "\t", "http_success: ", this.settings.http_success.join(", "), "\n", + "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n", + "\t", "file_post_name: ", this.settings.file_post_name, "\n", + "\t", "post_params: ", this.settings.post_params.toString(), "\n", + "\t", "file_types: ", this.settings.file_types, "\n", + "\t", "file_types_description: ", this.settings.file_types_description, "\n", + "\t", "file_size_limit: ", this.settings.file_size_limit, "\n", + "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n", + "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n", + "\t", "debug: ", this.settings.debug.toString(), "\n", + + "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n", + + "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n", + "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n", + "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n", + "\t", "button_width: ", this.settings.button_width.toString(), "\n", + "\t", "button_height: ", this.settings.button_height.toString(), "\n", + "\t", "button_text: ", this.settings.button_text.toString(), "\n", + "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n", + "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n", + "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n", + "\t", "button_action: ", this.settings.button_action.toString(), "\n", + "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n", + + "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n", + "Event Handlers:\n", + "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n", + "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n", + "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n", + "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n", + "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n", + "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n", + "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n", + "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n", + "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n", + "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n" + ].join("") + ); +}; + +/* Note: addSetting and getSetting are no longer used by SWFUpload but are included + the maintain v2 API compatibility +*/ +// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used. +SWFUpload.prototype.addSetting = function (name, value, default_value) { + if (value == undefined) { + return (this.settings[name] = default_value); + } else { + return (this.settings[name] = value); + } +}; + +// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found. +SWFUpload.prototype.getSetting = function (name) { + if (this.settings[name] != undefined) { + return this.settings[name]; + } + + return ""; +}; + + + +// Private: callFlash handles function calls made to the Flash element. +// Calls are made with a setTimeout for some functions to work around +// bugs in the ExternalInterface library. +SWFUpload.prototype.callFlash = function (functionName, argumentArray) { + argumentArray = argumentArray || []; + + var movieElement = this.getMovieElement(); + var returnValue, returnString; + + // Flash's method if calling ExternalInterface methods (code adapted from MooTools). + try { + returnString = movieElement.CallFunction('' + __flash__argumentsToXML(argumentArray, 0) + ''); + returnValue = eval(returnString); + } catch (ex) { + throw "Call to " + functionName + " failed"; + } + + // Unescape file post param values + if (returnValue != undefined && typeof returnValue.post === "object") { + returnValue = this.unescapeFilePostParams(returnValue); + } + + return returnValue; +}; + +/* ***************************** + -- Flash control methods -- + Your UI should use these + to operate SWFUpload + ***************************** */ + +// WARNING: this function does not work in Flash Player 10 +// Public: selectFile causes a File Selection Dialog window to appear. This +// dialog only allows 1 file to be selected. +SWFUpload.prototype.selectFile = function () { + this.callFlash("SelectFile"); +}; + +// WARNING: this function does not work in Flash Player 10 +// Public: selectFiles causes a File Selection Dialog window to appear/ This +// dialog allows the user to select any number of files +// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names. +// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around +// for this bug. +SWFUpload.prototype.selectFiles = function () { + this.callFlash("SelectFiles"); +}; + + +// Public: startUpload starts uploading the first file in the queue unless +// the optional parameter 'fileID' specifies the ID +SWFUpload.prototype.startUpload = function (fileID) { + this.callFlash("StartUpload", [fileID]); +}; + +// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index. +// If you do not specify a fileID the current uploading file or first file in the queue is cancelled. +// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter. +SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) { + if (triggerErrorEvent !== false) { + triggerErrorEvent = true; + } + this.callFlash("CancelUpload", [fileID, triggerErrorEvent]); +}; + +// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue. +// If nothing is currently uploading then nothing happens. +SWFUpload.prototype.stopUpload = function () { + this.callFlash("StopUpload"); +}; + +/* ************************ + * Settings methods + * These methods change the SWFUpload settings. + * SWFUpload settings should not be changed directly on the settings object + * since many of the settings need to be passed to Flash in order to take + * effect. + * *********************** */ + +// Public: getStats gets the file statistics object. +SWFUpload.prototype.getStats = function () { + return this.callFlash("GetStats"); +}; + +// Public: setStats changes the SWFUpload statistics. You shouldn't need to +// change the statistics but you can. Changing the statistics does not +// affect SWFUpload accept for the successful_uploads count which is used +// by the upload_limit setting to determine how many files the user may upload. +SWFUpload.prototype.setStats = function (statsObject) { + this.callFlash("SetStats", [statsObject]); +}; + +// Public: getFile retrieves a File object by ID or Index. If the file is +// not found then 'null' is returned. +SWFUpload.prototype.getFile = function (fileID) { + if (typeof(fileID) === "number") { + return this.callFlash("GetFileByIndex", [fileID]); + } else { + return this.callFlash("GetFile", [fileID]); + } +}; + +// Public: addFileParam sets a name/value pair that will be posted with the +// file specified by the Files ID. If the name already exists then the +// exiting value will be overwritten. +SWFUpload.prototype.addFileParam = function (fileID, name, value) { + return this.callFlash("AddFileParam", [fileID, name, value]); +}; + +// Public: removeFileParam removes a previously set (by addFileParam) name/value +// pair from the specified file. +SWFUpload.prototype.removeFileParam = function (fileID, name) { + this.callFlash("RemoveFileParam", [fileID, name]); +}; + +// Public: setUploadUrl changes the upload_url setting. +SWFUpload.prototype.setUploadURL = function (url) { + this.settings.upload_url = url.toString(); + this.callFlash("SetUploadURL", [url]); +}; + +// Public: setPostParams changes the post_params setting +SWFUpload.prototype.setPostParams = function (paramsObject) { + this.settings.post_params = paramsObject; + this.callFlash("SetPostParams", [paramsObject]); +}; + +// Public: addPostParam adds post name/value pair. Each name can have only one value. +SWFUpload.prototype.addPostParam = function (name, value) { + this.settings.post_params[name] = value; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; + +// Public: removePostParam deletes post name/value pair. +SWFUpload.prototype.removePostParam = function (name) { + delete this.settings.post_params[name]; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; + +// Public: setFileTypes changes the file_types setting and the file_types_description setting +SWFUpload.prototype.setFileTypes = function (types, description) { + this.settings.file_types = types; + this.settings.file_types_description = description; + this.callFlash("SetFileTypes", [types, description]); +}; + +// Public: setFileSizeLimit changes the file_size_limit setting +SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) { + this.settings.file_size_limit = fileSizeLimit; + this.callFlash("SetFileSizeLimit", [fileSizeLimit]); +}; + +// Public: setFileUploadLimit changes the file_upload_limit setting +SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) { + this.settings.file_upload_limit = fileUploadLimit; + this.callFlash("SetFileUploadLimit", [fileUploadLimit]); +}; + +// Public: setFileQueueLimit changes the file_queue_limit setting +SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) { + this.settings.file_queue_limit = fileQueueLimit; + this.callFlash("SetFileQueueLimit", [fileQueueLimit]); +}; + +// Public: setFilePostName changes the file_post_name setting +SWFUpload.prototype.setFilePostName = function (filePostName) { + this.settings.file_post_name = filePostName; + this.callFlash("SetFilePostName", [filePostName]); +}; + +// Public: setUseQueryString changes the use_query_string setting +SWFUpload.prototype.setUseQueryString = function (useQueryString) { + this.settings.use_query_string = useQueryString; + this.callFlash("SetUseQueryString", [useQueryString]); +}; + +// Public: setRequeueOnError changes the requeue_on_error setting +SWFUpload.prototype.setRequeueOnError = function (requeueOnError) { + this.settings.requeue_on_error = requeueOnError; + this.callFlash("SetRequeueOnError", [requeueOnError]); +}; + +// Public: setHTTPSuccess changes the http_success setting +SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) { + if (typeof http_status_codes === "string") { + http_status_codes = http_status_codes.replace(" ", "").split(","); + } + + this.settings.http_success = http_status_codes; + this.callFlash("SetHTTPSuccess", [http_status_codes]); +}; + +// Public: setHTTPSuccess changes the http_success setting +SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) { + this.settings.assume_success_timeout = timeout_seconds; + this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]); +}; + +// Public: setDebugEnabled changes the debug_enabled setting +SWFUpload.prototype.setDebugEnabled = function (debugEnabled) { + this.settings.debug_enabled = debugEnabled; + this.callFlash("SetDebugEnabled", [debugEnabled]); +}; + +// Public: setButtonImageURL loads a button image sprite +SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) { + if (buttonImageURL == undefined) { + buttonImageURL = ""; + } + + this.settings.button_image_url = buttonImageURL; + this.callFlash("SetButtonImageURL", [buttonImageURL]); +}; + +// Public: setButtonDimensions resizes the Flash Movie and button +SWFUpload.prototype.setButtonDimensions = function (width, height) { + this.settings.button_width = width; + this.settings.button_height = height; + + var movie = this.getMovieElement(); + if (movie != undefined) { + movie.style.width = width + "px"; + movie.style.height = height + "px"; + } + + this.callFlash("SetButtonDimensions", [width, height]); +}; +// Public: setButtonText Changes the text overlaid on the button +SWFUpload.prototype.setButtonText = function (html) { + this.settings.button_text = html; + this.callFlash("SetButtonText", [html]); +}; +// Public: setButtonTextPadding changes the top and left padding of the text overlay +SWFUpload.prototype.setButtonTextPadding = function (left, top) { + this.settings.button_text_top_padding = top; + this.settings.button_text_left_padding = left; + this.callFlash("SetButtonTextPadding", [left, top]); +}; + +// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button +SWFUpload.prototype.setButtonTextStyle = function (css) { + this.settings.button_text_style = css; + this.callFlash("SetButtonTextStyle", [css]); +}; +// Public: setButtonDisabled disables/enables the button +SWFUpload.prototype.setButtonDisabled = function (isDisabled) { + this.settings.button_disabled = isDisabled; + this.callFlash("SetButtonDisabled", [isDisabled]); +}; +// Public: setButtonAction sets the action that occurs when the button is clicked +SWFUpload.prototype.setButtonAction = function (buttonAction) { + this.settings.button_action = buttonAction; + this.callFlash("SetButtonAction", [buttonAction]); +}; + +// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button +SWFUpload.prototype.setButtonCursor = function (cursor) { + this.settings.button_cursor = cursor; + this.callFlash("SetButtonCursor", [cursor]); +}; + +/* ******************************* + Flash Event Interfaces + These functions are used by Flash to trigger the various + events. + + All these functions a Private. + + Because the ExternalInterface library is buggy the event calls + are added to a queue and the queue then executed by a setTimeout. + This ensures that events are executed in a determinate order and that + the ExternalInterface bugs are avoided. +******************************* */ + +SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) { + // Warning: Don't call this.debug inside here or you'll create an infinite loop + + if (argumentArray == undefined) { + argumentArray = []; + } else if (!(argumentArray instanceof Array)) { + argumentArray = [argumentArray]; + } + + var self = this; + if (typeof this.settings[handlerName] === "function") { + // Queue the event + this.eventQueue.push(function () { + this.settings[handlerName].apply(this, argumentArray); + }); + + // Execute the next queued event + setTimeout(function () { + self.executeNextEvent(); + }, 0); + + } else if (this.settings[handlerName] !== null) { + throw "Event handler " + handlerName + " is unknown or is not a function"; + } +}; + +// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout +// we must queue them in order to garentee that they are executed in order. +SWFUpload.prototype.executeNextEvent = function () { + // Warning: Don't call this.debug inside here or you'll create an infinite loop + + var f = this.eventQueue ? this.eventQueue.shift() : null; + if (typeof(f) === "function") { + f.apply(this); + } +}; + +// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have +// properties that contain characters that are not valid for JavaScript identifiers. To work around this +// the Flash Component escapes the parameter names and we must unescape again before passing them along. +SWFUpload.prototype.unescapeFilePostParams = function (file) { + var reg = /[$]([0-9a-f]{4})/i; + var unescapedPost = {}; + var uk; + + if (file != undefined) { + for (var k in file.post) { + if (file.post.hasOwnProperty(k)) { + uk = k; + var match; + while ((match = reg.exec(uk)) !== null) { + uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16))); + } + unescapedPost[uk] = file.post[k]; + } + } + + file.post = unescapedPost; + } + + return file; +}; + +// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working) +SWFUpload.prototype.testExternalInterface = function () { + try { + return this.callFlash("TestExternalInterface"); + } catch (ex) { + return false; + } +}; + +// Private: This event is called by Flash when it has finished loading. Don't modify this. +// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded. +SWFUpload.prototype.flashReady = function () { + // Check that the movie element is loaded correctly with its ExternalInterface methods defined + var movieElement = this.getMovieElement(); + + if (!movieElement) { + this.debug("Flash called back ready but the flash movie can't be found."); + return; + } + + this.cleanUp(movieElement); + + this.queueEvent("swfupload_loaded_handler"); +}; + +// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE. +// This function is called by Flash each time the ExternalInterface functions are created. +SWFUpload.prototype.cleanUp = function (movieElement) { + // Pro-actively unhook all the Flash functions + try { + if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE + this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)"); + for (var key in movieElement) { + try { + if (typeof(movieElement[key]) === "function") { + movieElement[key] = null; + } + } catch (ex) { + } + } + } + } catch (ex1) { + + } + + // Fix Flashes own cleanup code so if the SWFMovie was removed from the page + // it doesn't display errors. + window["__flash__removeCallback"] = function (instance, name) { + try { + if (instance) { + instance[name] = null; + } + } catch (flashEx) { + + } + }; + +}; + + +/* This is a chance to do something before the browse window opens */ +SWFUpload.prototype.fileDialogStart = function () { + this.queueEvent("file_dialog_start_handler"); +}; + + +/* Called when a file is successfully added to the queue. */ +SWFUpload.prototype.fileQueued = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queued_handler", file); +}; + + +/* Handle errors that occur when an attempt to queue a file fails. */ +SWFUpload.prototype.fileQueueError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queue_error_handler", [file, errorCode, message]); +}; + +/* Called after the file dialog has closed and the selected files have been queued. + You could call startUpload here if you want the queued files to begin uploading immediately. */ +SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) { + this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]); +}; + +SWFUpload.prototype.uploadStart = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("return_upload_start_handler", file); +}; + +SWFUpload.prototype.returnUploadStart = function (file) { + var returnValue; + if (typeof this.settings.upload_start_handler === "function") { + file = this.unescapeFilePostParams(file); + returnValue = this.settings.upload_start_handler.call(this, file); + } else if (this.settings.upload_start_handler != undefined) { + throw "upload_start_handler must be a function"; + } + + // Convert undefined to true so if nothing is returned from the upload_start_handler it is + // interpretted as 'true'. + if (returnValue === undefined) { + returnValue = true; + } + + returnValue = !!returnValue; + + this.callFlash("ReturnUploadStart", [returnValue]); +}; + + + +SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]); +}; + +SWFUpload.prototype.uploadError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_error_handler", [file, errorCode, message]); +}; + +SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_success_handler", [file, serverData, responseReceived]); +}; + +SWFUpload.prototype.uploadComplete = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_complete_handler", file); +}; + +/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the + internal debug console. You can override this event and have messages written where you want. */ +SWFUpload.prototype.debug = function (message) { + this.queueEvent("debug_handler", message); +}; + + +/* ********************************** + Debug Console + The debug console is a self contained, in page location + for debug message to be sent. The Debug Console adds + itself to the body if necessary. + + The console is automatically scrolled as messages appear. + + If you are using your own debug handler or when you deploy to production and + have debug disabled you can remove these functions to reduce the file size + and complexity. +********************************** */ + +// Private: debugMessage is the default debug_handler. If you want to print debug messages +// call the debug() function. When overriding the function your own function should +// check to see if the debug setting is true before outputting debug information. +SWFUpload.prototype.debugMessage = function (message) { + if (this.settings.debug) { + var exceptionMessage, exceptionValues = []; + + // Check for an exception object and print it nicely + if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") { + for (var key in message) { + if (message.hasOwnProperty(key)) { + exceptionValues.push(key + ": " + message[key]); + } + } + exceptionMessage = exceptionValues.join("\n") || ""; + exceptionValues = exceptionMessage.split("\n"); + exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: "); + SWFUpload.Console.writeLine(exceptionMessage); + } else { + SWFUpload.Console.writeLine(message); + } + } +}; + +SWFUpload.Console = {}; +SWFUpload.Console.writeLine = function (message) { + var console, documentForm; + + try { + console = document.getElementById("SWFUpload_Console"); + + if (!console) { + documentForm = document.createElement("form"); + document.getElementsByTagName("body")[0].appendChild(documentForm); + + console = document.createElement("textarea"); + console.id = "SWFUpload_Console"; + console.style.fontFamily = "monospace"; + console.setAttribute("wrap", "off"); + console.wrap = "off"; + console.style.overflow = "auto"; + console.style.width = "700px"; + console.style.height = "350px"; + console.style.margin = "5px"; + documentForm.appendChild(console); + } + + console.value += message + "\n"; + + console.scrollTop = console.scrollHeight - console.clientHeight; + } catch (ex) { + alert("Exception: " + ex.name + " Message: " + ex.message); + } +}; + +})(); + +(function() { +/* + Queue Plug-in + + Features: + *Adds a cancelQueue() method for cancelling the entire queue. + *All queued files are uploaded when startUpload() is called. + *If false is returned from uploadComplete then the queue upload is stopped. + If false is not returned (strict comparison) then the queue upload is continued. + *Adds a QueueComplete event that is fired when all the queued files have finished uploading. + Set the event handler with the queue_complete_handler setting. + + */ + +if (typeof(SWFUpload) === "function") { + SWFUpload.queue = {}; + + SWFUpload.prototype.initSettings = (function (oldInitSettings) { + return function () { + if (typeof(oldInitSettings) === "function") { + oldInitSettings.call(this); + } + + this.queueSettings = {}; + + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + + this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler; + this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler; + this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler; + this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler; + + this.settings.queue_complete_handler = this.settings.queue_complete_handler || null; + }; + })(SWFUpload.prototype.initSettings); + + SWFUpload.prototype.startUpload = function (fileID) { + this.queueSettings.queue_cancelled_flag = false; + this.callFlash("StartUpload", [fileID]); + }; + + SWFUpload.prototype.cancelQueue = function () { + this.queueSettings.queue_cancelled_flag = true; + this.stopUpload(); + + var stats = this.getStats(); + while (stats.files_queued > 0) { + this.cancelUpload(); + stats = this.getStats(); + } + }; + + SWFUpload.queue.uploadStartHandler = function (file) { + var returnValue; + if (typeof(this.queueSettings.user_upload_start_handler) === "function") { + returnValue = this.queueSettings.user_upload_start_handler.call(this, file); + } + + // To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value. + returnValue = (returnValue === false) ? false : true; + + this.queueSettings.queue_cancelled_flag = !returnValue; + + return returnValue; + }; + + SWFUpload.queue.uploadCompleteHandler = function (file) { + var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler; + var continueUpload; + + if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) { + this.queueSettings.queue_upload_count++; + } + + if (typeof(user_upload_complete_handler) === "function") { + continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true; + } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) { + // If the file was stopped and re-queued don't restart the upload + continueUpload = false; + } else { + continueUpload = true; + } + + if (continueUpload) { + var stats = this.getStats(); + if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) { + this.startUpload(); + } else if (this.queueSettings.queue_cancelled_flag === false) { + this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]); + this.queueSettings.queue_upload_count = 0; + } else { + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + } + } + }; +} + +})(); diff --git a/php/kindeditor_demo/kindeditor/plugins/pagebreak/pagebreak.js b/php/kindeditor_demo/kindeditor/plugins/pagebreak/pagebreak.js new file mode 100755 index 0000000..3898e32 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/pagebreak/pagebreak.js @@ -0,0 +1,27 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('pagebreak', function(K) { + var self = this; + var name = 'pagebreak'; + var pagebreakHtml = K.undef(self.pagebreakHtml, '
      '); + + self.clickToolbar(name, function() { + var cmd = self.cmd, range = cmd.range; + self.focus(); + var tail = self.newlineTag == 'br' || K.WEBKIT ? '' : ''; + self.insertHtml(pagebreakHtml + tail); + if (tail !== '') { + var p = K('#__kindeditor_tail_tag__', self.edit.doc); + range.selectNodeContents(p[0]); + p.removeAttr('id'); + cmd.select(); + } + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/plainpaste/plainpaste.js b/php/kindeditor_demo/kindeditor/plugins/plainpaste/plainpaste.js new file mode 100755 index 0000000..1faec86 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/plainpaste/plainpaste.js @@ -0,0 +1,41 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('plainpaste', function(K) { + var self = this, name = 'plainpaste'; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = '
      ' + + '
      ' + lang.comment + '
      ' + + '' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var html = textarea.val(); + html = K.escape(html); + html = html.replace(/ {2}/g, '  '); + if (self.newlineTag == 'p') { + html = html.replace(/^/, '

      ').replace(/$/, '

      ').replace(/\n/g, '

      '); + } else { + html = html.replace(/\n/g, '
      $&'); + } + self.insertHtml(html).hideDialog().focus(); + } + } + }), + textarea = K('textarea', dialog.div); + textarea[0].focus(); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/preview/preview.js b/php/kindeditor_demo/kindeditor/plugins/preview/preview.js new file mode 100755 index 0000000..3bbb7b5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/preview/preview.js @@ -0,0 +1,31 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('preview', function(K) { + var self = this, name = 'preview', undefined; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = '

      ' + + '' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 750, + title : self.lang(name), + body : html + }), + iframe = K('iframe', dialog.div), + doc = K.iframeDoc(iframe); + doc.open(); + doc.write(self.fullHtml()); + doc.close(); + K(doc.body).css('background-color', '#FFF'); + iframe[0].contentWindow.focus(); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/quickformat/quickformat.js b/php/kindeditor_demo/kindeditor/plugins/quickformat/quickformat.js new file mode 100755 index 0000000..a7af1e5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/quickformat/quickformat.js @@ -0,0 +1,81 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('quickformat', function(K) { + var self = this, name = 'quickformat', + blockMap = K.toMap('blockquote,center,div,h1,h2,h3,h4,h5,h6,p'); + function getFirstChild(knode) { + var child = knode.first(); + while (child && child.first()) { + child = child.first(); + } + return child; + } + self.clickToolbar(name, function() { + self.focus(); + var doc = self.edit.doc, + range = self.cmd.range, + child = K(doc.body).first(), next, + nodeList = [], subList = [], + bookmark = range.createBookmark(true); + while(child) { + next = child.next(); + var firstChild = getFirstChild(child); + if (!firstChild || firstChild.name != 'img') { + if (blockMap[child.name]) { + child.html(child.html().replace(/^(\s| | )+/ig, '')); + child.css('text-indent', '2em'); + } else { + subList.push(child); + } + if (!next || (blockMap[next.name] || blockMap[child.name] && !blockMap[next.name])) { + if (subList.length > 0) { + nodeList.push(subList); + } + subList = []; + } + } + child = next; + } + K.each(nodeList, function(i, subList) { + var wrapper = K('

      ', doc); + subList[0].before(wrapper); + K.each(subList, function(i, knode) { + wrapper.append(knode); + }); + }); + range.moveToBookmark(bookmark); + self.addBookmark(); + }); +}); + +/** +-------------------------- +abcd
      +1234
      + +to + +

      + abcd
      + 1234
      +

      + +-------------------------- + +  abcd1233 +

      1234

      + +to + +

      abcd1233

      +

      1234

      + +-------------------------- +*/ \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/plugins/table/table.js b/php/kindeditor_demo/kindeditor/plugins/table/table.js new file mode 100755 index 0000000..d3f1232 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/table/table.js @@ -0,0 +1,712 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('table', function(K) { + var self = this, name = 'table', lang = self.lang(name + '.'), zeroborder = 'ke-zeroborder'; + // 设置颜色 + function _setColor(box, color) { + color = color.toUpperCase(); + box.css('background-color', color); + box.css('color', color === '#000000' ? '#FFFFFF' : '#000000'); + box.html(color); + } + // 初始化取色器 + var pickerList = []; + function _initColorPicker(dialogDiv, colorBox) { + colorBox.bind('click,mousedown', function(e){ + e.stopPropagation(); + }); + function removePicker() { + K.each(pickerList, function() { + this.remove(); + }); + pickerList = []; + K(document).unbind('click,mousedown', removePicker); + dialogDiv.unbind('click,mousedown', removePicker); + } + colorBox.click(function(e) { + removePicker(); + var box = K(this), + pos = box.pos(); + var picker = K.colorpicker({ + x : pos.x, + y : pos.y + box.height(), + z : 811214, + selectedColor : K(this).html(), + colors : self.colorTable, + noColor : self.lang('noColor'), + shadowMode : self.shadowMode, + click : function(color) { + _setColor(box, color); + removePicker(); + } + }); + pickerList.push(picker); + K(document).bind('click,mousedown', removePicker); + dialogDiv.bind('click,mousedown', removePicker); + }); + } + // 取得下一行cell的index + function _getCellIndex(table, row, cell) { + var rowSpanCount = 0; + for (var i = 0, len = row.cells.length; i < len; i++) { + if (row.cells[i] == cell) { + break; + } + rowSpanCount += row.cells[i].rowSpan - 1; + } + return cell.cellIndex - rowSpanCount; + } + self.plugin.table = { + //insert or modify table + prop : function(isInsert) { + var html = [ + '
      ', + //rows, cols + '
      ', + '', + lang.rows + '   ', + lang.cols + ' ', + '
      ', + //width, height + '
      ', + '', + lang.width + '   ', + '   ', + lang.height + '   ', + '', + '
      ', + //space, padding + '
      ', + '', + lang.padding + '   ', + lang.spacing + ' ', + '
      ', + //align + '
      ', + '', + '', + '
      ', + //border + '
      ', + '', + lang.borderWidth + '   ', + lang.borderColor + ' ', + '
      ', + //background color + '
      ', + '', + '', + '
      ', + '
      ' + ].join(''); + var bookmark = self.cmd.range.createBookmark(); + var dialog = self.createDialog({ + name : name, + width : 500, + title : self.lang(name), + body : html, + beforeRemove : function() { + colorBox.unbind(); + }, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var rows = rowsBox.val(), + cols = colsBox.val(), + width = widthBox.val(), + height = heightBox.val(), + widthType = widthTypeBox.val(), + heightType = heightTypeBox.val(), + padding = paddingBox.val(), + spacing = spacingBox.val(), + align = alignBox.val(), + border = borderBox.val(), + borderColor = K(colorBox[0]).html() || '', + bgColor = K(colorBox[1]).html() || ''; + if (rows == 0 || !/^\d+$/.test(rows)) { + alert(self.lang('invalidRows')); + rowsBox[0].focus(); + return; + } + if (cols == 0 || !/^\d+$/.test(cols)) { + alert(self.lang('invalidRows')); + colsBox[0].focus(); + return; + } + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + if (!/^\d*$/.test(padding)) { + alert(self.lang('invalidPadding')); + paddingBox[0].focus(); + return; + } + if (!/^\d*$/.test(spacing)) { + alert(self.lang('invalidSpacing')); + spacingBox[0].focus(); + return; + } + if (!/^\d*$/.test(border)) { + alert(self.lang('invalidBorder')); + borderBox[0].focus(); + return; + } + //modify table + if (table) { + if (width !== '') { + table.width(width + widthType); + } else { + table.css('width', ''); + } + if (table[0].width !== undefined) { + table.removeAttr('width'); + } + if (height !== '') { + table.height(height + heightType); + } else { + table.css('height', ''); + } + if (table[0].height !== undefined) { + table.removeAttr('height'); + } + table.css('background-color', bgColor); + if (table[0].bgColor !== undefined) { + table.removeAttr('bgColor'); + } + if (padding !== '') { + table[0].cellPadding = padding; + } else { + table.removeAttr('cellPadding'); + } + if (spacing !== '') { + table[0].cellSpacing = spacing; + } else { + table.removeAttr('cellSpacing'); + } + if (align !== '') { + table[0].align = align; + } else { + table.removeAttr('align'); + } + if (border !== '') { + table.attr('border', border); + } else { + table.removeAttr('border'); + } + if (border === '' || border === '0') { + table.addClass(zeroborder); + } else { + table.removeClass(zeroborder); + } + if (borderColor !== '') { + table.attr('borderColor', borderColor); + } else { + table.removeAttr('borderColor'); + } + self.hideDialog().focus(); + self.cmd.range.moveToBookmark(bookmark); + self.cmd.select(); + self.addBookmark(); + return; + } + //insert new table + var style = ''; + if (width !== '') { + style += 'width:' + width + widthType + ';'; + } + if (height !== '') { + style += 'height:' + height + heightType + ';'; + } + if (bgColor !== '') { + style += 'background-color:' + bgColor + ';'; + } + var html = '') + ''; + } + html += ''; + } + html += ''; + if (!K.IE) { + html += '
      '; + } + self.insertHtml(html); + self.select().hideDialog().focus(); + self.addBookmark(); + } + } + }), + div = dialog.div, + rowsBox = K('[name="rows"]', div).val(3), + colsBox = K('[name="cols"]', div).val(2), + widthBox = K('[name="width"]', div).val(100), + heightBox = K('[name="height"]', div), + widthTypeBox = K('[name="widthType"]', div), + heightTypeBox = K('[name="heightType"]', div), + paddingBox = K('[name="padding"]', div).val(2), + spacingBox = K('[name="spacing"]', div).val(0), + alignBox = K('[name="align"]', div), + borderBox = K('[name="border"]', div).val(1), + colorBox = K('.ke-input-color', div); + _initColorPicker(div, colorBox.eq(0)); + _initColorPicker(div, colorBox.eq(1)); + _setColor(colorBox.eq(0), '#000000'); + _setColor(colorBox.eq(1), ''); + // foucs and select + rowsBox[0].focus(); + rowsBox[0].select(); + var table; + if (isInsert) { + return; + } + //get selected table node + table = self.plugin.getSelectedTable(); + if (table) { + rowsBox.val(table[0].rows.length); + colsBox.val(table[0].rows.length > 0 ? table[0].rows[0].cells.length : 0); + rowsBox.attr('disabled', true); + colsBox.attr('disabled', true); + var match, + tableWidth = table[0].style.width || table[0].width, + tableHeight = table[0].style.height || table[0].height; + if (tableWidth !== undefined && (match = /^(\d+)((?:px|%)*)$/.exec(tableWidth))) { + widthBox.val(match[1]); + widthTypeBox.val(match[2]); + } else { + widthBox.val(''); + } + if (tableHeight !== undefined && (match = /^(\d+)((?:px|%)*)$/.exec(tableHeight))) { + heightBox.val(match[1]); + heightTypeBox.val(match[2]); + } + paddingBox.val(table[0].cellPadding || ''); + spacingBox.val(table[0].cellSpacing || ''); + alignBox.val(table[0].align || ''); + borderBox.val(table[0].border === undefined ? '' : table[0].border); + _setColor(colorBox.eq(0), K.toHex(table.attr('borderColor') || '')); + _setColor(colorBox.eq(1), K.toHex(table[0].style.backgroundColor || table[0].bgColor || '')); + widthBox[0].focus(); + widthBox[0].select(); + } + }, + //modify cell + cellprop : function() { + var html = [ + '
      ', + //width, height + '
      ', + '', + lang.width + '   ', + '   ', + lang.height + '   ', + '', + '
      ', + //align + '
      ', + '', + lang.textAlign + ' ', + lang.verticalAlign + ' ', + '
      ', + //border + '
      ', + '', + lang.borderWidth + '   ', + lang.borderColor + ' ', + '
      ', + //background color + '
      ', + '', + '', + '
      ', + '
      ' + ].join(''); + var bookmark = self.cmd.range.createBookmark(); + var dialog = self.createDialog({ + name : name, + width : 500, + title : self.lang('tablecell'), + body : html, + beforeRemove : function() { + colorBox.unbind(); + }, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var width = widthBox.val(), + height = heightBox.val(), + widthType = widthTypeBox.val(), + heightType = heightTypeBox.val(), + padding = paddingBox.val(), + spacing = spacingBox.val(), + textAlign = textAlignBox.val(), + verticalAlign = verticalAlignBox.val(), + border = borderBox.val(), + borderColor = K(colorBox[0]).html() || '', + bgColor = K(colorBox[1]).html() || ''; + if (!/^\d*$/.test(width)) { + alert(self.lang('invalidWidth')); + widthBox[0].focus(); + return; + } + if (!/^\d*$/.test(height)) { + alert(self.lang('invalidHeight')); + heightBox[0].focus(); + return; + } + if (!/^\d*$/.test(border)) { + alert(self.lang('invalidBorder')); + borderBox[0].focus(); + return; + } + cell.css({ + width : width !== '' ? (width + widthType) : '', + height : height !== '' ? (height + heightType) : '', + 'background-color' : bgColor, + 'text-align' : textAlign, + 'vertical-align' : verticalAlign, + 'border-width' : border, + 'border-style' : border !== '' ? 'solid' : '', + 'border-color' : borderColor + }); + self.hideDialog().focus(); + self.cmd.range.moveToBookmark(bookmark); + self.cmd.select(); + self.addBookmark(); + } + } + }), + div = dialog.div, + widthBox = K('[name="width"]', div).val(100), + heightBox = K('[name="height"]', div), + widthTypeBox = K('[name="widthType"]', div), + heightTypeBox = K('[name="heightType"]', div), + paddingBox = K('[name="padding"]', div).val(2), + spacingBox = K('[name="spacing"]', div).val(0), + textAlignBox = K('[name="textAlign"]', div), + verticalAlignBox = K('[name="verticalAlign"]', div), + borderBox = K('[name="border"]', div).val(1), + colorBox = K('.ke-input-color', div); + _initColorPicker(div, colorBox.eq(0)); + _initColorPicker(div, colorBox.eq(1)); + _setColor(colorBox.eq(0), '#000000'); + _setColor(colorBox.eq(1), ''); + // foucs and select + widthBox[0].focus(); + widthBox[0].select(); + // get selected cell + var cell = self.plugin.getSelectedCell(); + var match, + cellWidth = cell[0].style.width || cell[0].width || '', + cellHeight = cell[0].style.height || cell[0].height || ''; + if ((match = /^(\d+)((?:px|%)*)$/.exec(cellWidth))) { + widthBox.val(match[1]); + widthTypeBox.val(match[2]); + } else { + widthBox.val(''); + } + if ((match = /^(\d+)((?:px|%)*)$/.exec(cellHeight))) { + heightBox.val(match[1]); + heightTypeBox.val(match[2]); + } + textAlignBox.val(cell[0].style.textAlign || ''); + verticalAlignBox.val(cell[0].style.verticalAlign || ''); + var border = cell[0].style.borderWidth || ''; + if (border) { + border = parseInt(border); + } + borderBox.val(border); + _setColor(colorBox.eq(0), K.toHex(cell[0].style.borderColor || '')); + _setColor(colorBox.eq(1), K.toHex(cell[0].style.backgroundColor || '')); + widthBox[0].focus(); + widthBox[0].select(); + }, + insert : function() { + this.prop(true); + }, + 'delete' : function() { + var table = self.plugin.getSelectedTable(); + self.cmd.range.setStartBefore(table[0]).collapse(true); + self.cmd.select(); + table.remove(); + self.addBookmark(); + }, + colinsert : function(offset) { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + index = cell.cellIndex + offset; + // 取得第一行的index + index += table.rows[0].cells.length - row.cells.length; + + for (var i = 0, len = table.rows.length; i < len; i++) { + var newRow = table.rows[i], + newCell = newRow.insertCell(index); + newCell.innerHTML = K.IE ? '' : '
      '; + // 调整下一行的单元格index + index = _getCellIndex(table, newRow, newCell); + } + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + colinsertleft : function() { + this.colinsert(0); + }, + colinsertright : function() { + this.colinsert(1); + }, + rowinsert : function(offset) { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0]; + var rowIndex = row.rowIndex; + if (offset === 1) { + rowIndex = row.rowIndex + (cell.rowSpan - 1) + offset; + } + var newRow = table.insertRow(rowIndex); + + for (var i = 0, len = row.cells.length; i < len; i++) { + // 调整cell个数 + if (row.cells[i].rowSpan > 1) { + len -= row.cells[i].rowSpan - 1; + } + var newCell = newRow.insertCell(i); + // copy colspan + if (offset === 1 && row.cells[i].colSpan > 1) { + newCell.colSpan = row.cells[i].colSpan; + } + newCell.innerHTML = K.IE ? '' : '
      '; + } + // 调整rowspan + for (var j = rowIndex; j >= 0; j--) { + var cells = table.rows[j].cells; + if (cells.length > i) { + for (var k = cell.cellIndex; k >= 0; k--) { + if (cells[k].rowSpan > 1) { + cells[k].rowSpan += 1; + } + } + break; + } + } + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + rowinsertabove : function() { + this.rowinsert(0); + }, + rowinsertbelow : function() { + this.rowinsert(1); + }, + rowmerge : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex, // 当前行的index + nextRowIndex = rowIndex + cell.rowSpan, // 下一行的index + nextRow = table.rows[nextRowIndex]; // 下一行 + // 最后一行不能合并 + if (table.rows.length <= nextRowIndex) { + return; + } + var cellIndex = cell.cellIndex; // 下一行单元格的index + if (nextRow.cells.length <= cellIndex) { + return; + } + var nextCell = nextRow.cells[cellIndex]; // 下一行单元格 + // 上下行的colspan不一致时不能合并 + if (cell.colSpan !== nextCell.colSpan) { + return; + } + cell.rowSpan += nextCell.rowSpan; + nextRow.deleteCell(cellIndex); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + colmerge : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex, // 当前行的index + cellIndex = cell.cellIndex, + nextCellIndex = cellIndex + 1; + // 最后一列不能合并 + if (row.cells.length <= nextCellIndex) { + return; + } + var nextCell = row.cells[nextCellIndex]; + // 左右列的rowspan不一致时不能合并 + if (cell.rowSpan !== nextCell.rowSpan) { + return; + } + cell.colSpan += nextCell.colSpan; + row.deleteCell(nextCellIndex); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + rowsplit : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex; + // 不是可分割单元格 + if (cell.rowSpan === 1) { + return; + } + var cellIndex = _getCellIndex(table, row, cell); + for (var i = 1, len = cell.rowSpan; i < len; i++) { + var newRow = table.rows[rowIndex + i], + newCell = newRow.insertCell(cellIndex); + if (cell.colSpan > 1) { + newCell.colSpan = cell.colSpan; + } + newCell.innerHTML = K.IE ? '' : '
      '; + // 调整下一行的单元格index + cellIndex = _getCellIndex(table, newRow, newCell); + } + K(cell).removeAttr('rowSpan'); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + colsplit : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + cellIndex = cell.cellIndex; + // 不是可分割单元格 + if (cell.colSpan === 1) { + return; + } + for (var i = 1, len = cell.colSpan; i < len; i++) { + var newCell = row.insertCell(cellIndex + i); + if (cell.rowSpan > 1) { + newCell.rowSpan = cell.rowSpan; + } + newCell.innerHTML = K.IE ? '' : '
      '; + } + K(cell).removeAttr('colSpan'); + self.cmd.range.selectNodeContents(cell).collapse(true); + self.cmd.select(); + self.addBookmark(); + }, + coldelete : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + index = cell.cellIndex; + for (var i = 0, len = table.rows.length; i < len; i++) { + var newRow = table.rows[i], + newCell = newRow.cells[index]; + if (newCell.colSpan > 1) { + newCell.colSpan -= 1; + if (newCell.colSpan === 1) { + K(newCell).removeAttr('colSpan'); + } + } else { + newRow.deleteCell(index); + } + // 跳过不需要删除的行 + if (newCell.rowSpan > 1) { + i += newCell.rowSpan - 1; + } + } + if (row.cells.length === 0) { + self.cmd.range.setStartBefore(table).collapse(true); + self.cmd.select(); + K(table).remove(); + } else { + self.cmd.selection(true); + } + self.addBookmark(); + }, + rowdelete : function() { + var table = self.plugin.getSelectedTable()[0], + row = self.plugin.getSelectedRow()[0], + cell = self.plugin.getSelectedCell()[0], + rowIndex = row.rowIndex; + // 从下到上删除 + for (var i = cell.rowSpan - 1; i >= 0; i--) { + table.deleteRow(rowIndex + i); + } + if (table.rows.length === 0) { + self.cmd.range.setStartBefore(table).collapse(true); + self.cmd.select(); + K(table).remove(); + } else { + self.cmd.selection(true); + } + self.addBookmark(); + } + }; + self.clickToolbar(name, self.plugin.table.prop); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/template/html/1.html b/php/kindeditor_demo/kindeditor/plugins/template/html/1.html new file mode 100755 index 0000000..034126b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/template/html/1.html @@ -0,0 +1,14 @@ + + + + + + +

      + 在此处输入标题 +

      +

      + 在此处输入内容 +

      + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/plugins/template/html/2.html b/php/kindeditor_demo/kindeditor/plugins/template/html/2.html new file mode 100755 index 0000000..dc2584a --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/template/html/2.html @@ -0,0 +1,42 @@ + + + + + + +

      + 标题 +

      + + + + + + + + + + + + + + + +
      +

      标题1

      +
      +

      标题1

      +
      + 内容1 + + 内容2 +
      + 内容3 + + 内容4 +
      +

      + 表格说明 +

      + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/plugins/template/html/3.html b/php/kindeditor_demo/kindeditor/plugins/template/html/3.html new file mode 100755 index 0000000..873f0c6 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/template/html/3.html @@ -0,0 +1,36 @@ + + + + + + +

      + 在此处输入内容 +

      +
        +
      1. + 描述1 +
      2. +
      3. + 描述2 +
      4. +
      5. + 描述3 +
      6. +
      +

      + 在此处输入内容 +

      +
        +
      • + 描述1 +
      • +
      • + 描述2 +
      • +
      • + 描述3 +
      • +
      + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/plugins/template/template.js b/php/kindeditor_demo/kindeditor/plugins/template/template.js new file mode 100755 index 0000000..644882a --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/template/template.js @@ -0,0 +1,58 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('template', function(K) { + var self = this, name = 'template', lang = self.lang(name + '.'), + htmlPath = self.pluginsPath + name + '/html/'; + function getFilePath(fileName) { + return htmlPath + fileName + '?ver=' + encodeURIComponent(K.DEBUG ? K.TIME : K.VERSION); + } + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + arr = ['
      ', + '
      ', + // left start + '
      ', + lang. selectTemplate + '
      ', + // right start + '
      ', + ' ', + '
      ', + '
      ', + '
      ', + '', + '
      '].join(''); + var dialog = self.createDialog({ + name : name, + width : 500, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var doc = K.iframeDoc(iframe); + self[checkbox[0].checked ? 'html' : 'insertHtml'](doc.body.innerHTML).hideDialog().focus(); + } + } + }); + var selectBox = K('select', dialog.div), + checkbox = K('[name="replaceFlag"]', dialog.div), + iframe = K('iframe', dialog.div); + checkbox[0].checked = true; + iframe.attr('src', getFilePath(selectBox.val())); + selectBox.change(function() { + iframe.attr('src', getFilePath(this.value)); + }); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/plugins/wordpaste/wordpaste.js b/php/kindeditor_demo/kindeditor/plugins/wordpaste/wordpaste.js new file mode 100755 index 0000000..d3af21b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/plugins/wordpaste/wordpaste.js @@ -0,0 +1,51 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2011 kindsoft.net +* +* @author Roddy +* @site http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +*******************************************************************************/ + +KindEditor.plugin('wordpaste', function(K) { + var self = this, name = 'wordpaste'; + self.clickToolbar(name, function() { + var lang = self.lang(name + '.'), + html = '
      ' + + '
      ' + lang.comment + '
      ' + + '' + + '
      ', + dialog = self.createDialog({ + name : name, + width : 450, + title : self.lang(name), + body : html, + yesBtn : { + name : self.lang('yes'), + click : function(e) { + var str = doc.body.innerHTML; + str = K.clearMsWord(str, self.filterMode ? self.htmlTags : K.options.htmlTags); + self.insertHtml(str).hideDialog().focus(); + } + } + }), + div = dialog.div, + iframe = K('iframe', div), + doc = K.iframeDoc(iframe); + if (!K.IE) { + doc.designMode = 'on'; + } + doc.open(); + doc.write('WordPaste'); + doc.write(''); + if (!K.IE) { + doc.write('
      '); + } + doc.write(''); + doc.close(); + if (K.IE) { + doc.body.contentEditable = 'true'; + } + iframe[0].contentWindow.focus(); + }); +}); diff --git a/php/kindeditor_demo/kindeditor/src/ajax.js b/php/kindeditor_demo/kindeditor/src/ajax.js new file mode 100755 index 0000000..c81bfa3 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/ajax.js @@ -0,0 +1,72 @@ + +function _loadScript(url, fn) { + var head = document.getElementsByTagName('head')[0] || (_QUIRKS ? document.body : document.documentElement), + script = document.createElement('script'); + head.appendChild(script); + script.src = url; + script.charset = 'utf-8'; + script.onload = script.onreadystatechange = function() { + if (!this.readyState || this.readyState === 'loaded') { + if (fn) { + fn(); + } + script.onload = script.onreadystatechange = null; + head.removeChild(script); + } + }; +} + +// 移除URL里的GET参数 +function _chopQuery(url) { + var index = url.indexOf('?'); + return index > 0 ? url.substr(0, index) : url; +} + +function _loadStyle(url) { + var head = document.getElementsByTagName('head')[0] || (_QUIRKS ? document.body : document.documentElement), + link = document.createElement('link'), + absoluteUrl = _chopQuery(_formatUrl(url, 'absolute')); + var links = K('link[rel="stylesheet"]', head); + for (var i = 0, len = links.length; i < len; i++) { + if (_chopQuery(_formatUrl(links[i].href, 'absolute')) === absoluteUrl) { + return; + } + } + head.appendChild(link); + link.href = url; + link.rel = 'stylesheet'; +} + +function _ajax(url, fn, method, param, dataType) { + method = method || 'GET'; //POST or GET + dataType = dataType || 'json'; //json or html + var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); + xhr.open(method, url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4 && xhr.status == 200) { + if (fn) { + var data = _trim(xhr.responseText); + if (dataType == 'json') { + data = _json(data); + } + fn(data); + } + } + }; + if (method == 'POST') { + var params = []; + _each(param, function(key, val) { + params.push(encodeURIComponent(key) + '=' + encodeURIComponent(val)); + }); + try { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } catch (e) {} + xhr.send(params.join('&')); + } else { + xhr.send(null); + } +} + +K.loadScript = _loadScript; +K.loadStyle = _loadStyle; +K.ajax = _ajax; diff --git a/php/kindeditor_demo/kindeditor/src/cmd.js b/php/kindeditor_demo/kindeditor/src/cmd.js new file mode 100755 index 0000000..4e93057 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/cmd.js @@ -0,0 +1,884 @@ + +// original execCommand +function _nativeCommand(doc, key, val) { + try { + doc.execCommand(key, false, val); + } catch(e) {} +} +// original queryCommandValue +function _nativeCommandValue(doc, key) { + var val = ''; + try { + val = doc.queryCommandValue(key); + } catch (e) {} + if (typeof val !== 'string') { + val = ''; + } + return val; +} +// get current selection of a document +function _getSel(doc) { + var win = _getWin(doc); + return _IERANGE ? doc.selection : win.getSelection(); +} +// get range of current selection +function _getRng(doc) { + var sel = _getSel(doc), rng; + try { + if (sel.rangeCount > 0) { + rng = sel.getRangeAt(0); + } else { + rng = sel.createRange(); + } + } catch(e) {} + if (_IERANGE && (!rng || (!rng.item && rng.parentElement().ownerDocument !== doc))) { + return null; + } + return rng; +} +//将map的复合key转换成单一key +function _singleKeyMap(map) { + var newMap = {}, arr, v; + _each(map, function(key, val) { + arr = key.split(','); + for (var i = 0, len = arr.length; i < len; i++) { + v = arr[i]; + newMap[v] = val; + } + }); + return newMap; +} +//判断一个node是否有指定属性或CSS +function _hasAttrOrCss(knode, map) { + return _hasAttrOrCssByKey(knode, map, '*') || _hasAttrOrCssByKey(knode, map); +} +function _hasAttrOrCssByKey(knode, map, mapKey) { + mapKey = mapKey || knode.name; + if (knode.type !== 1) { + return false; + } + var newMap = _singleKeyMap(map); + if (!newMap[mapKey]) { + return false; + } + var arr = newMap[mapKey].split(','); + for (var i = 0, len = arr.length; i < len; i++) { + var key = arr[i]; + if (key === '*') { + return true; + } + var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key); + var method = match[1] ? 'css' : 'attr'; + key = match[2]; + var val = match[3] || ''; + if (val === '' && knode[method](key) !== '') { + return true; + } + if (val !== '' && knode[method](key) === val) { + return true; + } + } + return false; +} +//删除一个node的属性和CSS +function _removeAttrOrCss(knode, map) { + if (knode.type != 1) { + return; + } + _removeAttrOrCssByKey(knode, map, '*'); + _removeAttrOrCssByKey(knode, map); +} +function _removeAttrOrCssByKey(knode, map, mapKey) { + mapKey = mapKey || knode.name; + if (knode.type !== 1) { + return; + } + var newMap = _singleKeyMap(map); + if (!newMap[mapKey]) { + return; + } + var arr = newMap[mapKey].split(','), allFlag = false; + for (var i = 0, len = arr.length; i < len; i++) { + var key = arr[i]; + if (key === '*') { + allFlag = true; + break; + } + var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key); + key = match[2]; + if (match[1]) { + key = _toCamel(key); + if (knode[0].style[key]) { + knode[0].style[key] = ''; + } + } else { + knode.removeAttr(key); + } + } + if (allFlag) { + knode.remove(true); + } +} +//取得最里面的element +function _getInnerNode(knode) { + var inner = knode; + while (inner.first()) { + inner = inner.first(); + } + return inner; +} +//最里面的element为inline element时返回true +function _isEmptyNode(knode) { + if (knode.type != 1 || knode.isSingle()) { + return false; + } + return knode.html().replace(/<[^>]+>/g, '') === ''; +} +//merge two wrapper +//a : +//b : +//result : +function _mergeWrapper(a, b) { + a = a.clone(true); + var lastA = _getInnerNode(a), childA = a, merged = false; + while (b) { + while (childA) { + if (childA.name === b.name) { + _mergeAttrs(childA, b.attr(), b.css()); + merged = true; + } + childA = childA.first(); + } + if (!merged) { + lastA.append(b.clone(false)); + } + merged = false; + b = b.first(); + } + return a; +} +//wrap and merge a node +function _wrapNode(knode, wrapper) { + wrapper = wrapper.clone(true); + //node为text node时 + if (knode.type == 3) { + _getInnerNode(wrapper).append(knode.clone(false)); + knode.replaceWith(wrapper); + return wrapper; + } + //node为element时 + //取得node的wrapper + var nodeWrapper = knode, child; + while ((child = knode.first()) && child.children().length == 1) { + knode = child; + } + //将node的子节点纳入在一个documentFragment里 + child = knode.first(); + var frag = knode.doc.createDocumentFragment(); + while (child) { + frag.appendChild(child[0]); + child = child.next(); + } + wrapper = _mergeWrapper(nodeWrapper, wrapper); + if (frag.firstChild) { + _getInnerNode(wrapper).append(frag); + } + nodeWrapper.replaceWith(wrapper); + return wrapper; +} +//merge attributes and styles +function _mergeAttrs(knode, attrs, styles) { + _each(attrs, function(key, val) { + if (key !== 'style') { + knode.attr(key, val); + } + }); + _each(styles, function(key, val) { + knode.css(key, val); + }); +} +// 判断node是否在pre、style、script里 +function _inPreElement(knode) { + while (knode && knode.name != 'body') { + if (_PRE_TAG_MAP[knode.name] || knode.name == 'div' && knode.hasClass('ke-script')) { + return true; + } + knode = knode.parent(); + } + return false; +} +// create KCmd class +function KCmd(range) { + this.init(range); +} +_extend(KCmd, { + init : function(range) { + var self = this, doc = range.doc; + self.doc = doc; + self.win = _getWin(doc); + self.sel = _getSel(doc); + self.range = range; + }, + selection : function(forceReset) { + var self = this, doc = self.doc, rng = _getRng(doc); + self.sel = _getSel(doc); + if (rng) { + self.range = _range(rng); + if (K(self.range.startContainer).name == 'html') { + self.range.selectNodeContents(doc.body).collapse(false); + } + return self; + } + if (forceReset) { + self.range.selectNodeContents(doc.body).collapse(false); + } + return self; + }, + select : function(hasDummy) { + hasDummy = _undef(hasDummy, true); + var self = this, sel = self.sel, range = self.range.cloneRange().shrink(), + sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset, + doc = _getDoc(sc), win = self.win, rng, hasU200b = false; + // tag内部无内容时选中tag内部,[] + if (hasDummy && sc.nodeType == 1 && range.collapsed) { + if (_IERANGE) { + var dummy = K(' ', doc); + range.insertNode(dummy[0]); + rng = doc.body.createTextRange(); + try { + rng.moveToElementText(dummy[0]); + } catch(ex) {} + rng.collapse(false); + rng.select(); + dummy.remove(); + win.focus(); + return self; + } + if (_WEBKIT) { + var children = sc.childNodes; + if (K(sc).isInline() || so > 0 && K(children[so - 1]).isInline() || children[so] && K(children[so]).isInline()) { + range.insertNode(doc.createTextNode('\u200B')); + hasU200b = true; + } + } + } + //other case + if (_IERANGE) { + try { + rng = range.get(true); + rng.select(); + } catch(e) {} + } else { + if (hasU200b) { + range.collapse(false); + } + rng = range.get(true); + sel.removeAllRanges(); + sel.addRange(rng); + // Bugfix: https://github.com/kindsoft/kindeditor/issues/54 + if (doc !== document) { + var pos = K(rng.endContainer).pos(); + win.scrollTo(pos.x, pos.y); + } + } + win.focus(); + return self; + }, + wrap : function(val) { + var self = this, doc = self.doc, range = self.range, wrapper; + wrapper = K(val, doc); + // collapsed=true + if (range.collapsed) { + range.shrink(); + range.insertNode(wrapper[0]).selectNodeContents(wrapper[0]); + return self; + } + // block wrapper + if (wrapper.isBlock()) { + var copyWrapper = wrapper.clone(true), child = copyWrapper; + // find inner element + while (child.first()) { + child = child.first(); + } + child.append(range.extractContents()); + range.insertNode(copyWrapper[0]).selectNode(copyWrapper[0]); + return self; + } + // collapsed=false + range.enlarge(); + var bookmark = range.createBookmark(), ancestor = range.commonAncestor(), isStart = false; + K(ancestor).scan(function(node) { + if (!isStart && node == bookmark.start) { + isStart = true; + return; + } + if (isStart) { + if (node == bookmark.end) { + return false; + } + var knode = K(node); + if (_inPreElement(knode)) { + return; + } + if (knode.type == 3 && _trim(node.nodeValue).length > 0) { + // textNode为唯一的子节点时,重新设置node + var parent; + while ((parent = knode.parent()) && parent.isStyle() && parent.children().length == 1) { + knode = parent; + } + _wrapNode(knode, wrapper); + } + } + }); + range.moveToBookmark(bookmark); + return self; + }, + split : function(isStart, map) { + var range = this.range, doc = range.doc; + //get parent node + var tempRange = range.cloneRange().collapse(isStart); + var node = tempRange.startContainer, pos = tempRange.startOffset, + parent = node.nodeType == 3 ? node.parentNode : node, + needSplit = false, knode; + while (parent && parent.parentNode) { + knode = K(parent); + if (map) { + if (!knode.isStyle()) { + break; + } + if (!_hasAttrOrCss(knode, map)) { + break; + } + } else { + if (_NOSPLIT_TAG_MAP[knode.name]) { + break; + } + } + needSplit = true; + parent = parent.parentNode; + } + //split parent node + if (needSplit) { + var dummy = doc.createElement('span'); + range.cloneRange().collapse(!isStart).insertNode(dummy); + if (isStart) { + tempRange.setStartBefore(parent.firstChild).setEnd(node, pos); + } else { + tempRange.setStart(node, pos).setEndAfter(parent.lastChild); + } + var frag = tempRange.extractContents(), + first = frag.firstChild, last = frag.lastChild; + if (isStart) { + tempRange.insertNode(frag); + range.setStartAfter(last).setEndBefore(dummy); + } else { + parent.appendChild(frag); + range.setStartBefore(dummy).setEndBefore(first); + } + //调整endOffset + var dummyParent = dummy.parentNode; + if (dummyParent == range.endContainer) { + var prev = K(dummy).prev(), next = K(dummy).next(); + if (prev && next && prev.type == 3 && next.type == 3) { + //dummy元素的左右都是textNode,fg + range.setEnd(prev[0], prev[0].nodeValue.length); + } else if (!isStart) { + range.setEnd(range.endContainer, range.endOffset - 1); + } + } + dummyParent.removeChild(dummy); + } + return this; + }, + remove : function(map) { + var self = this, doc = self.doc, range = self.range; + range.enlarge(); + //

      [123456789]

      , remove strong + if (range.startOffset === 0) { + var ksc = K(range.startContainer), parent; + while ((parent = ksc.parent()) && parent.isStyle() && parent.children().length == 1) { + ksc = parent; + } + range.setStart(ksc[0], 0); + //

      [abcd

      , remove style + ksc = K(range.startContainer); + if (ksc.isBlock()) { + _removeAttrOrCss(ksc, map); + } + var kscp = ksc.parent(); + if (kscp && kscp.isBlock()) { + _removeAttrOrCss(kscp, map); + } + } + var sc, so; + // collapsed == true + if (range.collapsed) { + self.split(true, map); + // remove empty element + sc = range.startContainer; + so = range.startOffset; + if (so > 0) { + var sb = K(sc.childNodes[so - 1]); + if (sb && _isEmptyNode(sb)) { + sb.remove(); + range.setStart(sc, so - 1); + } + } + var sa = K(sc.childNodes[so]); + if (sa && _isEmptyNode(sa)) { + sa.remove(); + } + // | + if (_isEmptyNode(sc)) { + range.startBefore(sc); + sc.remove(); + } + range.collapse(true); + return self; + } + // split range + self.split(true, map); + self.split(false, map); + // insert dummy element + var startDummy = doc.createElement('span'), endDummy = doc.createElement('span'); + range.cloneRange().collapse(false).insertNode(endDummy); + range.cloneRange().collapse(true).insertNode(startDummy); + // select element + var nodeList = [], cmpStart = false; + K(range.commonAncestor()).scan(function(node) { + if (!cmpStart && node == startDummy) { + cmpStart = true; + return; + } + if (node == endDummy) { + return false; + } + if (cmpStart) { + nodeList.push(node); + } + }); + // remove dummy element + K(startDummy).remove(); + K(endDummy).remove(); + // remove empty element + sc = range.startContainer; + so = range.startOffset; + var ec = range.endContainer, eo = range.endOffset; + if (so > 0) { + var startBefore = K(sc.childNodes[so - 1]); + if (startBefore && _isEmptyNode(startBefore)) { + startBefore.remove(); + range.setStart(sc, so - 1); + if (sc == ec) { + range.setEnd(ec, eo - 1); + } + } + // abc[def]ghi,分割后HTML变成 + // abc[def]ghi + var startAfter = K(sc.childNodes[so]); + if (startAfter && _isEmptyNode(startAfter)) { + startAfter.remove(); + if (sc == ec) { + range.setEnd(ec, eo - 1); + } + } + } + var endAfter = K(ec.childNodes[range.endOffset]); + if (endAfter && _isEmptyNode(endAfter)) { + endAfter.remove(); + } + var bookmark = range.createBookmark(true); + // remove attributes or styles + _each(nodeList, function(i, node) { + _removeAttrOrCss(K(node), map); + }); + range.moveToBookmark(bookmark); + return self; + }, + commonNode : function(map) { + var range = this.range; + var ec = range.endContainer, eo = range.endOffset, + node = (ec.nodeType == 3 || eo === 0) ? ec : ec.childNodes[eo - 1]; + function find(node) { + var child = node, parent = node; + while (parent) { + if (_hasAttrOrCss(K(parent), map)) { + return K(parent); + } + parent = parent.parentNode; + } + while (child && (child = child.lastChild)) { + if (_hasAttrOrCss(K(child), map)) { + return K(child); + } + } + return null; + } + var cNode = find(node); + if (cNode) { + return cNode; + } + //123|4567 + //123|
      + if (node.nodeType == 1 || (ec.nodeType == 3 && eo === 0)) { + var prev = K(node).prev(); + if (prev) { + return find(prev); + } + } + return null; + }, + commonAncestor : function(tagName) { + var range = this.range, + sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset, + startNode = (sc.nodeType == 3 || so === 0) ? sc : sc.childNodes[so - 1], + endNode = (ec.nodeType == 3 || eo === 0) ? ec : ec.childNodes[eo - 1]; + function find(node) { + while (node) { + if (node.nodeType == 1) { + if (node.tagName.toLowerCase() === tagName) { + return node; + } + } + node = node.parentNode; + } + return null; + } + var start = find(startNode), end = find(endNode); + if (start && end && start === end) { + return K(start); + } + return null; + }, + // Reference: document.queryCommandState + // TODO + state : function(key) { + var self = this, doc = self.doc, bool = false; + try { + bool = doc.queryCommandState(key); + } catch (e) {} + return bool; + }, + // Reference: document.queryCommandValue + val : function(key) { + var self = this, doc = self.doc, range = self.range; + function lc(val) { + return val.toLowerCase(); + } + key = lc(key); + var val = '', knode; + if (key === 'fontfamily' || key === 'fontname') { + val = _nativeCommandValue(doc, 'fontname'); + val = val.replace(/['"]/g, ''); + return lc(val); + } + if (key === 'formatblock') { + val = _nativeCommandValue(doc, key); + if (val === '') { + knode = self.commonNode({'h1,h2,h3,h4,h5,h6,p,div,pre,address' : '*'}); + if (knode) { + val = knode.name; + } + } + if (val === 'Normal') { + val = 'p'; + } + return lc(val); + } + if (key === 'fontsize') { + knode = self.commonNode({'*' : '.font-size'}); + if (knode) { + val = knode.css('font-size'); + } + return lc(val); + } + if (key === 'forecolor') { + knode = self.commonNode({'*' : '.color'}); + if (knode) { + val = knode.css('color'); + } + val = _toHex(val); + if (val === '') { + val = 'default'; + } + return lc(val); + } + if (key === 'hilitecolor') { + knode = self.commonNode({'*' : '.background-color'}); + if (knode) { + val = knode.css('background-color'); + } + val = _toHex(val); + if (val === '') { + val = 'default'; + } + return lc(val); + } + return val; + }, + toggle : function(wrapper, map) { + var self = this; + if (self.commonNode(map)) { + self.remove(map); + } else { + self.wrap(wrapper); + } + return self.select(); + }, + bold : function() { + return this.toggle('', { + span : '.font-weight=bold', + strong : '*', + b : '*' + }); + }, + italic : function() { + return this.toggle('', { + span : '.font-style=italic', + em : '*', + i : '*' + }); + }, + underline : function() { + return this.toggle('', { + span : '.text-decoration=underline', + u : '*' + }); + }, + strikethrough : function() { + return this.toggle('', { + span : '.text-decoration=line-through', + s : '*' + }); + }, + forecolor : function(val) { + return this.wrap('').select(); + // return this.toggle('', { + // span : '.color=' + val, + // font : 'color' + // }); + }, + hilitecolor : function(val) { + return this.wrap('').select(); + // return this.toggle('', { + // span : '.background-color=' + val + // }); + }, + fontsize : function(val) { + return this.wrap('').select(); + // return this.toggle('', { + // span : '.font-size=' + val, + // font : 'size' + // }); + }, + fontname : function(val) { + return this.fontfamily(val); + }, + fontfamily : function(val) { + return this.wrap('').select(); + // return this.toggle('', { + // span : '.font-family=' + val, + // font : 'face' + // }); + }, + removeformat : function() { + var map = { + '*' : '.font-weight,.font-style,.text-decoration,.color,.background-color,.font-size,.font-family,.text-indent' + }, + tags = _STYLE_TAG_MAP; + _each(tags, function(key, val) { + map[key] = '*'; + }); + this.remove(map); + return this.select(); + }, + inserthtml : function(val, quickMode) { + var self = this, range = self.range; + if (val === '') { + return self; + } + //if (_inPreElement(K(range.startContainer))) { + // return self; + //} + // IE专用,优化性能 + function pasteHtml(range, val) { + val = '' + val; + var rng = range.get(); + if (rng.item) { + rng.item(0).outerHTML = val; + } else { + rng.pasteHTML(val); + } + var temp = range.doc.getElementById('__kindeditor_temp_tag__'); + temp.parentNode.removeChild(temp); + var newRange = _toRange(rng); + range.setEnd(newRange.endContainer, newRange.endOffset); + range.collapse(false); + self.select(false); + } + // 全浏览器兼容,在IE上速度慢 + function insertHtml(range, val) { + var doc = range.doc, + frag = doc.createDocumentFragment(); + K('@' + val, doc).each(function() { + frag.appendChild(this); + }); + range.deleteContents(); + range.insertNode(frag); + range.collapse(false); + self.select(false); + } + if (_IERANGE && quickMode) { + try { + pasteHtml(range, val); + } catch(e) { + insertHtml(range, val); + } + return self; + } + insertHtml(range, val); + return self; + }, + hr : function() { + return this.inserthtml('
      '); + }, + print : function() { + this.win.print(); + return this; + }, + insertimage : function(url, title, width, height, border, align) { + title = _undef(title, ''); + border = _undef(border, 0); + var html = ''; + return self.inserthtml(html); + } + if (range.isControl()) { + var node = K(range.startContainer.childNodes[range.startOffset]); + html += '>'; + node.after(K(html, doc)); + node.next().append(node); + range.selectNode(node[0]); + return self.select(); + } + function setAttr(node, url, type) { + K(node).attr('href', url).attr('data-ke-src', url); + if (type) { + K(node).attr('target', type); + } else { + K(node).removeAttr('target'); + } + } + // Bugfix: https://github.com/kindsoft/kindeditor/issues/117 + // [IE] 当两个A标签并排在一起中间没有别的内容,修改后面的链接地址时,前面的链接地址也被改掉。 + var sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset; + if (sc.nodeType == 1 && sc === ec && so + 1 === eo) { + var child = sc.childNodes[so]; + if (child.nodeName.toLowerCase() == 'a') { + setAttr(child, url, type); + return self; + } + } + _nativeCommand(doc, 'createlink', '__kindeditor_temp_url__'); + K('a[href="__kindeditor_temp_url__"]', doc).each(function() { + setAttr(this, url, type); + }); + return self; + }, + unlink : function() { + var self = this, doc = self.doc, range = self.range; + self.select(); + if (range.collapsed) { + var a = self.commonNode({ a : '*' }); + if (a) { + range.selectNode(a.get()); + self.select(); + } + _nativeCommand(doc, 'unlink', null); + if (_WEBKIT && K(range.startContainer).name === 'img') { + var parent = K(range.startContainer).parent(); + if (parent.name === 'a') { + parent.remove(true); + } + } + } else { + _nativeCommand(doc, 'unlink', null); + } + return self; + } +}); + +_each(('formatblock,selectall,justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,' + + 'insertunorderedlist,indent,outdent,subscript,superscript').split(','), function(i, name) { + KCmd.prototype[name] = function(val) { + var self = this; + self.select(); + _nativeCommand(self.doc, name, val); + // Bugfix: [IE] 先选中图片后居中,再左对齐,光标跳到顶部 + if (_IERANGE && _inArray(name, 'justifyleft,justifycenter,justifyright,justifyfull'.split(',')) >= 0) { + self.selection(); + } + // 在webkit和firefox上需要重新选取range,否则有时候会报错 + if (!_IERANGE || _inArray(name, 'formatblock,selectall,insertorderedlist,insertunorderedlist'.split(',')) >= 0) { + self.selection(); + } + return self; + }; +}); + +_each('cut,copy,paste'.split(','), function(i, name) { + KCmd.prototype[name] = function() { + var self = this; + if (!self.doc.queryCommandSupported(name)) { + throw 'not supported'; + } + self.select(); + _nativeCommand(self.doc, name, null); + return self; + }; +}); + +function _cmd(mixed) { + // mixed is a node + if (mixed.nodeName) { + var doc = _getDoc(mixed); + mixed = _range(doc).selectNodeContents(doc.body).collapse(false); + } + // mixed is a KRange + return new KCmd(mixed); +} + +K.CmdClass = KCmd; +K.cmd = _cmd; diff --git a/php/kindeditor_demo/kindeditor/src/colorpicker.js b/php/kindeditor_demo/kindeditor/src/colorpicker.js new file mode 100755 index 0000000..25ef259 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/colorpicker.js @@ -0,0 +1,79 @@ + +// create KColorPicker class +function KColorPicker(options) { + this.init(options); +} +_extend(KColorPicker, KWidget, { + init : function(options) { + var self = this; + options.z = options.z || 811213; + KColorPicker.parent.init.call(self, options); + var colors = options.colors || [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ]; + self.selectedColor = (options.selectedColor || '').toLowerCase(); + self._cells = []; + self.div.addClass('ke-colorpicker').bind('click,mousedown', function(e){ + e.stopPropagation(); + }).attr('unselectable', 'on'); + var table = self.doc.createElement('table'); + self.div.append(table); + table.className = 'ke-colorpicker-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + var row = table.insertRow(0), cell = row.insertCell(0); + cell.colSpan = colors[0].length; + self._addAttr(cell, '', 'ke-colorpicker-cell-top'); + for (var i = 0; i < colors.length; i++) { + row = table.insertRow(i + 1); + for (var j = 0; j < colors[i].length; j++) { + cell = row.insertCell(j); + self._addAttr(cell, colors[i][j], 'ke-colorpicker-cell'); + } + } + }, + _addAttr : function(cell, color, cls) { + var self = this; + cell = K(cell).addClass(cls); + if (self.selectedColor === color.toLowerCase()) { + cell.addClass('ke-colorpicker-cell-selected'); + } + cell.attr('title', color || self.options.noColor); + cell.mouseover(function(e) { + K(this).addClass('ke-colorpicker-cell-on'); + }); + cell.mouseout(function(e) { + K(this).removeClass('ke-colorpicker-cell-on'); + }); + cell.click(function(e) { + e.stop(); + self.options.click.call(K(this), color); + }); + if (color) { + cell.append(K('
      ').css('background-color', color)); + } else { + cell.html(self.options.noColor); + } + K(cell).attr('unselectable', 'on'); + self._cells.push(cell); + }, + remove : function() { + var self = this; + _each(self._cells, function() { + this.unbind(); + }); + KColorPicker.parent.remove.call(self); + return self; + } +}); + +function _colorpicker(options) { + return new KColorPicker(options); +} + +K.ColorPickerClass = KColorPicker; +K.colorpicker = _colorpicker; diff --git a/php/kindeditor_demo/kindeditor/src/config.js b/php/kindeditor_demo/kindeditor/src/config.js new file mode 100755 index 0000000..c584652 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/config.js @@ -0,0 +1,97 @@ + +function _getBasePath() { + var els = document.getElementsByTagName('script'), src; + for (var i = 0, len = els.length; i < len; i++) { + src = els[i].src || ''; + if (/kindeditor[\w\-\.]*\.js/.test(src)) { + return src.substring(0, src.lastIndexOf('/') + 1); + } + } + return ''; +} + +K.basePath = _getBasePath(); + +K.options = { + designMode : true, + fullscreenMode : false, + filterMode : true, + wellFormatMode : true, + shadowMode : true, + loadStyleMode : true, + basePath : K.basePath, + themesPath : K.basePath + 'themes/', + langPath : K.basePath + 'lang/', + pluginsPath : K.basePath + 'plugins/', + themeType : 'default', // default, simple + langType : 'zh-CN', + urlType : '', // "", relative, absolute, domain + newlineTag : 'p', // p, br + resizeType : 2, // 0, 1, 2 + syncType : 'form', // "", form + pasteType : 2, // 0:none, 1:text, 2:HTML + dialogAlignType : 'page', // page, editor + useContextmenu : true, + fullscreenShortcut : false, + bodyClass : 'ke-content', + indentChar : '\t', // \t, " " + cssPath : '', //String or Array + cssData : '', + minWidth : 650, + minHeight : 100, + minChangeSize : 50, + zIndex : 811213, + items : [ + 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste', + 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright', + 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript', + 'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/', + 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', + 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage', + 'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak', + 'anchor', 'link', 'unlink', '|', 'about' + ], + noDisableItems : ['source', 'fullscreen'], + colorTable : [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ], + fontSizeTable : ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'], + htmlTags : { + font : ['id', 'class', 'color', 'size', 'face', '.background-color'], + span : [ + 'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background', + '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height' + ], + div : [ + 'id', 'class', 'align', '.border', '.margin', '.padding', '.text-align', '.color', + '.background-color', '.font-size', '.font-family', '.font-weight', '.background', + '.font-style', '.text-decoration', '.vertical-align', '.margin-left' + ], + table: [ + 'id', 'class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'bordercolor', + '.padding', '.margin', '.border', 'bgcolor', '.text-align', '.color', '.background-color', + '.font-size', '.font-family', '.font-weight', '.font-style', '.text-decoration', '.background', + '.width', '.height', '.border-collapse' + ], + 'td,th': [ + 'id', 'class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor', + '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.font-weight', + '.font-style', '.text-decoration', '.vertical-align', '.background', '.border' + ], + a : ['id', 'class', 'href', 'target', 'name'], + embed : ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess', 'wmode'], + img : ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'], + 'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [ + 'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background', + '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.text-indent', '.margin-left' + ], + pre : ['id', 'class'], + hr : ['id', 'class', '.page-break-after'], + 'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del' : ['id', 'class'], + iframe : ['id', 'class', 'src', 'frameborder', 'width', 'height', '.width', '.height'] + }, + layout : '
      ' +}; diff --git a/php/kindeditor_demo/kindeditor/src/core.js b/php/kindeditor_demo/kindeditor/src/core.js new file mode 100755 index 0000000..d1c0687 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/core.js @@ -0,0 +1,231 @@ + +/**/ var undefined; + +if (!window.console) { + window.console = {}; +} +if (!console.log) { + console.log = function () {}; +} + +var _VERSION = '${VERSION}', + _ua = navigator.userAgent.toLowerCase(), + _IE = _ua.indexOf('msie') > -1 && _ua.indexOf('opera') == -1, + _NEWIE = _ua.indexOf('msie') == -1 && _ua.indexOf('trident') > -1, + _GECKO = _ua.indexOf('gecko') > -1 && _ua.indexOf('khtml') == -1, + _WEBKIT = _ua.indexOf('applewebkit') > -1, + _OPERA = _ua.indexOf('opera') > -1, + _MOBILE = _ua.indexOf('mobile') > -1, + _IOS = /ipad|iphone|ipod/.test(_ua), + _QUIRKS = document.compatMode != 'CSS1Compat', + _IERANGE = !window.getSelection, + _matches = /(?:msie|firefox|webkit|opera)[\/:\s](\d+)/.exec(_ua), + _V = _matches ? _matches[1] : '0', + _TIME = new Date().getTime(); + +function _isArray(val) { + if (!val) { + return false; + } + return Object.prototype.toString.call(val) === '[object Array]'; +} + +function _isFunction(val) { + if (!val) { + return false; + } + return Object.prototype.toString.call(val) === '[object Function]'; +} + +function _inArray(val, arr) { + for (var i = 0, len = arr.length; i < len; i++) { + if (val === arr[i]) { + return i; + } + } + return -1; +} + +function _each(obj, fn) { + if (_isArray(obj)) { + for (var i = 0, len = obj.length; i < len; i++) { + if (fn.call(obj[i], i, obj[i]) === false) { + break; + } + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (fn.call(obj[key], key, obj[key]) === false) { + break; + } + } + } + } +} + +function _trim(str) { + // Forgive various special whitespaces, e.g.  (\xa0). + return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, ''); +} + +function _inString(val, str, delimiter) { + delimiter = delimiter === undefined ? ',' : delimiter; + return (delimiter + str + delimiter).indexOf(delimiter + val + delimiter) >= 0; +} + +function _addUnit(val, unit) { + unit = unit || 'px'; + return val && /^-?\d+(?:\.\d+)?$/.test(val) ? val + unit : val; +} + +function _removeUnit(val) { + var match; + return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0; +} + +function _escape(val) { + return val.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} + +function _unescape(val) { + return val.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/&/g, '&'); +} + +function _toCamel(str) { + var arr = str.split('-'); + str = ''; + _each(arr, function(key, val) { + str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1) : val; + }); + return str; +} + +function _toHex(val) { + function hex(d) { + var s = parseInt(d, 10).toString(16).toUpperCase(); + return s.length > 1 ? s : '0' + s; + } + return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig, + function($0, $1, $2, $3) { + return '#' + hex($1) + hex($2) + hex($3); + } + ); +} + +function _toMap(val, delimiter) { + delimiter = delimiter === undefined ? ',' : delimiter; + var map = {}, arr = _isArray(val) ? val : val.split(delimiter), match; + _each(arr, function(key, val) { + if ((match = /^(\d+)\.\.(\d+)$/.exec(val))) { + for (var i = parseInt(match[1], 10); i <= parseInt(match[2], 10); i++) { + map[i.toString()] = true; + } + } else { + map[val] = true; + } + }); + return map; +} + +function _toArray(obj, offset) { + return Array.prototype.slice.call(obj, offset || 0); +} + +function _undef(val, defaultVal) { + return val === undefined ? defaultVal : val; +} + +function _invalidUrl(url) { + return !url || /[<>"]/.test(url); +} + +function _addParam(url, param) { + return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param; +} + +function _extend(child, parent, proto) { + if (!proto) { + proto = parent; + parent = null; + } + var childProto; + if (parent) { + var fn = function () {}; + fn.prototype = parent.prototype; + childProto = new fn(); + _each(proto, function(key, val) { + childProto[key] = val; + }); + } else { + childProto = proto; + } + childProto.constructor = child; + child.prototype = childProto; + child.parent = parent ? parent.prototype : null; +} + +//From http://www.json.org/json2.js +function _json(text) { + var match; + if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) { + text = match[0]; + } + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + if (/^[\],:{}\s]*$/. + test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). + replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). + replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + return eval('(' + text + ')'); + } + throw 'JSON parse error'; +} + +var _round = Math.round; + +var K = { + DEBUG : false, + VERSION : _VERSION, + IE : _IE, + GECKO : _GECKO, + WEBKIT : _WEBKIT, + OPERA : _OPERA, + V : _V, + TIME : _TIME, + each : _each, + isArray : _isArray, + isFunction : _isFunction, + inArray : _inArray, + inString : _inString, + trim : _trim, + addUnit : _addUnit, + removeUnit : _removeUnit, + escape : _escape, + unescape : _unescape, + toCamel : _toCamel, + toHex : _toHex, + toMap : _toMap, + toArray : _toArray, + undef : _undef, + invalidUrl : _invalidUrl, + addParam : _addParam, + extend : _extend, + json : _json +}; + +var _INLINE_TAG_MAP = _toMap('a,abbr,acronym,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,img,input,ins,kbd,label,map,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'), + _BLOCK_TAG_MAP = _toMap('address,applet,blockquote,body,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,head,hr,html,iframe,ins,isindex,li,map,menu,meta,noframes,noscript,object,ol,p,pre,script,style,table,tbody,td,tfoot,th,thead,title,tr,ul'), + _SINGLE_TAG_MAP = _toMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'), + _STYLE_TAG_MAP = _toMap('b,basefont,big,del,em,font,i,s,small,span,strike,strong,sub,sup,u'), + _CONTROL_TAG_MAP = _toMap('img,table,input,textarea,button'), + _PRE_TAG_MAP = _toMap('pre,style,script'), + _NOSPLIT_TAG_MAP = _toMap('html,head,body,td,tr,table,ol,ul,li'), + _AUTOCLOSE_TAG_MAP = _toMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'), + _FILL_ATTR_MAP = _toMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'), + _VALUE_TAG_MAP = _toMap('input,button,textarea,select'); diff --git a/php/kindeditor_demo/kindeditor/src/dialog.js b/php/kindeditor_demo/kindeditor/src/dialog.js new file mode 100755 index 0000000..8d89d91 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/dialog.js @@ -0,0 +1,142 @@ + +function _createButton(arg) { + arg = arg || {}; + var name = arg.name || '', + span = K(''), + btn = K(''); + if (arg.click) { + btn.click(arg.click); + } + span.append(btn); + return span; +} + +// create KToolbar class +function KDialog(options) { + this.init(options); +} +_extend(KDialog, KWidget, { + init : function(options) { + var self = this; + var shadowMode = _undef(options.shadowMode, true); + options.z = options.z || 811213; + options.shadowMode = false; + options.autoScroll = _undef(options.autoScroll, true); + KDialog.parent.init.call(self, options); + var title = options.title, + body = K(options.body, self.doc), + previewBtn = options.previewBtn, + yesBtn = options.yesBtn, + noBtn = options.noBtn, + closeBtn = options.closeBtn, + showMask = _undef(options.showMask, true); + + self.div.addClass('ke-dialog').bind('click,mousedown', function(e){ + e.stopPropagation(); + }); + var contentDiv = K('
      ').appendTo(self.div); + if (_IE && _V < 7) { + self.iframeMask = K('').appendTo(self.div); + } else if (shadowMode) { + K('
      ').appendTo(self.div); + } + var headerDiv = K('
      '); + contentDiv.append(headerDiv); + headerDiv.html(title); + self.closeIcon = K('').click(closeBtn.click); + headerDiv.append(self.closeIcon); + self.draggable({ + clickEl : headerDiv, + beforeDrag : options.beforeDrag + }); + var bodyDiv = K('
      '); + contentDiv.append(bodyDiv); + bodyDiv.append(body); + var footerDiv = K(''); + if (previewBtn || yesBtn || noBtn) { + contentDiv.append(footerDiv); + } + _each([ + { btn : previewBtn, name : 'preview' }, + { btn : yesBtn, name : 'yes' }, + { btn : noBtn, name : 'no' } + ], function() { + if (this.btn) { + var button = _createButton(this.btn); + button.addClass('ke-dialog-' + this.name); + footerDiv.append(button); + } + }); + if (self.height) { + bodyDiv.height(_removeUnit(self.height) - headerDiv.height() - footerDiv.height()); + } + self.div.width(self.div.width()); + self.div.height(self.div.height()); + self.mask = null; + if (showMask) { + var docEl = _docElement(self.doc), + docWidth = Math.max(docEl.scrollWidth, docEl.clientWidth), + docHeight = Math.max(docEl.scrollHeight, docEl.clientHeight); + self.mask = _widget({ + x : 0, + y : 0, + z : self.z - 1, + cls : 'ke-dialog-mask', + width : docWidth, + height : docHeight + }); + } + self.autoPos(self.div.width(), self.div.height()); + self.footerDiv = footerDiv; + self.bodyDiv = bodyDiv; + self.headerDiv = headerDiv; + self.isLoading = false; + }, + setMaskIndex : function(z) { + var self = this; + self.mask.div.css('z-index', z); + }, + showLoading : function(msg) { + msg = _undef(msg, ''); + var self = this, body = self.bodyDiv; + self.loading = K('
      ' + msg + '
      ') + .width(body.width()).height(body.height()) + .css('top', self.headerDiv.height() + 'px'); + body.css('visibility', 'hidden').after(self.loading); + self.isLoading = true; + return self; + }, + hideLoading : function() { + this.loading && this.loading.remove(); + this.bodyDiv.css('visibility', 'visible'); + this.isLoading = false; + return this; + }, + remove : function() { + var self = this; + if (self.options.beforeRemove) { + self.options.beforeRemove.call(self); + } + self.mask && self.mask.remove(); + self.iframeMask && self.iframeMask.remove(); + self.closeIcon.unbind(); + K('input', self.div).unbind(); + K('button', self.div).unbind(); + self.footerDiv.unbind(); + self.bodyDiv.unbind(); + self.headerDiv.unbind(); + K('iframe', self.div).each(function() { + //this.src = 'javascript:false'; + K(this).remove(); + }); + KDialog.parent.remove.call(self); + return self; + } +}); + +function _dialog(options) { + return new KDialog(options); +} + +K.DialogClass = KDialog; +K.dialog = _dialog; diff --git a/php/kindeditor_demo/kindeditor/src/edit.js b/php/kindeditor_demo/kindeditor/src/edit.js new file mode 100755 index 0000000..d04a5cb --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/edit.js @@ -0,0 +1,371 @@ + +function _iframeDoc(iframe) { + iframe = _get(iframe); + return iframe.contentDocument || iframe.contentWindow.document; +} + +var html, _direction = ''; +if ((html = document.getElementsByTagName('html'))) { + _direction = html[0].dir; +} + +function _getInitHtml(themesPath, bodyClass, cssPath, cssData) { + var arr = [ + (_direction === '' ? '' : ''), + '', + '' + ]; + if (!_isArray(cssPath)) { + cssPath = [cssPath]; + } + _each(cssPath, function(i, path) { + if (path) { + arr.push(''); + } + }); + if (cssData) { + arr.push(''); + } + arr.push(''); + return arr.join('\n'); +} + +function _elementVal(knode, val) { + if (knode.hasVal()) { + if (val === undefined) { + var html = knode.val(); + // 去除内容为空的p标签 + // https://github.com/kindsoft/kindeditor/pull/52 + html = html.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/ig, ''); + return html; + } + return knode.val(val); + } + return knode.html(val); +} + +// create KEdit class +function KEdit(options) { + this.init(options); +} +_extend(KEdit, KWidget, { + init : function(options) { + var self = this; + KEdit.parent.init.call(self, options); + + self.srcElement = K(options.srcElement); + self.div.addClass('ke-edit'); + self.designMode = _undef(options.designMode, true); + self.beforeGetHtml = options.beforeGetHtml; + self.beforeSetHtml = options.beforeSetHtml; + self.afterSetHtml = options.afterSetHtml; + + var themesPath = _undef(options.themesPath, ''), + bodyClass = options.bodyClass, + cssPath = options.cssPath, + cssData = options.cssData, + isDocumentDomain = location.protocol != 'res:' && location.host.replace(/:\d+/, '') !== document.domain, + srcScript = ('document.open();' + + (isDocumentDomain ? 'document.domain="' + document.domain + '";' : '') + + 'document.close();'), + iframeSrc = _IE ? ' src="javascript:void(function(){' + encodeURIComponent(srcScript) + '}())"' : ''; + self.iframe = K('').css('width', '100%'); + self.textarea = K('').css('width', '100%'); + self.tabIndex = isNaN(parseInt(options.tabIndex, 10)) ? self.srcElement.attr('tabindex') : parseInt(options.tabIndex, 10); + self.iframe.attr('tabindex', self.tabIndex); + self.textarea.attr('tabindex', self.tabIndex); + + if (self.width) { + self.setWidth(self.width); + } + if (self.height) { + self.setHeight(self.height); + } + if (self.designMode) { + self.textarea.hide(); + } else { + self.iframe.hide(); + } + function ready() { + var doc = _iframeDoc(self.iframe); + doc.open(); + if (isDocumentDomain) { + doc.domain = document.domain; + } + doc.write(_getInitHtml(themesPath, bodyClass, cssPath, cssData)); + doc.close(); + self.win = self.iframe[0].contentWindow; + self.doc = doc; + var cmd = _cmd(doc); + // add events + self.afterChange(function(e) { + cmd.selection(); + }); + // [WEBKIT] select an image after click the image + if (_WEBKIT) { + K(doc).click(function(e) { + if (K(e.target).name === 'img') { + cmd.selection(true); + cmd.range.selectNode(e.target); + cmd.select(); + } + }); + } + if (_IE) { + // Fix bug: https://github.com/kindsoft/kindeditor/issues/53 + self._mousedownHandler = function() { + var newRange = cmd.range.cloneRange(); + newRange.shrink(); + if (newRange.isControl()) { + self.blur(); + } + }; + K(document).mousedown(self._mousedownHandler); + // [IE] bug: clear iframe when press backspase key + K(doc).keydown(function(e) { + if (e.which == 8) { + cmd.selection(); + var rng = cmd.range; + if (rng.isControl()) { + rng.collapse(true); + K(rng.startContainer.childNodes[rng.startOffset]).remove(); + e.preventDefault(); + } + } + }); + } + self.cmd = cmd; + self.html(_elementVal(self.srcElement)); + if (_IE) { + doc.body.disabled = true; + doc.body.contentEditable = true; + doc.body.removeAttribute('disabled'); + } else { + doc.designMode = 'on'; + } + if (options.afterCreate) { + options.afterCreate.call(self); + } + } + if (isDocumentDomain) { + self.iframe.bind('load', function(e) { + self.iframe.unbind('load'); + if (_IE) { + ready(); + } else { + setTimeout(ready, 0); + } + }); + } + self.div.append(self.iframe); + self.div.append(self.textarea); + self.srcElement.hide(); + !isDocumentDomain && ready(); + }, + setWidth : function(val) { + var self = this; + val = _addUnit(val); + self.width = val; + self.div.css('width', val); + return self; + }, + setHeight : function(val) { + var self = this; + val = _addUnit(val); + self.height = val; + self.div.css('height', val); + self.iframe.css('height', val); + // 校正IE6和IE7的textarea高度 + if ((_IE && _V < 8) || _QUIRKS) { + val = _addUnit(_removeUnit(val) - 2); + } + self.textarea.css('height', val); + return self; + }, + remove : function() { + var self = this, doc = self.doc; + // remove events + K(doc.body).unbind(); + K(doc).unbind(); + K(self.win).unbind(); + if (self._mousedownHandler) { + K(document).unbind('mousedown', self._mousedownHandler); + } + // remove elements + _elementVal(self.srcElement, self.html()); + self.srcElement.show(); + // doc.write(''); + self.iframe.unbind(); + self.textarea.unbind(); + KEdit.parent.remove.call(self); + }, + html : function(val, isFull) { + var self = this, doc = self.doc; + // design mode + if (self.designMode) { + var body = doc.body; + // get + if (val === undefined) { + if (isFull) { + val = '' + body.parentNode.innerHTML + ''; + } else { + val = body.innerHTML; + } + if (self.beforeGetHtml) { + val = self.beforeGetHtml(val); + } + // bugfix: Firefox自动生成一个br标签 + if (_GECKO && val == '
      ') { + val = ''; + } + return val; + } + // set + if (self.beforeSetHtml) { + val = self.beforeSetHtml(val); + } + // IE9 Bugfix: https://github.com/kindsoft/kindeditor/issues/62 + if (_IE && _V >= 9) { + val = val.replace(/(<.*?checked=")checked(".*>)/ig, '$1$2'); + } + K(body).html(val); + if (self.afterSetHtml) { + self.afterSetHtml(); + } + return self; + } + // source mode + if (val === undefined) { + return self.textarea.val(); + } + self.textarea.val(val); + return self; + }, + design : function(bool) { + var self = this, val; + if (bool === undefined ? !self.designMode : bool) { + if (!self.designMode) { + val = self.html(); + + self.designMode = true; + self.textarea.hide(); + + self.html(val); + + // cache + var iframe = self.iframe; + var height = _removeUnit(self.height); + + iframe.height(height - 2); + iframe.show(); + + // safari iframe scrollbar hack + setTimeout(function() { + iframe.height(height); + }, 0); + } + } else { + if (self.designMode) { + val = self.html(); + self.designMode = false; + self.html(val); + self.iframe.hide(); + self.textarea.show(); + } + } + return self.focus(); + }, + focus : function() { + var self = this; + self.designMode ? self.win.focus() : self.textarea[0].focus(); + return self; + }, + blur : function() { + var self = this; + if (_IE) { + var input = K('', self.div); + self.div.append(input); + input[0].focus(); + input.remove(); + } else { + self.designMode ? self.win.blur() : self.textarea[0].blur(); + } + return self; + }, + afterChange : function(fn) { + var self = this, doc = self.doc, body = doc.body; + K(doc).keyup(function(e) { + if (!e.ctrlKey && !e.altKey && _CHANGE_KEY_MAP[e.which]) { + fn(e); + } + }); + K(doc).mouseup(fn).contextmenu(fn); + K(self.win).blur(fn); + function timeoutHandler(e) { + setTimeout(function() { + fn(e); + }, 1); + } + K(body).bind('paste', timeoutHandler); + K(body).bind('cut', timeoutHandler); + return self; + } +}); + +function _edit(options) { + return new KEdit(options); +} + +K.EditClass = KEdit; +K.edit = _edit; +K.iframeDoc = _iframeDoc; diff --git a/php/kindeditor_demo/kindeditor/src/event.js b/php/kindeditor_demo/kindeditor/src/event.js new file mode 100755 index 0000000..facbc79 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/event.js @@ -0,0 +1,389 @@ + +var _useCapture = false; + +/** +DOM_VK_BACK_SPACE : 8 +DOM_VK_TAB : 9 +DOM_VK_RETURN : 13 +DOM_VK_SPACE : 32 +DOM_VK_PAGE_UP : 33 +DOM_VK_PAGE_DOWN : 34 +DOM_VK_END : 35 +DOM_VK_HOME : 36 +DOM_VK_LEFT : 37 +DOM_VK_UP : 38 +DOM_VK_RIGHT : 39 +DOM_VK_DOWN : 40 +DOM_VK_DELETE : 46 +DOM_VK_0 ~ DOM_VK_9 : 48 ~ 57 +DOM_VK_SEMICOLON : 59 (;:) +DOM_VK_EQUALS : 61 (=+) (+) +DOM_VK_A ~ DOM_VK_Z : 65 ~ 90 +DOM_VK_MULTIPLY : 106 (*) +DOM_VK_SUBTRACT : 109 (-_) (-) +DOM_VK_DECIMAL : 110 (.) +DOM_VK_DIVIDE : 111 (/) +DOM_VK_COMMA : 188 (,<) +DOM_VK_PERIOD : 190 (.>) +DOM_VK_SLASH : 191 (/?) +DOM_VK_BACK_QUOTE : 192 (`~) +DOM_VK_OPEN_BRACKET : 219 ([{) +DOM_VK_BACK_SLASH : 220 (\|) +DOM_VK_CLOSE_BRACKET : 221 (]}) +DOM_VK_QUOTE : 222 ('") +*/ +// 输入文字的键值 +var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222'); +// 移动光标的键值 +var _CURSORMOVE_KEY_MAP = _toMap('33..40'); +// 输入文字或移动光标的键值 +var _CHANGE_KEY_MAP = {}; +_each(_INPUT_KEY_MAP, function(key, val) { + _CHANGE_KEY_MAP[key] = val; +}); +_each(_CURSORMOVE_KEY_MAP, function(key, val) { + _CHANGE_KEY_MAP[key] = val; +}); + +// add native event +function _bindEvent(el, type, fn) { + if (el.addEventListener){ + el.addEventListener(type, fn, _useCapture); + } else if (el.attachEvent){ + el.attachEvent('on' + type, fn); + } +} +// remove native event +function _unbindEvent(el, type, fn) { + if (el.removeEventListener){ + el.removeEventListener(type, fn, _useCapture); + } else if (el.detachEvent){ + el.detachEvent('on' + type, fn); + } +} + +var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,' + + 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,' + + 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which').split(','); + +// create KEvent class +function KEvent(el, event) { + this.init(el, event); +} +_extend(KEvent, { + init : function(el, event) { + var self = this, doc = el.ownerDocument || el.document || el; + self.event = event; + _each(_EVENT_PROPS, function(key, val) { + self[val] = event[val]; + }); + if (!self.target) { + self.target = self.srcElement || doc; + } + if (self.target.nodeType === 3) { + self.target = self.target.parentNode; + } + if (!self.relatedTarget && self.fromElement) { + self.relatedTarget = self.fromElement === self.target ? self.toElement : self.fromElement; + } + if (self.pageX == null && self.clientX != null) { + var d = doc.documentElement, body = doc.body; + self.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0); + self.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0); + } + if (!self.which && ((self.charCode || self.charCode === 0) ? self.charCode : self.keyCode)) { + self.which = self.charCode || self.keyCode; + } + if (!self.metaKey && self.ctrlKey) { + self.metaKey = self.ctrlKey; + } + if (!self.which && self.button !== undefined) { + self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : (self.button & 4 ? 2 : 0))); + } + /** + DOM_VK_SEMICOLON : 59 (;:) + - IE,WEBKIT: 186 + - GECKO,OPERA : 59 + DOM_VK_EQUALS : 61 (=+) + - IE,WEBKIT : 187 + - GECKO : 107 + - OPERA : 61 + DOM_VK_NUMPAD0 ~ DOM_VK_NUMPAD9 : 96 ~ 105 + - IE、WEBKIT,GECKO : 96 ~ 105 + - OPERA : 48 ~ 57 + DOM_VK_MULTIPLY : 106 (*) + - IE、WEBKIT,GECKO : 106 + - OPERA : 42 + DOM_VK_ADD : 107 (+) + - IE、WEBKIT,GECKO : 107 + - OPERA : 43 + DOM_VK_SUBTRACT : 109 (-_) (-) + - IE,WEBKIT : 189, 109 + - GECKO : 109, 109 + - OPERA : 109, 45 + DOM_VK_DECIMAL : 110 (.) + - IE、WEBKIT,GECKO : 110 + - OPERA : 78 + DOM_VK_DIVIDE : 111 (/) + - IE、WEBKIT,GECKO : 111 + - OPERA : 47 + + Reference: + https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent + http://msdn.microsoft.com/en-us/library/ms536940(v=VS.85).aspx + */ + switch (self.which) { + case 186 : + self.which = 59; + break; + case 187 : + case 107 : + case 43 : + self.which = 61; + break; + case 189 : + case 45 : + self.which = 109; + break; + case 42 : + self.which = 106; + break; + case 47 : + self.which = 111; + break; + case 78 : + self.which = 110; + break; + } + if (self.which >= 96 && self.which <= 105) { + self.which -= 48; + } + }, + preventDefault : function() { + var ev = this.event; + if (ev.preventDefault) { + ev.preventDefault(); + } else { + ev.returnValue = false; + } + }, + stopPropagation : function() { + var ev = this.event; + if (ev.stopPropagation) { + ev.stopPropagation(); + } else { + ev.cancelBubble = true; + } + }, + stop : function() { + this.preventDefault(); + this.stopPropagation(); + } +}); + +var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {}; + +function _getId(el) { + return el[_eventExpendo] || null; +} + +function _setId(el) { + el[_eventExpendo] = ++_eventId; + return _eventId; +} + +function _removeId(el) { + try { + delete el[_eventExpendo]; + } catch(e) { + if (el.removeAttribute) { + el.removeAttribute(_eventExpendo); + } + } +} + +function _bind(el, type, fn) { + if (type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _bind(el, this, fn); + }); + return; + } + var id = _getId(el); + if (!id) { + id = _setId(el); + } + if (_eventData[id] === undefined) { + _eventData[id] = {}; + } + var events = _eventData[id][type]; + if (events && events.length > 0) { + _unbindEvent(el, type, events[0]); + } else { + _eventData[id][type] = []; + _eventData[id].el = el; + } + events = _eventData[id][type]; + if (events.length === 0) { + events[0] = function(e) { + var kevent = e ? new KEvent(el, e) : undefined; + _each(events, function(i, event) { + if (i > 0 && event) { + event.call(el, kevent); + } + }); + }; + } + if (_inArray(fn, events) < 0) { + events.push(fn); + } + _bindEvent(el, type, events[0]); +} + +function _unbind(el, type, fn) { + if (type && type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _unbind(el, this, fn); + }); + return; + } + var id = _getId(el); + if (!id) { + return; + } + if (type === undefined) { + if (id in _eventData) { + _each(_eventData[id], function(key, events) { + if (key != 'el' && events.length > 0) { + _unbindEvent(el, key, events[0]); + } + }); + delete _eventData[id]; + _removeId(el); + } + return; + } + if (!_eventData[id]) { + return; + } + var events = _eventData[id][type]; + if (events && events.length > 0) { + if (fn === undefined) { + _unbindEvent(el, type, events[0]); + delete _eventData[id][type]; + } else { + _each(events, function(i, event) { + if (i > 0 && event === fn) { + events.splice(i, 1); + } + }); + if (events.length == 1) { + _unbindEvent(el, type, events[0]); + delete _eventData[id][type]; + } + } + var count = 0; + _each(_eventData[id], function() { + count++; + }); + if (count < 2) { + delete _eventData[id]; + _removeId(el); + } + } +} + +function _fire(el, type) { + if (type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _fire(el, this); + }); + return; + } + var id = _getId(el); + if (!id) { + return; + } + var events = _eventData[id][type]; + if (_eventData[id] && events && events.length > 0) { + events[0](); + } +} + +function _ctrl(el, key, fn) { + var self = this; + key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0); + _bind(el, 'keydown', function(e) { + if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) { + fn.call(el); + e.stop(); + } + }); +} + +var _readyFinished = false; + +function _ready(fn) { + if (_readyFinished) { + fn(KindEditor); + return; + } + var loaded = false; + function readyFunc() { + if (!loaded) { + loaded = true; + fn(KindEditor); + _readyFinished = true; + } + } + function ieReadyFunc() { + if (!loaded) { + try { + document.documentElement.doScroll('left'); + } catch(e) { + setTimeout(ieReadyFunc, 100); + return; + } + readyFunc(); + } + } + function ieReadyStateFunc() { + if (document.readyState === 'complete') { + readyFunc(); + } + } + if (document.addEventListener) { + _bind(document, 'DOMContentLoaded', readyFunc); + } else if (document.attachEvent) { + _bind(document, 'readystatechange', ieReadyStateFunc); + // 在跨域的frame里调用会报错 + var toplevel = false; + try { + toplevel = window.frameElement == null; + } catch(e) {} + if (document.documentElement.doScroll && toplevel) { + ieReadyFunc(); + } + } + _bind(window, 'load', readyFunc); +} + +/** + Note: + 发现绑定dbclick事件后移除element会有内存泄漏,以下代码也不起作用。 + Reference: + http://isaacschlueter.com/2006/10/msie-memory-leaks/ + http://msdn.microsoft.com/en-us/library/bb250448.aspx +*/ +if (window.attachEvent) { + window.attachEvent('onunload', function() { + _each(_eventData, function(key, events) { + if (events.el) { + _unbind(events.el); + } + }); + }); +} + +K.ctrl = _ctrl; +K.ready = _ready; diff --git a/php/kindeditor_demo/kindeditor/src/footer.js b/php/kindeditor_demo/kindeditor/src/footer.js new file mode 100755 index 0000000..a1e329f --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/footer.js @@ -0,0 +1,2 @@ + +})(window); diff --git a/php/kindeditor_demo/kindeditor/src/header.js b/php/kindeditor_demo/kindeditor/src/header.js new file mode 100755 index 0000000..d0ca4be --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/header.js @@ -0,0 +1,15 @@ +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-${THISYEAR} kindsoft.net +* +* @author Roddy +* @website http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +* @version ${VERSION} +*******************************************************************************/ + +(function (window, undefined) { + + if (window.KindEditor) { + return; + } diff --git a/php/kindeditor_demo/kindeditor/src/html.js b/php/kindeditor_demo/kindeditor/src/html.js new file mode 100755 index 0000000..2e07bcd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/html.js @@ -0,0 +1,428 @@ +function _getCssList(css) { + var list = {}, + reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g, + match; + while ((match = reg.exec(css))) { + var key = _trim(match[1].toLowerCase()), + val = _trim(_toHex(match[2])); + list[key] = val; + } + return list; +} + +function _getAttrList(tag) { + var list = {}, + reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g, + match; + while ((match = reg.exec(tag))) { + var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(), + val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || ''; + list[key] = val; + } + return list; +} + +function _addClassToTag(tag, className) { + if (/\s+class\s*=/.test(tag)) { + tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function($0, $1, $2, $3) { + if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) { + return $2 === '' ? $1 + className + $3 : $1 + $2 + ' ' + className + $3; + } else { + return $0; + } + }); + } else { + tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">'; + } + return tag; +} + +function _formatCss(css) { + var str = ''; + _each(_getCssList(css), function(key, val) { + str += key + ':' + val + ';'; + }); + return str; +} + +function _formatUrl(url, mode, host, pathname) { + mode = _undef(mode, '').toLowerCase(); + // 移除连续斜线,比如,http://localhost/upload/file/201205//maincus.swf + // base64 data 除外 + if (url.substr(0, 5) != 'data:') { + url = url.replace(/([^:])\/\//g, '$1/'); + } + if (_inArray(mode, ['absolute', 'relative', 'domain']) < 0) { + return url; + } + host = host || location.protocol + '//' + location.host; + if (pathname === undefined) { + var m = location.pathname.match(/^(\/.*)\//); + pathname = m ? m[1] : ''; + } + var match; + if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) { + if (match[1] !== host) { + return url; + } + } else if (/^\w+:/.test(url)) { + return url; + } + function getRealPath(path) { + var parts = path.split('/'), paths = []; + for (var i = 0, len = parts.length; i < len; i++) { + var part = parts[i]; + if (part == '..') { + if (paths.length > 0) { + paths.pop(); + } + } else if (part !== '' && part != '.') { + paths.push(part); + } + } + return '/' + paths.join('/'); + } + if (/^\//.test(url)) { + url = host + getRealPath(url.substr(1)); + } else if (!/^\w+:\/\//.test(url)) { + url = host + getRealPath(pathname + '/' + url); + } + function getRelativePath(path, depth) { + if (url.substr(0, path.length) === path) { + var arr = []; + for (var i = 0; i < depth; i++) { + arr.push('..'); + } + var prefix = '.'; + if (arr.length > 0) { + prefix += '/' + arr.join('/'); + } + if (pathname == '/') { + prefix += '/'; + } + return prefix + url.substr(path.length); + } else { + if ((match = /^(.*)\//.exec(path))) { + return getRelativePath(match[1], ++depth); + } + } + } + if (mode === 'relative') { + url = getRelativePath(host + pathname, 0).substr(2); + } else if (mode === 'absolute') { + if (url.substr(0, host.length) === host) { + url = url.substr(host.length); + } + } + return url; +} + +function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) { + // null or undefined: object == null + if (html == null) { + html = ''; + } + urlType = urlType || ''; + wellFormatted = _undef(wellFormatted, false); + indentChar = _undef(indentChar, '\t'); + var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(','); + // 将pre里的br转换成\n + html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) { + return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3; + }); + //

      to

      + html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '

      '); + //

      to


      + html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1
      $2'); + // empty char + html = html.replace(/\u200B/g, ''); + // © + html = html.replace(/\u00A9/g, '©'); + // ® + html = html.replace(/\u00AE/g, '®'); + // Bugfix: + // https://github.com/kindsoft/kindeditor/issues/147 + html = html.replace(/\u2003/g, ' '); + html = html.replace(/\u3000/g, ' '); + // Bugfix: + // https://github.com/kindsoft/kindeditor/issues/116 + // https://github.com/kindsoft/kindeditor/issues/145 + html = html.replace(/<[^>]+/g, function($0) { + return $0.replace(/\s+/g, ' '); + }); + + var htmlTagMap = {}; + if (htmlTags) { + // 展开htmlTags里的key + _each(htmlTags, function(key, val) { + var arr = key.split(','); + for (var i = 0, len = arr.length; i < len; i++) { + htmlTagMap[arr[i]] = _toMap(val); + } + }); + // 删除script和style里的内容 + if (!htmlTagMap.script) { + html = html.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig, ''); + } + if (!htmlTagMap.style) { + html = html.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig, ''); + } + } + var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g; + var tagStack = []; + html = html.replace(re, function($0, $1, $2, $3, $4, $5, $6) { + var full = $0, + startNewline = $1 || '', + startSlash = $2 || '', + tagName = $3.toLowerCase(), + attr = $4 || '', + endSlash = $5 ? ' ' + $5 : '', + endNewline = $6 || ''; + // 不在名单里的过滤掉 + if (htmlTags && !htmlTagMap[tagName]) { + return ''; + } + // 无闭合标签的自动添加斜线 + if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) { + endSlash = ' /'; + } + // inline tag时自动将多个空白转换成一个空格 + if (_INLINE_TAG_MAP[tagName]) { + if (startNewline) { + startNewline = ' '; + } + if (endNewline) { + endNewline = ' '; + } + } + // pre,style,script tag的格式化 + if (_PRE_TAG_MAP[tagName]) { + if (startSlash) { + endNewline = '\n'; + } else { + startNewline = '\n'; + } + } + // br tag + if (wellFormatted && tagName == 'br') { + endNewline = '\n'; + } + // block tag的格式化 + if (_BLOCK_TAG_MAP[tagName] && !_PRE_TAG_MAP[tagName]) { + if (wellFormatted) { + if (startSlash && tagStack.length > 0 && tagStack[tagStack.length - 1] === tagName) { + tagStack.pop(); + } else { + tagStack.push(tagName); + } + startNewline = '\n'; + endNewline = '\n'; + for (var i = 0, len = startSlash ? tagStack.length : tagStack.length - 1; i < len; i++) { + startNewline += indentChar; + if (!startSlash) { + endNewline += indentChar; + } + } + if (endSlash) { + tagStack.pop(); + } else if (!startSlash) { + endNewline += indentChar; + } + } else { + startNewline = endNewline = ''; + } + } + if (attr !== '') { + var attrMap = _getAttrList(full); + // 将font tag转换成span tag + if (tagName === 'font') { + var fontStyleMap = {}, fontStyle = ''; + _each(attrMap, function(key, val) { + if (key === 'color') { + fontStyleMap.color = val; + delete attrMap[key]; + } + if (key === 'size') { + fontStyleMap['font-size'] = fontSizeList[parseInt(val, 10) - 1] || ''; + delete attrMap[key]; + } + if (key === 'face') { + fontStyleMap['font-family'] = val; + delete attrMap[key]; + } + if (key === 'style') { + fontStyle = val; + } + }); + if (fontStyle && !/;$/.test(fontStyle)) { + fontStyle += ';'; + } + _each(fontStyleMap, function(key, val) { + if (val === '') { + return; + } + if (/\s/.test(val)) { + val = "'" + val + "'"; + } + fontStyle += key + ':' + val + ';'; + }); + attrMap.style = fontStyle; + } + // 处理attribute和style + _each(attrMap, function(key, val) { + // 补全单独属性 + if (_FILL_ATTR_MAP[key]) { + attrMap[key] = key; + } + // 处理URL + if (_inArray(key, ['src', 'href']) >= 0) { + attrMap[key] = _formatUrl(val, urlType); + } + // 过滤属性 + if (htmlTags && key !== 'style' && !htmlTagMap[tagName]['*'] && !htmlTagMap[tagName][key] || + tagName === 'body' && key === 'contenteditable' || + /^kindeditor_\d+$/.test(key)) { + delete attrMap[key]; + } + if (key === 'style' && val !== '') { + var styleMap = _getCssList(val); + _each(styleMap, function(k, v) { + // 过滤样式 + if (htmlTags && !htmlTagMap[tagName].style && !htmlTagMap[tagName]['.' + k]) { + delete styleMap[k]; + } + }); + var style = ''; + _each(styleMap, function(k, v) { + style += k + ':' + v + ';'; + }); + attrMap.style = style; + } + }); + attr = ''; + _each(attrMap, function(key, val) { + if (key === 'style' && val === '') { + return; + } + val = val.replace(/"/g, '"'); + attr += ' ' + key + '="' + val + '"'; + }); + } + if (tagName === 'font') { + tagName = 'span'; + } + return startNewline + '<' + startSlash + tagName + attr + endSlash + '>' + endNewline; + }); + // 将pre里的\n转换成 临时标签 + \n,防止被替换 + html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) { + return $1 + $2.replace(/\n/g, '\n') + $3; + }); + html = html.replace(/\n\s*\n/g, '\n'); + // 删除临时标签 + html = html.replace(/\n/g, '\n'); + return _trim(html); +} +// 清理MS Word专用标签 +function _clearMsWord(html, htmlTags) { + html = html.replace(//ig, '') + .replace(//ig, '') + .replace(/]*>[\s\S]*?<\/style>/ig, '') + .replace(/]*>[\s\S]*?<\/script>/ig, '') + .replace(/]+>[\s\S]*?<\/w:[^>]+>/ig, '') + .replace(/]+>[\s\S]*?<\/o:[^>]+>/ig, '') + .replace(/[\s\S]*?<\/xml>/ig, '') + .replace(/<(?:table|td)[^>]*>/ig, function(full) { + return full.replace(/border-bottom:([#\w\s]+)/ig, 'border:$1'); + }); + return _formatHtml(html, htmlTags); +} +// 根据URL判断 media type +function _mediaType(src) { + if (/\.(rm|rmvb)(\?|$)/i.test(src)) { + return 'audio/x-pn-realaudio-plugin'; + } + if (/\.(swf|flv)(\?|$)/i.test(src)) { + return 'application/x-shockwave-flash'; + } + return 'video/x-ms-asf-plugin'; +} +// 根据 media type取得className +function _mediaClass(type) { + if (/realaudio/i.test(type)) { + return 'ke-rm'; + } + if (/flash/i.test(type)) { + return 'ke-flash'; + } + return 'ke-media'; +} + +function _mediaAttrs(srcTag) { + return _getAttrList(unescape(srcTag)); +} + +function _mediaEmbed(attrs) { + var html = ' 0) { + style += 'width:' + width + 'px;'; + } + if (/\D/.test(height)) { + style += 'height:' + height + ';'; + } else if (height > 0) { + style += 'height:' + height + 'px;'; + } + var html = ''; + return html; +} + +// Simple JavaScript Templating +// John Resig - http://ejohn.org/ - MIT Licensed +// http://ejohn.org/blog/javascript-micro-templating/ +function _tmpl(str, data) { + // Figure out if we're getting a template, or if we need to + // load the template - and be sure to cache the result. + var fn = new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + // Introduce the data as local variables using with(){} + "with(obj){p.push('" + + // Convert the template into pure JavaScript + str.replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + "');}return p.join('');"); + // Provide some basic currying to the user + return data ? fn(data) : fn; +} + +K.formatUrl = _formatUrl; +K.formatHtml = _formatHtml; +K.getCssList = _getCssList; +K.getAttrList = _getAttrList; +K.mediaType = _mediaType; +K.mediaAttrs = _mediaAttrs; +K.mediaEmbed = _mediaEmbed; +K.mediaImg = _mediaImg; +K.clearMsWord = _clearMsWord; +K.tmpl = _tmpl; diff --git a/php/kindeditor_demo/kindeditor/src/main.js b/php/kindeditor_demo/kindeditor/src/main.js new file mode 100755 index 0000000..b6b0fd3 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/src/main.js @@ -0,0 +1,1623 @@ + +var _plugins = {}; + +function _plugin(name, fn) { + if (name === undefined) { + return _plugins; + } + if (!fn) { + return _plugins[name]; + } + _plugins[name] = fn; +} + +var _language = {}; + +function _parseLangKey(key) { + var match, ns = 'core'; + if ((match = /^(\w+)\.(\w+)$/.exec(key))) { + ns = match[1]; + key = match[2]; + } + return { ns : ns, key : key }; +} +/** + @example + K.lang('about'); //get core.about + K.lang('about.version'); // get about.version + K.lang('about.').version; // get about.version + K.lang('about', 'en'); //get English core.about + K.lang({ + core.about : '关于', + about.version : '4.0' + }, 'zh-CN'); //add language +*/ +function _lang(mixed, langType) { + langType = langType === undefined ? K.options.langType : langType; + if (typeof mixed === 'string') { + if (!_language[langType]) { + return 'no language'; + } + var pos = mixed.length - 1; + if (mixed.substr(pos) === '.') { + return _language[langType][mixed.substr(0, pos)]; + } + var obj = _parseLangKey(mixed); + return _language[langType][obj.ns][obj.key]; + } + _each(mixed, function(key, val) { + var obj = _parseLangKey(key); + if (!_language[langType]) { + _language[langType] = {}; + } + if (!_language[langType][obj.ns]) { + _language[langType][obj.ns] = {}; + } + _language[langType][obj.ns][obj.key] = val; + }); +} + +// 当前range为图片时返回KNode,否则返回undefined +function _getImageFromRange(range, fn) { + if (range.collapsed) { + return; + } + range = range.cloneRange().up(); + var sc = range.startContainer, so = range.startOffset; + if (!_WEBKIT && !range.isControl()) { + return; + } + var img = K(sc.childNodes[so]); + if (!img || img.name != 'img') { + return; + } + if (fn(img)) { + return img; + } +} + +function _bindContextmenuEvent() { + var self = this, doc = self.edit.doc; + K(doc).contextmenu(function(e) { + if (self.menu) { + self.hideMenu(); + } + if (!self.useContextmenu) { + e.preventDefault(); + return; + } + if (self._contextmenus.length === 0) { + return; + } + var maxWidth = 0, items = []; + _each(self._contextmenus, function() { + if (this.title == '-') { + items.push(this); + return; + } + if (this.cond && this.cond()) { + items.push(this); + if (this.width && this.width > maxWidth) { + maxWidth = this.width; + } + } + }); + while (items.length > 0 && items[0].title == '-') { + items.shift(); + } + while (items.length > 0 && items[items.length - 1].title == '-') { + items.pop(); + } + var prevItem = null; + _each(items, function(i) { + if (this.title == '-' && prevItem.title == '-') { + delete items[i]; + } + prevItem = this; + }); + if (items.length > 0) { + e.preventDefault(); + var pos = K(self.edit.iframe).pos(), + menu = _menu({ + x : pos.x + e.clientX, + y : pos.y + e.clientY, + width : maxWidth, + css : { visibility: 'hidden' }, + shadowMode : self.shadowMode + }); + _each(items, function() { + if (this.title) { + menu.addItem(this); + } + }); + // 下拉菜单超过可视区域时调整菜单位置 + var docEl = _docElement(menu.doc), + menuHeight = menu.div.height(); + if (e.clientY + menuHeight >= docEl.clientHeight - 100) { + menu.pos(menu.x, _removeUnit(menu.y) - menuHeight); + } + menu.div.css('visibility', 'visible'); + self.menu = menu; + } + }); +} + +function _bindNewlineEvent() { + var self = this, doc = self.edit.doc, newlineTag = self.newlineTag; + if (_IE && newlineTag !== 'br') { + return; + } + if (_GECKO && _V < 3 && newlineTag !== 'p') { + return; + } + if (_OPERA && _V < 9) { + return; + } + var brSkipTagMap = _toMap('h1,h2,h3,h4,h5,h6,pre,li'), + pSkipTagMap = _toMap('p,h1,h2,h3,h4,h5,h6,pre,li,blockquote'); + // 取得range的block标签名 + function getAncestorTagName(range) { + var ancestor = K(range.commonAncestor()); + while (ancestor) { + if (ancestor.type == 1 && !ancestor.isStyle()) { + break; + } + ancestor = ancestor.parent(); + } + return ancestor.name; + } + K(doc).keydown(function(e) { + if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) { + return; + } + self.cmd.selection(); + var tagName = getAncestorTagName(self.cmd.range); + if (tagName == 'marquee' || tagName == 'select') { + return; + } + // br + if (newlineTag === 'br' && !brSkipTagMap[tagName]) { + e.preventDefault(); + self.insertHtml('
      ' + (_IE && _V < 9 ? '' : '\u200B')); + return; + } + // p + if (!pSkipTagMap[tagName]) { + _nativeCommand(doc, 'formatblock', '

      '); + } + }); + K(doc).keyup(function(e) { + if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) { + return; + } + if (newlineTag == 'br') { + return; + } + if (_GECKO) { + var root = self.cmd.commonAncestor('p'); + var a = self.cmd.commonAncestor('a'); + if (a && a.text() == '') { + a.remove(true); + self.cmd.range.selectNodeContents(root[0]).collapse(true); + self.cmd.select(); + } + return; + } + self.cmd.selection(); + var tagName = getAncestorTagName(self.cmd.range); + if (tagName == 'marquee' || tagName == 'select') { + return; + } + if (!pSkipTagMap[tagName]) { + _nativeCommand(doc, 'formatblock', '

      '); + } + // [WEBKIT] 将DIV改成P + var div = self.cmd.commonAncestor('div'); + if (div) { + var p = K('

      '), + child = div[0].firstChild; + while (child) { + var next = child.nextSibling; + p.append(child); + child = next; + } + div.before(p); + div.remove(); + self.cmd.range.selectNodeContents(p[0]); + self.cmd.select(); + } + }); +} + +function _bindTabEvent() { + var self = this, doc = self.edit.doc; + K(doc).keydown(function(e) { + if (e.which == 9) { + e.preventDefault(); + if (self.afterTab) { + self.afterTab.call(self, e); + return; + } + var cmd = self.cmd, range = cmd.range; + range.shrink(); + // Bugfix #271: 回车,按下tab键,光标在下一行显示 + if (range.collapsed && range.startContainer.nodeType == 1) { + range.insertNode(K('@ ', doc)[0]); + cmd.select(); + } + self.insertHtml('    '); + } + }); +} + +function _bindFocusEvent() { + var self = this; + K(self.edit.textarea[0], self.edit.win).focus(function(e) { + if (self.afterFocus) { + self.afterFocus.call(self, e); + } + }).blur(function(e) { + if (self.afterBlur) { + self.afterBlur.call(self, e); + } + }); +} + +function _removeBookmarkTag(html) { + return _trim(html.replace(/]*id="?__kindeditor_bookmark_\w+_\d+__"?[^>]*><\/span>/ig, '')); +} + +function _removeTempTag(html) { + return html.replace(/]+class="?__kindeditor_paste__"?[^>]*>[\s\S]*?<\/div>/ig, ''); +} + +function _addBookmarkToStack(stack, bookmark) { + if (stack.length === 0) { + stack.push(bookmark); + return; + } + var prev = stack[stack.length - 1]; + if (_removeBookmarkTag(bookmark.html) !== _removeBookmarkTag(prev.html)) { + stack.push(bookmark); + } +} + +// undo: _undoToRedo.call(this, undoStack, redoStack); +// redo: _undoToRedo.call(this, redoStack, undoStack); +function _undoToRedo(fromStack, toStack) { + var self = this, edit = self.edit, + body = edit.doc.body, + range, bookmark; + if (fromStack.length === 0) { + return self; + } + if (edit.designMode) { + range = self.cmd.range; + bookmark = range.createBookmark(true); + bookmark.html = body.innerHTML; + } else { + bookmark = { + html : body.innerHTML + }; + } + _addBookmarkToStack(toStack, bookmark); + var prev = fromStack.pop(); + if (_removeBookmarkTag(bookmark.html) === _removeBookmarkTag(prev.html) && fromStack.length > 0) { + prev = fromStack.pop(); + } + if (edit.designMode) { + edit.html(prev.html); + if (prev.start) { + range.moveToBookmark(prev); + self.select(); + } + } else { + K(body).html(_removeBookmarkTag(prev.html)); + } + return self; +} + +function KEditor(options) { + var self = this; + // save original options + self.options = {}; + function setOption(key, val) { + if (KEditor.prototype[key] === undefined) { + self[key] = val; + } + self.options[key] = val; + } + // set options from param + _each(options, function(key, val) { + setOption(key, options[key]); + }); + // set options from default setting + _each(K.options, function(key, val) { + if (self[key] === undefined) { + setOption(key, val); + } + }); + var se = K(self.srcElement || ' +
      +
      +
      +
      + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/edit.js b/php/kindeditor_demo/kindeditor/test/edit.js new file mode 100755 index 0000000..284dce2 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/edit.js @@ -0,0 +1,52 @@ + +var edit = null; + +var cmds = { + bold : '', + italic : '', + underline : '', + strikethrough : '', + forecolor : '#FF0000', + hilitecolor : '#DDDDDD', + fontsize : '32px', + fontfamily : 'Arial Black', + removeformat : '', + selectall : '' +}; + +K.each(cmds, function(key, val) { + var a = K('' + key + '').bind('click', (function(key, val) { + return function(e) { + edit.cmd[key](val); + e.stop(); + }; + })(key, val)); + K('#cmdArea').append(a); + K('#cmdArea').append(document.createTextNode(' ')); +}); + +edit = K.edit({ + src : 'div#edit', + srcElement : 'body textarea', + width : '700px', + height : '200px', + designMode : true, + bodyClass : 'ke-content', + cssData : 'body {font-size:12px;margin:0;}' +}); + +K('#design').bind('click', function(e) { + if (edit) { + edit.design(true); + } +}); +K('#source').bind('click', function(e) { + if (edit) { + edit.design(false); + } +}); +K('#toggle').bind('click', function(e) { + if (edit) { + edit.design(); + } +}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/editor.html b/php/kindeditor_demo/kindeditor/test/editor.html new file mode 100755 index 0000000..4315374 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/editor.html @@ -0,0 +1,59 @@ + + + + + KindEditor Unittest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      KindEditor Unittest

      +

      KindEditor Unittest

      +

      +
        +
        +
        + +
        + +
        + + + + diff --git a/php/kindeditor_demo/kindeditor/test/editor.js b/php/kindeditor_demo/kindeditor/test/editor.js new file mode 100755 index 0000000..f5176b8 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/editor.js @@ -0,0 +1,140 @@ +module("editor"); + +KindEditor.ready(function (K) { + + var editor = K.create('#content1', { + basePath : '../', + filterMode : false, + wellFormatMode : false + }); + + var editor2 = K.create('#content2', { + basePath : '../', + filterMode : false, + wellFormatMode : false + }); + + test("K.instances", function() { + ok(editor == K.instances[0]); + ok(editor2 == K.instances[1]); + }); + + test("editor.html", function() { + editor.html(undefined); + equals(editor.html(), ''); + + editor.html(null); + equals(editor.html(), ''); + + editor.html('

        abc

        '); + equals(editor.html(), '

        abc

        '); + + editor.html('
        abc
        '); + equals(editor.html(), '
        abc
        '); + + editor.html(''); + equals(editor.html(), ''); + + editor.html('
        abc
        '); + equals(editor.html(), '
        abc
        '); + + editor.html('

        abc

        '); + equals(editor.html(), '

        abc

        '); + + editor.html('
        '); + equals(editor.html(), '
        '); + + editor.html('test'); + equals(editor.html(), 'test'); + + editor.html('test'); + equals(editor.html(), 'test'); + + editor.html(''); + equals(editor.html(), ''); + + editor.html(''); + equals(editor.html(), ''); + + editor.html('test'); + equals(editor.html(), 'test'); + + editor.html(''); + equals(editor.html(), ''); + + editor.html(''); + equals(editor.html(), ''); + + editor.html(''); + equals(editor.html(), ''); + + editor.html(''); + equals(editor.html(), ''); + + }); + + test("editor.text", function() { + editor.html('

        abc

        '); + equals(editor.text(), 'abc'); + editor.html('
        abc
        '); + equals(editor.text(), 'abc'); + editor.text('

        '); + equals(editor.text(), '<p class="a"></p>'); + editor.text(''); + equals(editor.text(), ''); + }); + + test("editor.insertHtml", function() { + editor.html('

        abc

        '); + var h3 = K('#test-h3', editor.edit.doc); + editor.cmd.range.selectNodeContents(h3[0]); + editor.cmd.select(); + editor.insertHtml('abc'); + equals(editor.html(), '

        abc

        '); + editor.html(''); + }); + + test("editor.selectedHtml", function() { + editor.html('abc'); + var span = K('#test', editor.edit.doc); + editor.cmd.range.setStart(span.first()[0], 0).setEnd(span.first()[0], 2); + editor.cmd.select(); + equals(editor.selectedHtml().replace(/<.+?>/g, ''), 'ab'); + editor.html(''); + }); + + test("editor.appendHtml", function() { + editor.html(''); + editor.appendHtml('

        abc

        '); + equals(editor.html(), '

        abc

        '); + editor.appendHtml('
        abc
        '); + equals(editor.html(), '

        abc

        abc
        '); + editor.html(''); + editor.appendHtml('abc'); + equals(editor.html(), 'abc'); + }); + + test("editor.isEmpty", function() { + editor.html('

        abc

        '); + ok(editor.isEmpty() === false); + editor.html('

        '); + ok(editor.isEmpty() === true); + editor.html(''); + ok(editor.isEmpty() === false); + editor.html(''); + }); + + test("editor.count", function() { + editor.html('

        abc

        '); + ok(editor.count('html') === 12); + ok(editor.count('text') === 3); + editor.html('

        '); + ok(editor.count('html') === 9); + ok(editor.count('text') === 0); + editor.html(''); + ok(editor.count('html') === 14); + ok(editor.count('text') === 1); + editor.html(''); + }); + +}); diff --git a/php/kindeditor_demo/kindeditor/test/event.html b/php/kindeditor_demo/kindeditor/test/event.html new file mode 100755 index 0000000..4e39d28 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/event.html @@ -0,0 +1,61 @@ + + + + + KindEditor Event Test + + + + + + + + + + + + + +

        KindEditor Event Test

        +

        +
          +
          + outer event: + inner event: + event method: +
          + +
          + + + + diff --git a/php/kindeditor_demo/kindeditor/test/event.js b/php/kindeditor_demo/kindeditor/test/event.js new file mode 100755 index 0000000..9c208dd --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/event.js @@ -0,0 +1,153 @@ +module('event'); + +test('bind/unbind/fire', function() { + var result = ''; + function click1(e) { + result += 'click1'; + } + //bind + K(document).click(click1); + result = ''; + K(document).click(); + equals(result, 'click1'); + //unbind + K(document).unbind('click', click1); + result = ''; + K(document).click(); + equals(result, ''); + function click2(e) { + K(this).html('click2'); + } + K('#test-data-01').click(click2); + K('#test-data-01').click(); + equals(K('#test-data-01').html(), 'click2'); +}); + +test('unbind(el, type, fn)', function() { + var result = ''; + function click1(e) { + result += 'click1'; + } + function click2(e) { + result += 'click2'; + } + function mousedown1(e) { + result += 'mousedown1'; + } + K(document).click(click1); + K(document).click(click2); + K(document).mousedown(mousedown1); + result = ''; + K(document).click(); + equals(result, 'click1click2'); + result = ''; + K(document).mousedown(); + equals(result, 'mousedown1'); + K(document).unbind('click', click1); + result = ''; + K(document).click(); + equals(result, 'click2'); + K(document).unbind('click', click2); + result = ''; + K(document).click(); + equals(result, ''); + K(document).unbind('mousedown', mousedown1); + result = ''; + K(document).mousedown(); + equals(result, ''); +}); + +test('unbind(el, type)', function() { + var result = ''; + function click1(e) { + result += 'click1'; + } + function click2(e) { + result += 'click2'; + } + function mousedown1(e) { + result += 'mousedown1'; + } + K(document).click(click1); + K(document).click(click2); + K(document).mousedown(mousedown1); + //unbind click + K(document).unbind('click'); + result = ''; + K(document).click(); + equals(result, ''); + //unbind mousedown + K(document).unbind('mousedown'); + result = ''; + K(document).mousedown(); + equals(result, ''); +}); + +test('unbind(el)', function() { + var result = ''; + function click1(e) { + result += 'click1'; + console.log('check'); + } + function click2(e) { + result += 'click2'; + console.log('check'); + } + function mousedown1(e) { + result += 'mousedown1'; + console.log('check'); + } + K(document).click(click1); + K(document).click(click2); + K(document).mousedown(mousedown1); + //unbind + K(document).unbind(); + result = ''; + K(document).click(); + equals(result, ''); + result = ''; + K(document).mousedown(); + equals(result, ''); +}); + +(function () { + var outerEvent = K('#outerEvent'), + innerEvent = K('#innerEvent'), + eventMethod = K('#eventMethod'), + outerDiv = K('#outerDiv'), + innerDiv = K('#innerDiv'); + outerEvent.change(function(e) { + outerDiv.unbind(); + if (outerEvent.val() === 'none') return; + outerDiv.bind(outerEvent.val(), function(e) { + console.log('outer: ' + outerEvent.val()); + if (eventMethod.val() === 'none') return; + e[eventMethod.val()](); + }); + }); + innerEvent.change(function(e) { + innerDiv.unbind(); + if (innerEvent.val() === 'none') return; + innerDiv.bind(innerEvent.val(), function(e) { + console.log('inner: ' + innerEvent.val()); + if (eventMethod.val() === 'none') return; + e[eventMethod.val()](); + }); + }); +})(); + +K.ready(function() { + console.log('ready1'); +}); +K.ready(function() { + console.log('ready2'); +}); +K.ready(function() { + console.log('ready3'); +}); +K.ready(function() { + console.log('ready4'); +}); +K.ready(function() { + console.log('ready5'); +}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/frame.html b/php/kindeditor_demo/kindeditor/test/frame.html new file mode 100755 index 0000000..f0c2f31 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/frame.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/hidden.html b/php/kindeditor_demo/kindeditor/test/hidden.html new file mode 100755 index 0000000..a46a144 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/hidden.html @@ -0,0 +1,48 @@ + + + + + + KindEditor Test + + +

          KindEditor Test

          + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/html.html b/php/kindeditor_demo/kindeditor/test/html.html new file mode 100755 index 0000000..cbb957a --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/html.html @@ -0,0 +1,48 @@ + + + + + KindEditor Unittest + + + + + + + + + + + +

          KindEditor Unittest

          +

          +
            + +
            + + + + + + + + + +
            test
            +
            123
            test
            123
            +
            +
            test
            +
            test
            +
            test
            +
            test
            +
            ddd
            +
            ddd
            +
            ddd
            +
            ddd
            +
            ©
            +
            + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/html.js b/php/kindeditor_demo/kindeditor/test/html.js new file mode 100755 index 0000000..778adc5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/html.js @@ -0,0 +1,91 @@ +module('html'); + +test("formatUrl", function() { + equals(K.formatUrl(K.query("#test01").value, "absolute", 'http://localhost', '/ke/test'), '/ke/images/xxx.gif'); + equals(K.formatUrl(K.query("#test01").value, "relative", 'http://localhost', '/ke/test'), '../images/xxx.gif'); + equals(K.formatUrl(K.query("#test01").value, "domain", 'http://localhost', '/ke/test'), 'http://localhost/ke/images/xxx.gif'); + equals(K.formatUrl(K.query("#test01").value), '../images/xxx.gif'); + + equals(K.formatUrl(K.query("#test02").value, "absolute", 'http://localhost:8080', '/ke/test'), '/images/xxx.gif'); + equals(K.formatUrl(K.query("#test02").value, "relative", 'http://localhost:8080', '/ke/test'), '../../images/xxx.gif'); + equals(K.formatUrl(K.query("#test02").value, "domain", 'http://localhost:8080', '/ke/test'), 'http://localhost:8080/images/xxx.gif'); + equals(K.formatUrl(K.query("#test02").value), './../../images/xxx.gif'); + + equals(K.formatUrl(K.query("#test03").value, "absolute", 'http://localhost', '/ke/test'), '/ke/images/xxx.gif'); + equals(K.formatUrl(K.query("#test03").value, "relative", 'http://localhost', '/ke/test'), '../images/xxx.gif'); + equals(K.formatUrl(K.query("#test03").value, "domain", 'http://localhost', '/ke/test'), 'http://localhost/ke/images/xxx.gif'); + equals(K.formatUrl(K.query("#test03").value), '/ke/images/xxx.gif'); + + equals(K.formatUrl(K.query("#test04").value, "absolute", 'http://localhost', '/ke/test'), '/ke/images/xxx.gif'); + equals(K.formatUrl(K.query("#test04").value, "relative", 'http://localhost', '/ke/images'), 'xxx.gif'); + equals(K.formatUrl(K.query("#test04").value, "domain", 'http://localhost', '/ke'), 'http://localhost/ke/images/xxx.gif'); + equals(K.formatUrl(K.query("#test04").value), 'http://localhost/ke/images/xxx.gif'); + + equals(K.formatUrl(K.query("#test05").value, "absolute", 'http://localhost', '/ke'), 'http://www.163.com/images/xxx.gif'); + equals(K.formatUrl(K.query("#test05").value, "relative", 'http://localhost', '/ke'), 'http://www.163.com/images/xxx.gif'); + equals(K.formatUrl(K.query("#test05").value, "domain", 'http://localhost', '/ke'), 'http://www.163.com/images/xxx.gif'); + equals(K.formatUrl(K.query("#test05").value), 'http://www.163.com/images/xxx.gif'); + + equals(K.formatUrl(K.query("#test06").value, "absolute", 'http://kindsoft.net', '/'), '/kindeditor/plugins/emoticons/etc_01.gif'); + equals(K.formatUrl(K.query("#test06").value, "relative", 'http://kindsoft.net', '/'), 'kindeditor/plugins/emoticons/etc_01.gif'); + equals(K.formatUrl(K.query("#test06").value, "domain", 'http://kindsoft.net', '/'), 'http://kindsoft.net/kindeditor/plugins/emoticons/etc_01.gif'); + equals(K.formatUrl(K.query("#test06").value), 'http://kindsoft.net/kindeditor/plugins/emoticons/etc_01.gif'); + + equals(K.formatUrl(K.query("#test07").value, "absolute", 'http://kindsoft.net', '/'), 'mailto:test@test.com'); + equals(K.formatUrl(K.query("#test07").value, "relative", 'http://kindsoft.net', '/'), 'mailto:test@test.com'); + equals(K.formatUrl(K.query("#test07").value, "domain", 'http://kindsoft.net', '/'), 'mailto:test@test.com'); + equals(K.formatUrl(K.query("#test07").value), 'mailto:test@test.com'); + + equals(K.formatUrl('http://static.domain.com/img//123.png'), 'http://static.domain.com/img/123.png'); + + equals(K.formatUrl('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='); +}); + +test("formatHtml", function() { + equals(K.formatHtml(K.query("#test11").innerHTML).toLowerCase(), 'test'); + equals(K.formatHtml(K.query("#test11").innerHTML, {span:[".color"]}).toLowerCase(), 'test'); + equals(K.formatHtml(K.query("#test11").innerHTML, {span:[".font-size", "class"]}), 'test'); + equals(K.formatHtml(K.query("#test11").innerHTML, {div:[".font-size", "class"]}), 'test'); + equals(K.formatHtml(K.query("#test11").innerHTML, {span:["style"]}).toLowerCase(), 'test'); + equals(K.formatHtml(K.query("#test11").innerHTML, {span:[]}), 'test'); + + equals(K.formatHtml(K.query("#test12").innerHTML).toLowerCase(), '123
            test
            123'); + equals(K.formatHtml(K.query("#test12").innerHTML, {span:[".color"]}), '123test123'); + equals(K.formatHtml(K.query("#test12").innerHTML, {div:[".font-size", "class"]}), '123
            test
            123'); + equals(K.formatHtml(K.query("#test12").innerHTML, {div:[".color"]}).toLowerCase(), '123
            test
            123'); + equals(K.formatHtml(K.query("#test12").innerHTML, {div:[".color", ".font-weight"]}).toLowerCase(), '123
            test
            123'); + + equals(K.formatHtml(K.query("#test13").innerHTML), ' '); + equals(K.formatHtml(K.query("#test13").innerHTML, {input:["type", "value"]}), ' checkbox'); + equals(K.formatHtml(K.query("#test13").innerHTML, {input:["checked"],label:[]}), ' '); + equals(K.formatHtml(K.query("#test13").innerHTML, {}), 'checkbox'); + + equals(K.formatHtml(K.query("#test14").innerHTML, null, "relative"), ' test'); + + equals(K.formatHtml(K.query("#test16").innerHTML), 'test'); + equals(K.formatHtml(K.query("#test17").innerHTML), 'test'); + + equals(K.formatHtml(K.query("#test18").innerHTML), 'ddd'); + equals(K.formatHtml(K.query("#test19").innerHTML), 'ddd'); + equals(K.formatHtml(K.query("#test20").innerHTML).toLowerCase(), 'ddd'); + equals(K.formatHtml(K.query("#test21").innerHTML), 'ddd'); + + equals(K.formatHtml(K.query("#test22").innerHTML, {}), '©'); + + equals(K.formatHtml('123', {a:['href']}), '123'); + equals(K.formatHtml('123', {a:['*']}), '123'); + + equals(K.formatHtml('

            '), '


            '); + equals(K.formatHtml('

            \t\n
            \n

            '), '


            '); + +}); + + +test("getAttrList/getCssList", function() { + var tag = ''; + var attrList = K.getAttrList(tag); + equals(attrList.href, '#'); + equals(attrList.onclick, 'javascript:if(1<2)alert(1);'); + var cssList = K.getCssList(attrList.style); + equals(cssList['font-family'], '\'Arial Black\''); +}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/index.html b/php/kindeditor_demo/kindeditor/test/index.html new file mode 100755 index 0000000..e8cb8ac --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/index.html @@ -0,0 +1,11 @@ + + + + + KindEditor Test + + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/leak.html b/php/kindeditor_demo/kindeditor/test/leak.html new file mode 100755 index 0000000..c95f3ba --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/leak.html @@ -0,0 +1,39 @@ + + + + + KindEditor Memory Leak Test + + + + + + + + + + + + + 刷新 + 返回上一步 + + + diff --git a/php/kindeditor_demo/kindeditor/test/main.html b/php/kindeditor_demo/kindeditor/test/main.html new file mode 100755 index 0000000..eea92a1 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/main.html @@ -0,0 +1,369 @@ + + + + + KindEditor Main Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

            KindEditor Main Test

            + + + + + +
            + + diff --git a/php/kindeditor_demo/kindeditor/test/menu.html b/php/kindeditor_demo/kindeditor/test/menu.html new file mode 100755 index 0000000..95e5196 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/menu.html @@ -0,0 +1,33 @@ + + + + + KindEditor Menu Test + + + + + + + + + + + + + + + + + + + + + +

            KindEditor Menu Test

            + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/menu.js b/php/kindeditor_demo/kindeditor/test/menu.js new file mode 100755 index 0000000..f8d1de4 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/menu.js @@ -0,0 +1,72 @@ + +var menu = null; +K('#menu').bind('click', function(e) { + if (menu) { + menu.remove(); + menu = null; + } else { + var menuPos = K('#menu').pos(); + menu = K.menu({ + width : 200, + x : menuPos.x, + y : menuPos.y + K('#menu').height(), + z : 19811212, + centerLineMode : false + }); + K.each('9px,10px,12px,14px,16px,18px,24px,32px'.split(','), function(i, val) { + menu.addItem({ + title : '' + val + '', + click : function() { + alert(val); + }, + height : parseInt(val, 10) + 12, + checked : val === '12px' + }); + }); + } +}); + +var contextmenu = null; +K('#contextmenu').bind('click', function(e) { + if (contextmenu) { + contextmenu.remove(); + contextmenu = null; + } else { + var contextmenuPos = K('#contextmenu').pos(); + contextmenu = K.menu({ + width : 200, + x : contextmenuPos.x, + y : contextmenuPos.y + K('#contextmenu').height(), + z : 19811213 + }); + K.each('image,flash,media,-,bold,cut,copy,paste,-,selectall'.split(','), function(i, val) { + contextmenu.addItem({ + title : val, + click : function() { + alert(val); + }, + iconClass : 'ke-icon-' + val + }); + }); + } +}); + +var colorpicker = null; +K('#colorpicker').bind('click', function(e) { + if (colorpicker) { + colorpicker.remove(); + colorpicker = null; + } else { + var colorpickerPos = K('#colorpicker').pos(); + colorpicker = K.colorpicker({ + x : colorpickerPos.x, + y : colorpickerPos.y + K('#colorpicker').height(), + z : 19811214, + selectedColor : 'default', + noColor : '无颜色', + click : function(color) { + alert(color); + } + }); + } +}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/navi.html b/php/kindeditor_demo/kindeditor/test/navi.html new file mode 100755 index 0000000..c2e24cb --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/navi.html @@ -0,0 +1,36 @@ + + + + + KindEditor Test + + + + + + + \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/node.html b/php/kindeditor_demo/kindeditor/test/node.html new file mode 100755 index 0000000..9ae86eb --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/node.html @@ -0,0 +1,62 @@ + + + + + KindEditor Unittest + + + + + + + + + + + + + + + + +

            KindEditor Unittest

            +

            +
              + + +
              +

              +abcdefghijkxyz
              +0123456789
              +

              +
              div area
              +
              div area 2
              + +
              + + + + + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/node.js b/php/kindeditor_demo/kindeditor/test/node.js new file mode 100755 index 0000000..de7ec94 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/node.js @@ -0,0 +1,206 @@ +module('node'); + +test('K(html)', function(){ + var node = K('
              abc

              '); + equals(node.name, 'div'); + equals(node.length, 3); + equals(node.attr('class'), 'abc'); + equals(node.css('font-size'), '12px'); + equals(K('@p > strong').get().nodeValue, 'p > strong'); + equals(K('@1 2 ').get().nodeValue, '1 2 '); +}); + +test('K(selector)', function(){ + var node = K('p > strong'); + equals(node.name, 'strong'); + equals(node.get(1).nodeName.toLowerCase(), 'strong'); + equals(node.get(2).nodeName.toLowerCase(), 'strong'); + equals(node.length, 3); +}); + +test('K(node)', function(){ + var node = K(document.createTextNode('abc'), document.createElement('div')); + equals(node.name, '#text'); + equals(node.get(1).nodeName.toLowerCase(), 'div'); + equals(node.length, 2); +}); + +test('get', function() { + var div = K('div'); + ok(div.get(0) === div[0]); +}); + +test('eq', function() { + var div = K('div'); + ok(div.eq(0)[0] === div[0]); +}); + +test('attr/removeAttr', function() { + equals(K('#test-data-01').attr('src', 'aaa').attr('src'), 'aaa'); + equals(K('#test-data-02').attr('src', 'aaa').removeAttr('src').attr('src'), ''); + equals(K('#test-data-01').attr('id'), 'test-data-01'); + equals(K('#test-data-01').attr('class'), 'test-class'); + equals(K('#test-data-01 p img').attr('src'), './data/logo_180_30.gif'); + equals(K('#test-data-03 p span').attr('style'), 'color:red;'); + equals(K('#test-data-01 p img').attr('border'), '0'); + equals(K('#test-data-01').attr('class'), 'test-class'); + equals(K('
              ').attr('class', 'aaa').attr('class'), 'aaa'); + equals(K('
              ').removeAttr('class').attr('class'), ''); + equals(K('
              ').attr('style'), 'color:red;'); +}); + +test("hasClass/addClass/removeClass", function() { + var knode = K('
              '); + var div = knode.get(); + knode.addClass('aaa'); + ok(knode.hasClass('aaa')); + equals(div.className, 'aaa'); + knode.addClass('aaa'); + equals(div.className, 'aaa'); + knode.addClass('bbb'); + ok(knode.hasClass('bbb')); + equals(div.className, 'aaa bbb'); + knode.addClass('ccc'); + ok(knode.hasClass('ccc')); + equals(div.className, 'aaa bbb ccc'); + knode.removeClass('aaa'); + ok(!knode.hasClass('aaa')); + equals(div.className, 'bbb ccc'); + knode.removeClass('bbb'); + ok(!knode.hasClass('bbb')); + equals(div.className, 'ccc'); + knode.removeClass('ccc'); + ok(!knode.hasClass('ccc')); + equals(div.className, ''); + equals(K('
              ').addClass('aaa').removeClass('aaa').addClass('bbb').get().className, 'bbb'); +}); + +test("contains",function(){ + ok(K('#test-data-01 p').contains(K('#test-data-01 p')) === false); + ok(K('#test-data-01').contains(K('#test-data-01 p')) === true); + ok(K('#test-data-01 strong').contains(K('#test-data-01 strong').first()) === true); + ok(K(document).contains(K('#test-data-01 strong')) === true); + ok(K(document).contains(document) === false); + ok(K(document).contains(document.body)); + ok(K('#test-data-01 strong').first().contains(K('#test-data-01 strong')) === false); +}); + +test("val",function(){ + equals(K('').val(), "aa"); + equals(K('
              ').val(), "aa"); + equals(K('').val("bb").val(), "bb"); + equals(K('
              ').val("").val(), ""); + equals(K('').val('abc').val(), 'abc'); +}); + +test("css",function(){ + var node = K('
              '); + equals(node.css('width','300px').css('width'), '300px'); + equals(node.css('border','1px solid #ccc').css('border'),node.css('border')); + node = K('#test-data-01'); + equals(node.css('width'), '300px'); +}); + +test("width/height",function(){ + equals(K('#test-data-01').width(), 300); + ok(K('#test-data-01').height() > 110); +}); + +test("append",function(){ + var node = K('

              ').append('@abc'); + equals(node.html(), 'abc'); + equals(K(node[1]).html(), 'abc'); +}); + +test("before",function(){ + var parent = K('

              '); + K(document.body).append(parent); + K('.abc', parent).before('def'); + var children = parent.children(); + equals(children.length, 4); + equals(K(children[0]).name, 'span'); + equals(K(children[1]).name, 'div'); + equals(K(children[2]).name, 'span'); + equals(K(children[3]).name, 'p'); + parent.remove(); +}); + +test("after",function(){ + var parent = K('

              '); + K(document.body).append(parent); + K('.abc', parent).after('def'); + var children = parent.children(); + equals(children.length, 4); + equals(K(children[0]).name, 'div'); + equals(K(children[1]).name, 'span'); + equals(K(children[2]).name, 'p'); + equals(K(children[3]).name, 'span'); + parent.remove(); +}); + +test("replaceWith",function(){ + var node = K('
              ').replaceWith('

              '); + equals(node.length, 1); + equals(node.name, 'p'); +}); + +test("remove",function(){ + var node = K('

              123

              ').addClass('abc').html('test'); + node.remove(); + equals(node.length, 0); + // Test preserve child nodes. + var node = K('

              123456789

              '); + K('p', node).remove(true); + equals(node.html(), '123456789'); +}); + +test("html",function(){ + var node = K('
              xxx
              '); + K(document.body).append(node); + equals(node.html(), 'xxx'); + equals(node.html('bbb').html(), 'bbb'); + equals(K('').html('abc').html(), 'abc'); + equals(node.html('


              ').html(), '


              '); + equals(node.html('').html(), ''); + node.remove(); +}); + +test("outer",function(){ + var node = K('
              xxx
              '); + equals(node.outer(), '
              xxx
              '); + equals(node.addClass('aaa').outer(), '
              xxx
              '); +}); + +test("chidren",function(){ + var node = K('
              abc123
              '); + equals(node.children().length, 2); + equals(node.children().name, 'span'); + equals(K('
              ').children().length, 0); +}); + +test('show/hide',function(){ + var node = K('
              '); + equals(node.show().outer(), '
              '); + equals(node.hide().outer(), '
              '); + equals(node.show().outer(), '
              '); + + node = K('
              '); + equals(node.show().outer(), '
              '); + equals(node.hide().outer(), '
              '); + equals(node.show().outer(), '
              '); + + node = K('
              '); + equals(node.show().outer(), '
              '); + equals(node.hide().outer(), '
              '); + equals(node.show().outer(), '
              '); +}); + +test("data", function(){ + K(document).data('abc', '123'); + K('body').data('abc', '1234'); + K('body div').data('abc', '12345'); + + equals(K(document).data('abc'), '123'); + equals(K('body').data('abc'), '1234'); + equals(K('body div').data('abc'), '12345'); +}); diff --git a/php/kindeditor_demo/kindeditor/test/quirkmode.html b/php/kindeditor_demo/kindeditor/test/quirkmode.html new file mode 100755 index 0000000..3d7bc82 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/quirkmode.html @@ -0,0 +1,25 @@ + + + + + KindEditor Test + + +

              KindEditor Test

              +
              + +
              + + + + +
              + + diff --git a/php/kindeditor_demo/kindeditor/test/range.html b/php/kindeditor_demo/kindeditor/test/range.html new file mode 100755 index 0000000..abbef04 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/range.html @@ -0,0 +1,52 @@ + + + + + KindEditor Unittest + + + + + + + + + + + + + +

              KindEditor Unittest

              +

              +
                + + + + + + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/range.js b/php/kindeditor_demo/kindeditor/test/range.js new file mode 100755 index 0000000..3197aca --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/range.js @@ -0,0 +1,812 @@ +module('range'); + +test('range', function() { + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range, nativeRange; + range = K.range(document); + ok(range.startContainer === document); + ok(range.startOffset === 0); + ok(range.endContainer === document); + ok(range.endOffset === 0); + ok(range.collapsed === true); + ok(range.commonAncestor() === document); + + range = K.range(document); + range.selectNodeContents(strong); + nativeRange = range.get(); + var newRange = K.range(nativeRange); + same(range.toString(), newRange.toString()); +}); + +test('range.setStart', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setStart(strong.previousSibling, 3); + + ok(range.startContainer === strong.previousSibling); + ok(range.startOffset === 3); + ok(range.endContainer === strong.previousSibling); + ok(range.endOffset === 3); + ok(range.collapsed === true); + ok(range.commonAncestor() === strong.previousSibling); +}); + +test('range.setEnd', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setStart(strong.previousSibling, 3); + range.setEnd(p, 4); + + ok(range.startContainer === strong.previousSibling); + ok(range.startOffset === 3); + ok(range.endContainer === p); + ok(range.endOffset === 4); + ok(range.collapsed === false); + ok(range.commonAncestor() === p); +}); + +test('range.setStartBefore', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setStartBefore(strong); + + ok(range.startContainer === p); + ok(range.startOffset === 1); + ok(range.endContainer === p); + ok(range.endOffset === 1); + ok(range.collapsed === true); + ok(range.commonAncestor() === p); +}); + +test('range.setStartAfter', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setStartAfter(strong); + + ok(range.startContainer === p); + ok(range.startOffset === 2); + ok(range.endContainer === p); + ok(range.endOffset === 2); + ok(range.collapsed === true); + ok(range.commonAncestor() === p); +}); + +test('range.setEndBefore', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setEndBefore(strong); + ok(range.startContainer === p); + ok(range.startOffset === 1); + ok(range.endContainer === p); + ok(range.endOffset === 1); + ok(range.collapsed === true); + ok(range.commonAncestor() === p); +}); + +test('range.setEndAfter', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setStartAfter(strong); + range.setEndAfter(strong); + + ok(range.startContainer === p); + ok(range.startOffset === 2); + ok(range.endContainer === p); + ok(range.endOffset === 2); + ok(range.collapsed === true); + ok(range.commonAncestor() === p); +}); + +test('range.selectNode', function() { + expect(6); + + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.selectNode(strong); + ok(range.startContainer === p); + ok(range.startOffset === 1); + ok(range.endContainer === p); + ok(range.endOffset === 2); + ok(range.collapsed === false); + ok(range.commonAncestor() === p); +}); + +test('range.selectNodeContents', function() { + var range, strong, img, p; + //1 + strong = K.query('#test-data-01 strong'); + range = K.range(document); + range.selectNodeContents(strong); + ok(range.startContainer === strong); + ok(range.startOffset === 0); + ok(range.endContainer === strong); + ok(range.endOffset === 1); + ok(range.collapsed === false); + ok(range.commonAncestor() === strong); + //2 + img = K.query('#test-data-01 img'); + range = K.range(document); + range.selectNodeContents(img); + ok(range.startContainer === img.parentNode); + ok(range.startOffset === 3); + ok(range.endContainer === img.parentNode); + ok(range.endOffset === 4); + ok(range.collapsed === false); + ok(range.commonAncestor() === img.parentNode); + //3 + strong = K.query('#test-data-02 strong'); + range = K.range(document); + range.selectNodeContents(strong); + ok(range.startContainer === strong); + ok(range.startOffset === 0); + ok(range.endContainer === strong); + ok(range.endOffset === 0); + ok(range.collapsed === true); + ok(range.commonAncestor() === strong); + //4 + p = K.query('#test-data-02 p'); + range = K.range(document); + range.selectNodeContents(p); + ok(range.startContainer === p); + ok(range.endContainer === p); + ok(range.startOffset === 0); + ok(range.endOffset === 7); + ok(range.collapsed === false); + ok(range.commonAncestor() === p); +}); + +test('range.collapse', function() { + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + var range; + range = K.range(document); + range.setStart(p.childNodes[2], 0); + range.setEnd(p.childNodes[4], 2); + range.collapse(true); + ok(range.startContainer === range.endContainer); + ok(range.startOffset === range.endOffset); + ok(range.collapsed === true); + range = K.range(document); + range.setStart(p.childNodes[2], 0); + range.setEnd(p.childNodes[4], 2); + range.collapse(false); + ok(range.startContainer === range.endContainer); + ok(range.startOffset === range.endOffset); + ok(range.collapsed === true); +}); + +test('range.compareBoundaryPoints', function() { + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + var cmp, rangeA, rangeB; + //1 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.setStart(p.childNodes[0], 0); + rangeA.setEnd(p.childNodes[0], 2); + rangeB.setStart(p.childNodes[4], 0); + rangeB.setEnd(p.childNodes[4], 2); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //2 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.setStart(p.childNodes[0], 0); + rangeA.setEnd(p.childNodes[4], 3); + rangeB.setStart(p.childNodes[4], 0); + rangeB.setEnd(p.childNodes[4], 2); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //3 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.setStart(p.childNodes[0], 0); + rangeA.setEnd(p.childNodes[2], 3); + rangeB.setStart(p.childNodes[2], 0); + rangeB.setEnd(p.childNodes[4], 2); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //4 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.selectNode(strong); + rangeB.selectNode(p); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //5 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.setStart(p.childNodes[0], 0); + rangeA.setEnd(p.childNodes[0], 2); + rangeB.setStart(p.childNodes[0], 0); + rangeB.setEnd(p.childNodes[0], 2); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === 0); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === 0); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //6 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.selectNode(strong); + rangeB.selectNode(strong.firstChild); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //7 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.selectNode(strong.firstChild); + rangeB.setStart(strong.firstChild, 0); + rangeB.setEnd(strong.firstChild, 2); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //8 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.selectNode(p.childNodes[3]); + rangeB.selectNode(strong.firstChild); + rangeB.setEnd(strong.nextSibling, 4); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === 1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === 1); + //9 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.selectNode(strong.previousSibling); + rangeB.setStart(p, 1); + rangeB.setEnd(strong.firstChild, 3); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === 0); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //10 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.selectNode(strong.previousSibling); + rangeB.selectNode(strong.firstChild); + rangeB.setEnd(strong.nextSibling, 4); + cmp = rangeA.compareBoundaryPoints(K.START_TO_START, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_END, rangeB); + ok(cmp === -1); + cmp = rangeA.compareBoundaryPoints(K.END_TO_START, rangeB); + ok(cmp === -1); + //10 + rangeA = K.range(document); + rangeB = K.range(document); + rangeA.setStart(strong.previousSibling, 4); + rangeB.setStart(strong.firstChild, 0); + cmp = rangeA.compareBoundaryPoints(K.START_TO_END, rangeB); + ok(cmp === -1); +}); + +test('range.cloneRange', function() { + expect(6); + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + + var range = K.range(document); + range.setStart(p.childNodes[2], 0); + range.setEnd(p.childNodes[4], 2); + var cloneRange = range.cloneRange(); + ok(range.startContainer === cloneRange.startContainer); + ok(range.startOffset === cloneRange.startOffset); + ok(range.endContainer === cloneRange.endContainer); + ok(range.endOffset === cloneRange.endOffset); + ok(range.collapsed === cloneRange.collapsed); + ok(range.commonAncestor() === cloneRange.commonAncestor()); +}); + +test('range.toString', function() { + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + var range; + //1 + range = K.range(document); + range.selectNode(strong); + same(range.toString(), 'efg'); + //2 + range = K.range(document); + range.selectNode(strong); + range.setStart(strong.firstChild, 1); + same(range.toString(), 'fg'); + //3 + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.firstChild, 2); + same(range.toString(), 'f'); + //4 + range = K.range(document); + range.setStart(p.childNodes[0], 0); + range.setEnd(p.childNodes[4], 2); + same(range.toString(), 'abcdefghijkxy'); + //5 + range = K.range(document); + range.setStart(p.childNodes[4], 1); + range.setEnd(p.childNodes[4], 2); + same(range.toString(), 'y'); + //6 + range = K.range(document); + range.selectNode(p); + same(range.toString(), 'abcdefghijkxyz0123456789'); + //7 + range = K.range(document); + range.selectNode(strong.firstChild); + same(range.toString(), 'efg'); + //8 + range = K.range(document); + range.selectNode(strong); + same(range.toString(), 'efg'); + //9 + range = K.range(document); + same(range.toString(), ''); + //10 + range = K.range(document); + range.selectNode(document.body); + ok(range.toString().length > 100); +}); + +test('range.cloneContents', function() { + var p = K.query('#test-data-01 p'); + var strong = K.query('#test-data-01 strong'); + var range, frag; + //1 + range = K.range(document); + range.selectNode(strong); + frag = range.cloneContents(); + same(K(frag).outer().toLowerCase(), 'efg'); + ok(!range.collapsed); + //2 + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.firstChild, 2); + frag = range.cloneContents(); + same(K(frag).outer().toLowerCase(), 'f'); + //3 + range = K.range(document); + range.setStart(strong.firstChild, 0); + range.setEnd(strong.firstChild, 3); + frag = range.cloneContents(); + same(K(frag).outer().toLowerCase(), 'efg'); + //4 + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.nextSibling, 1); + frag = range.cloneContents(); + same(K(frag).outer().toLowerCase(), 'fgh'); + //5 + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.nextSibling, 0); + frag = range.cloneContents(); + same(K(frag).outer().toLowerCase(), 'fg'); + //6 + range = K.range(document); + range.setStart(p, 0); + range.setEnd(p, 4); + frag = range.cloneContents(); + ok(K(frag).children().length === 4); + //7 + range = K.range(document); + range.selectNode(strong.firstChild); + range.setEnd(strong.nextSibling, 4); + frag = range.cloneContents(); + same(K(frag).outer().toLowerCase(), 'efghijk'); + //8 + range = K.range(document); + range.setStart(strong.nextSibling, 4); + range.setEnd(p, 4); + frag = range.cloneContents(); + ok(K(frag).children().length === 1); + same(K(frag).first().name, 'img'); +}); + +test('range.extractContents', function() { + var p = K.query('#test-data-01 p'), + cloneP, strong, range, frag, div; + //1 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'efg'); + ok(range.collapsed); + document.body.removeChild(cloneP); + //2 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.firstChild, 2); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'f'); + document.body.removeChild(cloneP); + //3 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 0); + range.setEnd(strong.firstChild, 3); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'efg'); + document.body.removeChild(cloneP); + //4 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.nextSibling, 1); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'fgh'); + document.body.removeChild(cloneP); + //5 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.nextSibling, 0); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'fg'); + document.body.removeChild(cloneP); + //6 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(cloneP, 0); + range.setEnd(cloneP, 4); + frag = range.extractContents(); + ok(K(frag).children().length === 4); + document.body.removeChild(cloneP); + //7 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong.firstChild); + range.setEnd(strong.nextSibling, 4); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'efghijk'); + document.body.removeChild(cloneP); + //8 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(cloneP, 3); + range.setEnd(cloneP, 4); + frag = range.extractContents(); + ok(K(frag).children().length === 1); + same(K(frag).first().name, 'img'); + document.body.removeChild(cloneP); + //9 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(cloneP, 1); + range.setEnd(strong.firstChild, 3); + frag = range.extractContents(); + same(K(frag).outer().toLowerCase(), 'efg'); + document.body.removeChild(cloneP); + //10 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(cloneP, 0); + range.setEnd(strong.firstChild, 1); + frag = range.extractContents(); + same(K(frag).outer(), 'abcde'); + document.body.removeChild(cloneP); + //11 + div = K('
                efg
                '); + document.body.appendChild(div[0]); + range = K.range(document); + range.setStart(div[0], 1); + range.setEnd(div.last().first()[0], 1); + frag = range.extractContents(); + same(div.outer().toLowerCase(), '
                eg
                '); + same(K(frag).outer().toLowerCase(), 'f'); + document.body.removeChild(div[0]); + //12 + div = K('
                abcdefghijk
                '); + document.body.appendChild(div[0]); + range = K.range(document); + range.setStart(div[0], 2); + range.setEnd(div.children()[2], 1); + frag = range.extractContents(); + same(div.outer().toLowerCase(), '
                abcdhijk
                '); + same(K(frag).outer().toLowerCase(), 'efg'); + document.body.removeChild(div[0]); + //13 + div = K('
                abcdefghijk
                '); + document.body.appendChild(div[0]); + range = K.range(document); + range.setStart(div.children().eq(2).first()[0], 1); + range.setEnd(div[0], 4); + frag = range.extractContents(); + same(div.outer().toLowerCase(), '
                abcdefg
                '); + same(K(frag).outer().toLowerCase(), 'hijk'); + document.body.removeChild(div[0]); + //14 + div = K('
                \nabcd\n
                '); + document.body.appendChild(div[0]); + range = K.range(document); + range.setStart(div.first().next()[0], 1); + range.setEnd(div[0], 3); + frag = range.extractContents(); + same(div.html().toLowerCase(), 'abcd'); + same(K(frag).outer().toLowerCase(), ''); + document.body.removeChild(div[0]); +}); + +test('range.deleteContents', function() { + var p = K.query('#test-data-01 p'), + cloneP, strong, range, frag; + //1 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong); + frag = range.deleteContents(); + ok(range.collapsed); + ok(frag === range); + document.body.removeChild(cloneP); +}); + +test('range.insertNode', function() { + var p = K.query('#test-data-01 p'), + cloneP, strong, range, frag; + //1 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong); + range.insertNode(K('abc').get()); + same(range.toString(), 'abcefg'); + document.body.removeChild(cloneP); + //2 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong.firstChild); + range.insertNode(K('123').get()); + same(range.toString(), '123efg'); + document.body.removeChild(cloneP); + //3 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 0); + range.setEnd(strong.firstChild, 3); + range.insertNode(K('123').get()); + same(range.toString(), '123efg'); + document.body.removeChild(cloneP); + //4 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.firstChild, 2); + range.insertNode(K('123').get()); + same(range.toString(), '123f'); + document.body.removeChild(cloneP); + //5 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + var frag = document.createDocumentFragment(); + frag.appendChild(K('1').get()); + frag.appendChild(K('2').get()); + range = K.range(document); + range.selectNode(strong); + range.insertNode(frag); + same(range.toString(), '12efg'); + document.body.removeChild(cloneP); +}); + +test('range.surroundContents', function() { + var p = K.query('#test-data-01 p'), + cloneP, strong, range; + //1 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong); + range.surroundContents(K('').get()); + same(range.html(), 'efg'); + document.body.removeChild(cloneP); + //2 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.selectNode(strong.firstChild); + range.surroundContents(K('').get()); + same(range.html(), 'efg'); + document.body.removeChild(cloneP); + //3 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(strong.firstChild, 2); + range.surroundContents(K('').get()); + same(range.html(), 'f'); + document.body.removeChild(cloneP); + //4 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 0); + range.setEnd(strong.firstChild, 3); + range.surroundContents(K('').get()); + same(range.html(), 'efg'); + document.body.removeChild(cloneP); + //5 + cloneP = p.cloneNode(true); + document.body.appendChild(cloneP); + strong = K.query('strong', cloneP); + range = K.range(document); + range.setStart(strong.firstChild, 1); + range.setEnd(cloneP, 3); + range.surroundContents(K('').get()); + same(range.html(), 'fghijk'); + document.body.removeChild(cloneP); +}); + +test('range.enlarge', function() { + var div = K('
                '); + K(document.body.firstChild).before(div); + //1 + div.html('123abcdef'); + range = K.range(document); + range.setStart(div.first().first().first()[0], 0); + range.setEnd(div.first().first().next()[0], 3); + range.enlarge(); + same(range.html(), '123abc'); + div.html(''); +}); + +test('range.shrink', function() { + var div = K('
                '); + K(document.body.firstChild).before(div); + //1 + div.html('

                123abc

                '); + range = K.range(document); + range.setStart(div[0], 0); + range.setEnd(div[0], 1); + range.shrink(); + same(range.html(), '123abc'); + div.html(''); +}); + +test('range.moveToBookmark', function() { + var div = K('
                '); + K(document.body.firstChild).before(div); + //1 + div.html('

                123456789

                '); + range = K.range(document); + range.setStart(div.first().first()[0], 3); + range.setEnd(div.first().first().next()[0], 1); + var bookmark = range.createBookmark(); + range.moveToBookmark(bookmark); + same(range.html(), '45678'); + div.html(''); + //2 + div.html('

                123456789

                '); + range = K.range(document); + range.setStart(div.first()[0], 1); + range.setEnd(div.first().last()[0], 0); + var bookmark = range.createBookmark(true); + range.moveToBookmark(bookmark); + same(range.html(), '5678'); + div.html(''); +}); + +test('range.get', function() { + var div = K('
                '); + K(document.body.firstChild).before(div); + //1 + div.html('0123456789
                123
                '); + range = K.range(document); + range.setStart(div.first()[0], 7); + range.setEnd(div.first()[0], 8); // "7" + var nativeRange = range.get(); + newRange = K.range(nativeRange); + equals(range.html(), newRange.html()); + div.html(''); +}); \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/remote.html b/php/kindeditor_demo/kindeditor/test/remote.html new file mode 100755 index 0000000..d0c1638 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/remote.html @@ -0,0 +1,19 @@ + + + + + KindEditor Test + + + + +

                KindEditor Test

                + + + diff --git a/php/kindeditor_demo/kindeditor/test/selector.html b/php/kindeditor_demo/kindeditor/test/selector.html new file mode 100755 index 0000000..3815de9 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/selector.html @@ -0,0 +1,56 @@ + + + + + KindEditor Unittest + + + + + + + + + + + + +

                KindEditor Unittest

                +

                +
                  + + + + + + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/selector.js b/php/kindeditor_demo/kindeditor/test/selector.js new file mode 100755 index 0000000..e396e57 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/selector.js @@ -0,0 +1,55 @@ +module('selector'); + +test('query', function() { + var div = K.query('#test-data-01'); + var strong = K.query('#test-data-01 strong'); + + ok(K.query('p', div) === jQuery('p', div).get(0)); + ok(K.query('strong', strong) === null); + ok(K.query('strong', div) === jQuery('strong', div).get(0)); + ok(K.query('img[border]', div) === jQuery('img[border]', div).get(0)); + ok(K.query('img[alt]', div) === null); + ok(K.query('img[border="0"]', div) === jQuery('img[border="0"]', div).get(0)); + ok(K.query('img[border="1"]', div) === null); + ok(typeof K.query('img[src="\\.\\/data\\/logo_180_30\\.gif"]') === 'object'); // note: jquery has a bug + ok(K.query('.test-class') === jQuery('.test-class').get(0)); + ok(K.query('.test-class', document.body) === jQuery('.test-class').get(0)); + ok(K.query('[class="test-class"]') === jQuery('[class="test-class"]').get(0)); + ok(K.query('[id="test-data-01"]') === jQuery('[id="test-data-01"]').get(0)); + ok(K.query('img.test-class') === null); + ok(K.query('img#test-data-01') === null); + ok(K.query('div#escaped-id\\:\\.') === jQuery('div#escaped-id\\:\\.').get(0)); + ok(K.query('input[name="escaped-name\\:\\."]') === jQuery('input[name="escaped-name\\:\\."]').get(0)); + ok(K.query('input[name="escaped-name\\:\\."]', div) === jQuery('input[name="escaped-name\\:\\."]').get(0)); + ok(K.query('img[border="0"]', div) === jQuery('img[border="0"]', div).get(0)); + ok(K.query('img[border]', div) === jQuery('img[border]', div).get(0)); + ok(K.query('.test-class') === jQuery('.test-class').get(0)); + ok(K.query('img #test-data-01') === null); + ok(K.query('body #test-data-01') === jQuery('body #test-data-01').get(0)); + + ok(K.query('div#test-data-01 strong') === jQuery('div#test-data-01 strong').get(0)); + ok(K.query('div#test-data-01 p strong') === jQuery('div#test-data-01 p strong').get(0)); + ok(K.query('div#test-data-01 > p > strong') === jQuery('div#test-data-01 > p > strong').get(0)); + ok(K.query('div#test-data-01>p>strong') === jQuery('div#test-data-01>p>strong').get(0)); + ok(K.query('div#test-data-01 > p > img[border="0"]') === jQuery('div#test-data-01 > p > img[border="0"]').get(0)); + ok(K.query('div#test-data-01 > strong', document, false) === null); +}); + +test('queryAll', function() { + var div = K.query('#test-data-01'); + var strong = K.query('#test-data-01 strong'); + + ok(K.queryAll('*').length === jQuery('*').length); + ok(K.queryAll('div').length === jQuery('div').length); + ok(K.queryAll('.test-class').length === jQuery('.test-class').length); + ok(K.queryAll('*', div).length === jQuery('*', div).length); + ok(K.queryAll('[border]', div).length === jQuery('[border]', div).length); + ok(K.queryAll('[border="0"]', div).length === jQuery('[border="0"]', div).length); + ok(K.queryAll('[border="1"]', div).length === jQuery('[border="1"]', div).length); + ok(K.queryAll('div', div).length === jQuery('div', div).length); + ok(K.queryAll('p *', div).length === jQuery('p *', div).length); + ok(K.queryAll('strong', div).length === jQuery('strong', div).length); + ok(K.queryAll('strong', strong).length === jQuery('strong', strong).length); + ok(K.queryAll('div p').length === jQuery('div p').length); + ok(K.queryAll('div,.test-class').length === jQuery('div,test-class').length); +}); diff --git a/php/kindeditor_demo/kindeditor/test/tabs.html b/php/kindeditor_demo/kindeditor/test/tabs.html new file mode 100755 index 0000000..60455df --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/tabs.html @@ -0,0 +1,49 @@ + + + + + KindEditor Tabs Test + + + + + + + + + + + + + + + + +

                  KindEditor Tabs Test

                  +
                  +
                  内容1
                  +
                  内容2
                  +
                  内容3
                  + + + diff --git a/php/kindeditor_demo/kindeditor/test/toolbar.html b/php/kindeditor_demo/kindeditor/test/toolbar.html new file mode 100755 index 0000000..0383b9b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/toolbar.html @@ -0,0 +1,34 @@ + + + + + KindEditor Toolbar Test + + + + + + + + + + + + + + + + + +

                  KindEditor Toolbar Test

                  +
                  +
                  +
                  + + + + + + + + diff --git a/php/kindeditor_demo/kindeditor/test/toolbar.js b/php/kindeditor_demo/kindeditor/test/toolbar.js new file mode 100755 index 0000000..829e9b7 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/toolbar.js @@ -0,0 +1,60 @@ + +var items = [ + 'source', '|', 'fullscreen', 'undo', 'redo', 'print', 'cut', 'copy', 'paste', + 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright', + 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript', + 'superscript', '|', 'selectall', '/', + 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', + 'italic', 'underline', 'strikethrough', 'removeformat', '|', 'image', + 'flash', 'media', 'table', 'hr', 'emoticons', 'link', 'unlink', '|', 'about' +]; +var list = []; +K.each(items, function(i, name) { + if (name == '|') { + list.push(''); + } else if (name == '/') { + list.push('
                  '); + } else { + list.push(''); + list.push(''); + } +}); + +var toolbar = K.toolbar({ + src : 'div#toolbar', + width : '100%', + html : list.join(''), + click : function(e, name) { + alert(name); + } +}); + +K('#enable').bind('click', function(e) { + if (toolbar) { + toolbar.disableAll(false); + } +}); + +K('#disable').bind('click', function(e) { + if (toolbar) { + toolbar.disableAll(true); + } +}); + +K('#toggle').bind('click', function(e) { + if (toolbar) { + toolbar.disableAll(); + } +}); + +K('#select').bind('click', function(e) { + if (toolbar) { + toolbar.select('bold'); + } +}); + +K('#unselect').bind('click', function(e) { + if (toolbar) { + toolbar.unselect('bold'); + } +}); diff --git a/php/kindeditor_demo/kindeditor/test/total.html b/php/kindeditor_demo/kindeditor/test/total.html new file mode 100755 index 0000000..b79daeb --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/total.html @@ -0,0 +1,58 @@ + + + + + + KindEditor Test + + +

                  KindEditor Test

                  +
                  + +
                  + +
                  + +
                  + +
                  + +
                  + + + + + + + + + + +
                  + + diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/KindEditorDriver.php b/php/kindeditor_demo/kindeditor/test/webdriver/KindEditorDriver.php new file mode 100755 index 0000000..557d84c --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/KindEditorDriver.php @@ -0,0 +1,151 @@ +webDriver = new WebDriver($serverUrl); + $this->session = $this->webDriver->session($browser); + if ($url !== '') { + $this->open($url); + } + } + + public function open($url) { + if (strpos($url, 'http://') !== 0) { + $url = $this->baseUrl . $url; + } + $this->session->open($url); + return $this; + } + + public function selector($selector, $index = 0) { + $endTime = time() + $this->timeout; + while (true) { + try { + if ($index > 0) { + $elements = $this->session->elements('css selector', $selector); + $this->element = $elements[$index]; + } else { + $this->element = $this->session->element('css selector', $selector); + } + return $this; + } catch (NoSuchElementWebDriverError $e) { + } + sleep(1); + if (time() > $endTime) { + break; + } + } + throw new TimeOutWebDriverError('The element could not be found', ''); + } + + public function value($val) { + $this->element->value(array('value' => strSplitUnicode($val))); + return $this; + } + + public function keys($val) { + $this->session->keys(array('value' => strSplitUnicode($val))); + return $this; + } + + public function click() { + $this->element->click(''); + return $this; + } + + public function mouseover() { + $this->session->moveto(array('element' => $this->element->getID())); + return $this; + } + + public function script($script) { + return $this->session->execute(array( + 'script' => $script, + 'args' => array(), + )); + } + + public function clickToolbar($name) { + $this->session->frame(array('id' => null)); + return $this->selector('.ke-icon-' . $name)->click(); + } + + // get or set editor content + public function html($val = null) { + $this->session->frame(array('id' => null)); + if ($val === null) { + return preg_replace('/[\r\n\t]/', '', $this->script("return editor.html();")); + } + $this->script("editor.html('$val');"); + return $this; + } + + // input editor content + public function input($val) { + $id = 'ke-edit-iframe'; + $this->script("KindEditor('.ke-edit-iframe').eq(0).attr('id', '$id');"); + $this->selector("#$id"); + $this->session->frame(array('id' => $id)); + $this->keys($val); + return $this; + } + + // drag element + public function drag($x, $y) { + //$id = 'document-body'; + //$this->script("KindEditor('body').attr('id', '$id');"); + + $this->mouseover(); + $this->session->buttondown(""); + $this->session->moveto(array( + //'element' => $id, + 'xoffset' => $x, + 'yoffset' => $y, + )); + $this->session->buttonup(""); + return $this; + } + + public function close() { + $this->session->close(); + return $this; + } + +} + +function strSplitUnicode($str, $l = 1) { + if ($l > 0) { + $ret = array(); + $len = mb_strlen($str, "UTF-8"); + for ($i = 0; $i < $len; $i += $l) { + $ret[] = mb_substr($str, $i, $l, "UTF-8"); + } + return $ret; + } + return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY); +} + +function equals($a, $b) { + if ($a === $b) { + echo "[OK] \"$a\"\n"; + } else { + echo "[FAILED]\n"; + echo "Expected: \"$b\"\n"; + echo "Result: \"$a\"\n"; + } +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/all-chrome.bat b/php/kindeditor_demo/kindeditor/test/webdriver/all-chrome.bat new file mode 100755 index 0000000..81febc4 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/all-chrome.bat @@ -0,0 +1,2 @@ +php all.php --browser=chrome +pause \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/all-firefox.bat b/php/kindeditor_demo/kindeditor/test/webdriver/all-firefox.bat new file mode 100755 index 0000000..12e4e22 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/all-firefox.bat @@ -0,0 +1,2 @@ +php all.php --browser=firefox +pause \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/all-ie.bat b/php/kindeditor_demo/kindeditor/test/webdriver/all-ie.bat new file mode 100755 index 0000000..ada464b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/all-ie.bat @@ -0,0 +1,2 @@ +php all.php --browser="internet explorer" +pause \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/all.php b/php/kindeditor_demo/kindeditor/test/webdriver/all.php new file mode 100755 index 0000000..c702a18 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/all.php @@ -0,0 +1,27 @@ +session('firefox'); + +* See also [wiki page for launching different browsers](https://github.com/facebook/php-webdriver/wiki/Launching-Browsers). + +## SIMPLE EXAMPLES + +### Note that all of these match the Protocol exactly +* Move to a specific spot on the screen + + // POST /session/:sessionId/moveto + $session->moveto(array('xoffset' => 3, 'yoffset' => 300)); + +* Get the current url + + // GET /session/:sessionId/url + $session->url(); + +* Change focus to another frame + + // POST /session/:sessionId/frame + $session->frame(array('id' => 'some_frame_id')); + +* Get a list of window handles for all open windows + + // GET /session/:sessionId/window_handles + $session->window_handles(); + +* Accept the currently displayed alert dialog + + // POST /session/:sessionId/accept_alert + $session->accept_alert(); + +* Change asynchronous script timeout + + // POST /session/:sessionId/timeouts/async_script + $session->timeouts()->async_script(array('ms' => 2000)); + +* Doubleclick an element on a touch screen + + // POST session/:sessionId/touch/doubleclick + $session->touch()->doubleclick(array('element' => $element->getID()) + +* Check if two elements are equal + + // GET /session/:sessionId/element/:id/equals/:other + $element->equals($other_element->getID())) + +* Get value of a css property on element + + // GET /session/:sessionId/element/:id/css/:propertyName + $element->css($property_name) + +## 'GET', 'POST', or 'DELETE' to the same command examples + +### When you can do multiple http methods for the same command, call the command directly for the 'GET', and prepend the http method for the 'POST' or 'DELETE'. + +* Set landscape orientation with 'POST' + + // POST /session/:sessionId/orientation + $session->postOrientation(array('orientation' => 'LANDSCAPE')); + +* Get landscape orientation with normal 'GET' + + // GET /session/:sessionId/orientation + $session->orientation(); + +* Set size of window that has $window_handle with 'POST' + + // If excluded, $window_handle defaults to 'current' + // POST /session/:sessionId/window/:windowHandle/size + $session + ->window($window_handle) + ->postSize(array('width' => 10, 'height' => 10)); + +* Get current window size with 'GET' + + // GET /session/:sessionId/window/:windowHandle/size + $session->window()->size(); + +## Some unavoidable exceptions to direct protocol translation. + +* Opening pages + + // POST /session/:sessionId/url + $session->open('http://www.facebook.com'); + +* Dealing with the session + + // DELETE /session/:sessionId + $session->close(); + + // GET /session/:sessionId + $session->capabilities(); + +* To find elements + + // POST /session/:sessionId/element + $element = $session->element($using, $value); + + // POST /session/:sessionId/elements + $session->elements($using, $value); + + // POST /session/:sessionId/element/:id/element + $element->element($using, $value); + + // POST /session/:sessionId/element/:id/elements + $element->elements($using, $value); + +* To get the active element + + // POST /session/:sessionId/element/active + $session->activeElement(); + +* To manipulate cookies + + // GET /session/:sessionId/cookie + $session->getAllCookies(); + + // POST /session/:sessionId/cookie + $session->setCookie($cookie_json); + + // DELETE /session/:sessionId/cookie + $session->deleteAllCookies() + + // DELETE /session/:sessionId/cookie/:name + $session->deleteCookie($name) + +* To manipulate windows + + // POST /session/:sessionId/window + $session->focusWindow($window_handle); + + // DELETE /session/:sessionId/window + $session->deleteWindow(); + +### See also [wiki page of examples](https://github.com/facebook/php-webdriver/wiki/Example-command-reference). \ No newline at end of file diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriver.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriver.php new file mode 100755 index 0000000..a2dbbc2 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriver.php @@ -0,0 +1,49 @@ + 'GET', + ); + } + + public function session( + $browser = 'firefox', + $additional_capabilities = array()) { + + $desired_capabilities = array_merge( + $additional_capabilities, + array('browserName' => $browser)); + + $results = $this->curl( + 'POST', + '/session', + array('desiredCapabilities' => $desired_capabilities), + array(CURLOPT_FOLLOWLOCATION => true)); + + return new WebDriverSession($results['info']['url']); + } + + public function sessions() { + $result = $this->curl('GET', '/sessions'); + $sessions = array(); + foreach ($result['value'] as $session) { + $sessions[] = new WebDriverSession( + $this->url . '/session/' . $session['id']); + } + return $sessions; + } +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverBase.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverBase.php new file mode 100755 index 0000000..6d17fc5 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverBase.php @@ -0,0 +1,236 @@ +url = $url; + } + public function __toString() { + return $this->url; + } + + public function getURL() { + return $this->url; + } + + /** + * Curl request to webdriver server. + * + * $http_method 'GET', 'POST', or 'DELETE' + * $command If not defined in methods() this function will throw. + * $params If an array(), they will be posted as JSON parameters + * If a number or string, "/$params" is appended to url + * $extra_opts key=>value pairs of curl options to pass to curl_setopt() + */ + protected function curl( + $http_method, + $command, + $params = null, + $extra_opts = array()) { + + if ($params && is_array($params) && $http_method !== 'POST') { + throw new Exception(sprintf( + 'The http method called for %s is %s but it has to be POST' . + ' if you want to pass the JSON params %s', + $command, + $http_method, + json_encode($params))); + } + + $url = sprintf('%s%s', $this->url, $command); + if ($params && (is_int($params) || is_string($params))) { + $url .= '/' . $params; + } + + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt( + $curl, + CURLOPT_HTTPHEADER, + array( + 'Content-Type: application/json;charset=UTF-8', + 'Accept: application/json')); + + if ($http_method === 'POST') { + curl_setopt($curl, CURLOPT_POST, true); + if ($params && is_array($params)) { + curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params)); + } + } else if ($http_method == 'DELETE') { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); + } + + foreach ($extra_opts as $option => $value) { + curl_setopt($curl, $option, $value); + } + + $raw_results = trim(WebDriverEnvironment::CurlExec($curl)); + $info = curl_getinfo($curl); + + if ($error = curl_error($curl)) { + $msg = sprintf( + 'Curl error thrown for http %s to %s', + $http_method, + $url); + if ($params && is_array($params)) { + $msg .= sprintf(' with params: %s', json_encode($params)); + } + throw new WebDriverCurlException($msg . "\n\n" . $error); + } + curl_close($curl); + + $results = json_decode($raw_results, true); + + $value = null; + if (is_array($results) && array_key_exists('value', $results)) { + $value = $results['value']; + } + + $message = null; + if (is_array($value) && array_key_exists('message', $value)) { + $message = $value['message']; + } + + self::throwException($results['status'], $message, $results); + + return array('value' => $value, 'info' => $info); + } + + public function __call($name, $arguments) { + if (count($arguments) > 1) { + throw new Exception( + 'Commands should have at most only one parameter,' . + ' which should be the JSON Parameter object'); + } + + if (preg_match('/^(get|post|delete)/', $name, $matches)) { + $http_method = strtoupper($matches[0]); + $webdriver_command = strtolower(substr($name, strlen($http_method))); + $default_http_method = $this->getHTTPMethod($webdriver_command); + if ($http_method === $default_http_method) { + throw new Exception(sprintf( + '%s is the default http method for %s. Please just call %s().', + $http_method, + $webdriver_command, + $webdriver_command)); + } + $methods = $this->methods(); + if (!in_array($http_method, $methods[$webdriver_command])) { + throw new Exception(sprintf( + '%s is not an available http method for the command %s.', + $http_method, + $webdriver_command)); + } + } else { + $webdriver_command = $name; + $http_method = $this->getHTTPMethod($webdriver_command); + } + + $results = $this->curl( + $http_method, + '/' . $webdriver_command, + array_shift($arguments)); + + return $results['value']; + } + + private function getHTTPMethod($webdriver_command) { + if (!array_key_exists($webdriver_command, $this->methods())) { + throw new Exception(sprintf( + '%s is not a valid webdriver command.', + $webdriver_command)); + } + + $methods = $this->methods(); + $http_methods = (array) $methods[$webdriver_command]; + return array_shift($http_methods); + } +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverContainer.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverContainer.php new file mode 100755 index 0000000..9787ae7 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverContainer.php @@ -0,0 +1,60 @@ +curl( + 'POST', + '/element', + array( + 'using' => $using, + 'value' => $value)); + } catch (NoSuchElementWebDriverError $e) { + throw new NoSuchElementWebDriverError( + sprintf( + 'Element not found with %s, %s', + $using, + $value) . "\n\n" . $e->getMessage(), + $e->getResults()); + } + + return $this->webDriverElement($results['value']); + } + + public function elements($using, $value) { + $results = $this->curl( + 'POST', + '/elements', + array( + 'using' => $using, + 'value' => $value + )); + + return array_filter(array_map( + array($this, 'webDriverElement'), $results['value'])); + } + + protected function webDriverElement($value) { + return array_key_exists('ELEMENT', (array) $value) ? + new WebDriverElement( + $this->getElementPath($value['ELEMENT']), // url + $value['ELEMENT']) : // id + null; + } + + + abstract protected function getElementPath($element_id); +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverElement.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverElement.php new file mode 100755 index 0000000..2b806e4 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverElement.php @@ -0,0 +1,50 @@ + 'POST', + 'submit' => 'POST', + 'text' => 'GET', + 'value' => 'POST', + 'name' => 'GET', + 'clear' => 'POST', + 'selected' => 'GET', + 'enabled' => 'GET', + 'attribute' => 'GET', + 'equals' => 'GET', + 'displayed' => 'GET', + 'location' => 'GET', + 'location_in_view' => 'GET', + 'size' => 'GET', + 'css' => 'GET', + ); + } + + private $id; + public function __construct($url, $id) { + $this->id = $id; + parent::__construct($url); + } + + public function getID() { + return $this->id; + } + + protected function getElementPath($element_id) { + return preg_replace(sprintf('/%s$/', $this->id), $element_id, $this->url); + } +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverEnvironment.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverEnvironment.php new file mode 100755 index 0000000..71d393b --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverEnvironment.php @@ -0,0 +1,25 @@ +results = $results; + } + + public function getResults() { + return $this->results; + } +} + +class IndexOutOfBoundsWebDriverError extends WebDriverException {} // 1 +class NoCollectionWebDriverError extends WebDriverException {} // 2 +class NoStringWebDriverError extends WebDriverException {} // 3 +class NoStringLengthWebDriverError extends WebDriverException {} // 4 +class NoStringWrapperWebDriverError extends WebDriverException {} // 5 +class NoSuchDriverWebDriverError extends WebDriverException {} // 6 +class NoSuchElementWebDriverError extends WebDriverException {} // 7 +class NoSuchFrameWebDriverError extends WebDriverException {} // 8 +class UnknownCommandWebDriverError extends WebDriverException {} // 9 +class ObsoleteElementWebDriverError extends WebDriverException {} // 10 +class ElementNotDisplayedWebDriverError extends WebDriverException {} // 11 +class InvalidElementStateWebDriverError extends WebDriverException {} // 12 +class UnhandledWebDriverError extends WebDriverException {} // 13 +class ExpectedWebDriverError extends WebDriverException {} // 14 +class ElementNotSelectableWebDriverError extends WebDriverException {} // 15 +class NoSuchDocumentWebDriverError extends WebDriverException {} // 16 +class UnexpectedJavascriptWebDriverError extends WebDriverException {} // 17 +class NoScriptResultWebDriverError extends WebDriverException {} // 18 +class XPathLookupWebDriverError extends WebDriverException {} // 19 +class NoSuchCollectionWebDriverError extends WebDriverException {} // 20 +class TimeOutWebDriverError extends WebDriverException {} // 21 +class NullPointerWebDriverError extends WebDriverException {} // 22 +class NoSuchWindowWebDriverError extends WebDriverException {} // 23 +class InvalidCookieDomainWebDriverError extends WebDriverException {} // 24 +class UnableToSetCookieWebDriverError extends WebDriverException {} // 25 +class UnexpectedAlertOpenWebDriverError extends WebDriverException {} // 26 +class NoAlertOpenWebDriverError extends WebDriverException {} // 27 +class ScriptTimeoutWebDriverError extends WebDriverException {} // 28 +class InvalidElementCoordinatesWebDriverError extends WebDriverException {}// 29 +class IMENotAvailableWebDriverError extends WebDriverException {} // 30 +class IMEEngineActivationFailedWebDriverError extends WebDriverException {}// 31 +class InvalidSelectorWebDriverError extends WebDriverException {} // 32 diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverSession.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverSession.php new file mode 100755 index 0000000..5679b78 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverSession.php @@ -0,0 +1,148 @@ + 'GET', // for POST, use open($url) + 'forward' => 'POST', + 'back' => 'POST', + 'refresh' => 'POST', + 'execute' => 'POST', + 'execute_async' => 'POST', + 'screenshot' => 'GET', + 'window_handle' => 'GET', + 'window_handles' => 'GET', + 'frame' => 'POST', + 'source' => 'GET', + 'title' => 'GET', + 'keys' => 'POST', + 'orientation' => array('GET', 'POST'), + 'alert_text' => array('GET', 'POST'), + 'accept_alert' => 'POST', + 'dismiss_alert' => 'POST', + 'moveto' => 'POST', + 'click' => 'POST', + 'buttondown' => 'POST', + 'buttonup' => 'POST', + 'doubleclick' => 'POST', + ); + } + + // /session/:sessionId/url (POST) + public function open($url) { + $this->curl('POST', '/url', array('url' => $url)); + return $this; + } + + // /session/:sessionId (GET) + public function capabilities() { + $result = $this->curl('GET', ''); + return $result['value']; + } + + // /session/:sessionId (DELETE) + public function close() { + $result = $this->curl('DELETE', ''); + return $result['value']; + } + + // /session/:sessionId/cookie (GET) + public function getAllCookies() { + $result = $this->curl('GET', '/cookie'); + return $result['value']; + } + + // /session/:sessionId/cookie (POST) + public function setCookie($cookie_json) { + $this->curl('POST', '/cookie', array('cookie' => $cookie_json)); + return $this; + } + + // /session/:sessionId/cookie (DELETE) + public function deleteAllCookies() { + $this->curl('DELETE', '/cookie'); + return $this; + } + + // /session/:sessionId/cookie/:name (DELETE) + public function deleteCookie($cookie_name) { + $this->curl('DELETE', '/cookie/' . $cookie_name); + return $this; + } + + public function timeouts() { + $item = new WebDriverSimpleItem($this->url . '/timeouts'); + return $item->setMethods(array( + 'async_script' => 'POST', + 'implicit_wait' => 'POST', + )); + } + + public function ime() { + $item = new WebDriverSimpleItem($this->url . '/ime'); + return $item->setMethods(array( + 'available_engines' => 'GET', + 'active_engine' => 'GET', + 'activated' => 'GET', + 'deactivate' => 'POST', + 'activate' => 'POST', + )); + } + + // /session/:sessionId/window (DELETE) + public function deleteWindow() { + $this->curl('DELETE', '/window'); + return $this; + } + + // /session/:sessionId/window (POST) + public function focusWindow($name) { + $this->curl('POST', '/window', array('name' => $name)); + return $this; + } + + public function window($window_handle = 'current') { + $item = new WebDriverSimpleItem($this->url . '/window/' . $window_handle); + return $item->setMethods(array( + 'size' => array('GET', 'POST'), + 'position' => array('GET', 'POST'), + )); + } + + // /session/:sessionId/element/active (POST) + public function activeElement() { + $results = $this->curl('POST', '/element/active'); + return $this->webDriverElement($results['value']); + } + + public function touch() { + $item = new WebDriverSimpleItem($this->url . '/touch'); + return $item->setMethods(array( + 'click' => 'POST', + 'down' => 'POST', + 'up' => 'POST', + 'move' => 'POST', + 'scroll' => 'POST', + 'doubleclick' => 'POST', + 'longclick' => 'POST', + 'flick' => 'POST', + )); + } + + protected function getElementPath($element_id) { + return sprintf('%s/element/%s', $this->url, $element_id); + } +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverSimpleItem.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverSimpleItem.php new file mode 100755 index 0000000..f675c45 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/WebDriverSimpleItem.php @@ -0,0 +1,26 @@ +_methods; + } + + public function setMethods($methods) { + $this->_methods = $methods; + return $this; + } +} diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/__init__.php b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/__init__.php new file mode 100755 index 0000000..d2d4aa9 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/php-webdriver/__init__.php @@ -0,0 +1,23 @@ +html(''); +// bold +$driver->clickToolbar('bold'); +$driver->input('abc'); +equals($driver->html(), 'abc'); +// fontsize +$driver->clickToolbar('fontsize'); +$driver->selector('.ke-menu-item', 6)->mouseover()->click(); +$driver->input('abc'); +equals($driver->html(), 'abcabc'); +// removeformat +$driver->clickToolbar('removeformat'); +$driver->input('123'); +equals($driver->html(), 'abcabc123'); + +$driver->close(); diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/test-dialog.php b/php/kindeditor_demo/kindeditor/test/webdriver/test-dialog.php new file mode 100755 index 0000000..5912d14 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/test-dialog.php @@ -0,0 +1,17 @@ +script("return KindEditor('.ke-dialog').css('top')")); +$prevLeft = intval($driver->script("return KindEditor('.ke-dialog').css('left')")); +$driver->selector('.ke-dialog-header')->drag(100, 200); +equals(intval($driver->script("return KindEditor('.ke-dialog').css('top')")), $prevTop + 200); +equals(intval($driver->script("return KindEditor('.ke-dialog').css('left')")), $prevLeft + 100); + +// close dialog +$driver->selector('.ke-dialog-icon-close')->click(); + +$driver->close(); diff --git a/php/kindeditor_demo/kindeditor/test/webdriver/test-unittest.php b/php/kindeditor_demo/kindeditor/test/webdriver/test-unittest.php new file mode 100755 index 0000000..08982bf --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/webdriver/test-unittest.php @@ -0,0 +1,23 @@ +open($file); + equals($driver->selector('.failed')->element->text(), '0'); +} + +$driver->close(); diff --git a/php/kindeditor_demo/kindeditor/test/widget.html b/php/kindeditor_demo/kindeditor/test/widget.html new file mode 100755 index 0000000..6896ef3 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/test/widget.html @@ -0,0 +1,64 @@ + + + + + KindEditor Widget Test + + + + + + + + + + + + + + + + + +

                  KindEditor Widget Test

                  + + +
                  +
                  + + + + diff --git a/php/kindeditor_demo/kindeditor/themes/common/anchor.gif b/php/kindeditor_demo/kindeditor/themes/common/anchor.gif new file mode 100755 index 0000000..61145ea Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/common/anchor.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/common/blank.gif b/php/kindeditor_demo/kindeditor/themes/common/blank.gif new file mode 100755 index 0000000..5bfd67a Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/common/blank.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/common/flash.gif b/php/kindeditor_demo/kindeditor/themes/common/flash.gif new file mode 100755 index 0000000..2cb12b2 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/common/flash.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/common/loading.gif b/php/kindeditor_demo/kindeditor/themes/common/loading.gif new file mode 100755 index 0000000..c69e937 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/common/loading.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/common/media.gif b/php/kindeditor_demo/kindeditor/themes/common/media.gif new file mode 100755 index 0000000..e1c0e30 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/common/media.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/common/rm.gif b/php/kindeditor_demo/kindeditor/themes/common/rm.gif new file mode 100755 index 0000000..d013d55 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/common/rm.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/default/background.png b/php/kindeditor_demo/kindeditor/themes/default/background.png new file mode 100755 index 0000000..e59bd68 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/default/background.png differ diff --git a/php/kindeditor_demo/kindeditor/themes/default/default.css b/php/kindeditor_demo/kindeditor/themes/default/default.css new file mode 100755 index 0000000..3f72660 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/themes/default/default.css @@ -0,0 +1,1147 @@ +/* common */ +.ke-inline-block { + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; +} +.ke-clearfix { + zoom: 1; +} +.ke-clearfix:after { + content: "."; + display: block; + clear: both; + font-size: 0; + height: 0; + line-height: 0; + visibility: hidden; +} +.ke-shadow { + box-shadow: 1px 1px 3px #A0A0A0; + -moz-box-shadow: 1px 1px 3px #A0A0A0; + -webkit-box-shadow: 1px 1px 3px #A0A0A0; + filter: progid:DXImageTransform.Microsoft.Shadow(color='#A0A0A0', Direction=135, Strength=3); + background-color: #F0F0EE; +} +.ke-menu a, +.ke-menu a:hover, +.ke-dialog a, +.ke-dialog a:hover { + color: #337FE5; + text-decoration: none; +} +/* icons */ +.ke-icon-source { + background-position: 0px 0px; + width: 16px; + height: 16px; +} +.ke-icon-preview { + background-position: 0px -16px; + width: 16px; + height: 16px; +} +.ke-icon-print { + background-position: 0px -32px; + width: 16px; + height: 16px; +} +.ke-icon-undo { + background-position: 0px -48px; + width: 16px; + height: 16px; +} +.ke-icon-redo { + background-position: 0px -64px; + width: 16px; + height: 16px; +} +.ke-icon-cut { + background-position: 0px -80px; + width: 16px; + height: 16px; +} +.ke-icon-copy { + background-position: 0px -96px; + width: 16px; + height: 16px; +} +.ke-icon-paste { + background-position: 0px -112px; + width: 16px; + height: 16px; +} +.ke-icon-selectall { + background-position: 0px -128px; + width: 16px; + height: 16px; +} +.ke-icon-justifyleft { + background-position: 0px -144px; + width: 16px; + height: 16px; +} +.ke-icon-justifycenter { + background-position: 0px -160px; + width: 16px; + height: 16px; +} +.ke-icon-justifyright { + background-position: 0px -176px; + width: 16px; + height: 16px; +} +.ke-icon-justifyfull { + background-position: 0px -192px; + width: 16px; + height: 16px; +} +.ke-icon-insertorderedlist { + background-position: 0px -208px; + width: 16px; + height: 16px; +} +.ke-icon-insertunorderedlist { + background-position: 0px -224px; + width: 16px; + height: 16px; +} +.ke-icon-indent { + background-position: 0px -240px; + width: 16px; + height: 16px; +} +.ke-icon-outdent { + background-position: 0px -256px; + width: 16px; + height: 16px; +} +.ke-icon-subscript { + background-position: 0px -272px; + width: 16px; + height: 16px; +} +.ke-icon-superscript { + background-position: 0px -288px; + width: 16px; + height: 16px; +} +.ke-icon-date { + background-position: 0px -304px; + width: 25px; + height: 16px; +} +.ke-icon-time { + background-position: 0px -320px; + width: 25px; + height: 16px; +} +.ke-icon-formatblock { + background-position: 0px -336px; + width: 25px; + height: 16px; +} +.ke-icon-fontname { + background-position: 0px -352px; + width: 21px; + height: 16px; +} +.ke-icon-fontsize { + background-position: 0px -368px; + width: 23px; + height: 16px; +} +.ke-icon-forecolor { + background-position: 0px -384px; + width: 20px; + height: 16px; +} +.ke-icon-hilitecolor { + background-position: 0px -400px; + width: 23px; + height: 16px; +} +.ke-icon-bold { + background-position: 0px -416px; + width: 16px; + height: 16px; +} +.ke-icon-italic { + background-position: 0px -432px; + width: 16px; + height: 16px; +} +.ke-icon-underline { + background-position: 0px -448px; + width: 16px; + height: 16px; +} +.ke-icon-strikethrough { + background-position: 0px -464px; + width: 16px; + height: 16px; +} +.ke-icon-removeformat { + background-position: 0px -480px; + width: 16px; + height: 16px; +} +.ke-icon-image { + background-position: 0px -496px; + width: 16px; + height: 16px; +} +.ke-icon-flash { + background-position: 0px -512px; + width: 16px; + height: 16px; +} +.ke-icon-media { + background-position: 0px -528px; + width: 16px; + height: 16px; +} +.ke-icon-div { + background-position: 0px -544px; + width: 16px; + height: 16px; +} +.ke-icon-formula { + background-position: 0px -576px; + width: 16px; + height: 16px; +} +.ke-icon-hr { + background-position: 0px -592px; + width: 16px; + height: 16px; +} +.ke-icon-emoticons { + background-position: 0px -608px; + width: 16px; + height: 16px; +} +.ke-icon-link { + background-position: 0px -624px; + width: 16px; + height: 16px; +} +.ke-icon-unlink { + background-position: 0px -640px; + width: 16px; + height: 16px; +} +.ke-icon-fullscreen { + background-position: 0px -656px; + width: 16px; + height: 16px; +} +.ke-icon-about { + background-position: 0px -672px; + width: 16px; + height: 16px; +} +.ke-icon-plainpaste { + background-position: 0px -704px; + width: 16px; + height: 16px; +} +.ke-icon-wordpaste { + background-position: 0px -720px; + width: 16px; + height: 16px; +} +.ke-icon-table { + background-position: 0px -784px; + width: 16px; + height: 16px; +} +.ke-icon-tablemenu { + background-position: 0px -768px; + width: 16px; + height: 16px; +} +.ke-icon-tableinsert { + background-position: 0px -784px; + width: 16px; + height: 16px; +} +.ke-icon-tabledelete { + background-position: 0px -800px; + width: 16px; + height: 16px; +} +.ke-icon-tablecolinsertleft { + background-position: 0px -816px; + width: 16px; + height: 16px; +} +.ke-icon-tablecolinsertright { + background-position: 0px -832px; + width: 16px; + height: 16px; +} +.ke-icon-tablerowinsertabove { + background-position: 0px -848px; + width: 16px; + height: 16px; +} +.ke-icon-tablerowinsertbelow { + background-position: 0px -864px; + width: 16px; + height: 16px; +} +.ke-icon-tablecoldelete { + background-position: 0px -880px; + width: 16px; + height: 16px; +} +.ke-icon-tablerowdelete { + background-position: 0px -896px; + width: 16px; + height: 16px; +} +.ke-icon-tablecellprop { + background-position: 0px -912px; + width: 16px; + height: 16px; +} +.ke-icon-tableprop { + background-position: 0px -928px; + width: 16px; + height: 16px; +} +.ke-icon-checked { + background-position: 0px -944px; + width: 16px; + height: 16px; +} +.ke-icon-code { + background-position: 0px -960px; + width: 16px; + height: 16px; +} +.ke-icon-map { + background-position: 0px -976px; + width: 16px; + height: 16px; +} +.ke-icon-baidumap { + background-position: 0px -976px; + width: 16px; + height: 16px; +} +.ke-icon-lineheight { + background-position: 0px -992px; + width: 16px; + height: 16px; +} +.ke-icon-clearhtml { + background-position: 0px -1008px; + width: 16px; + height: 16px; +} +.ke-icon-pagebreak { + background-position: 0px -1024px; + width: 16px; + height: 16px; +} +.ke-icon-insertfile { + background-position: 0px -1040px; + width: 16px; + height: 16px; +} +.ke-icon-quickformat { + background-position: 0px -1056px; + width: 16px; + height: 16px; +} +.ke-icon-template { + background-position: 0px -1072px; + width: 16px; + height: 16px; +} +.ke-icon-tablecellsplit { + background-position: 0px -1088px; + width: 16px; + height: 16px; +} +.ke-icon-tablerowmerge { + background-position: 0px -1104px; + width: 16px; + height: 16px; +} +.ke-icon-tablerowsplit { + background-position: 0px -1120px; + width: 16px; + height: 16px; +} +.ke-icon-tablecolmerge { + background-position: 0px -1136px; + width: 16px; + height: 16px; +} +.ke-icon-tablecolsplit { + background-position: 0px -1152px; + width: 16px; + height: 16px; +} +.ke-icon-anchor { + background-position: 0px -1168px; + width: 16px; + height: 16px; +} +.ke-icon-search { + background-position: 0px -1184px; + width: 16px; + height: 16px; +} +.ke-icon-new { + background-position: 0px -1200px; + width: 16px; + height: 16px; +} +.ke-icon-specialchar { + background-position: 0px -1216px; + width: 16px; + height: 16px; +} +.ke-icon-multiimage { + background-position: 0px -1232px; + width: 16px; + height: 16px; +} +/* container */ +.ke-container { + display: block; + border: 1px solid #CCCCCC; + background-color: #FFF; + overflow: hidden; + margin: 0; + padding: 0; +} +/* toolbar */ +.ke-toolbar { + border-bottom: 1px solid #CCC; + background-color: #F0F0EE; + padding: 2px 5px; + text-align: left; + overflow: hidden; + zoom: 1; +} +.ke-toolbar-icon { + background-repeat: no-repeat; + font-size: 0; + line-height: 0; + overflow: hidden; + display: block; +} +.ke-toolbar-icon-url { + background-image: url(default.png); +} +.ke-toolbar .ke-outline { + border: 1px solid #F0F0EE; + margin: 1px; + padding: 1px 2px; + font-size: 0; + line-height: 0; + overflow: hidden; + cursor: pointer; + display: block; + float: left; +} +.ke-toolbar .ke-on { + border: 1px solid #5690D2; +} +.ke-toolbar .ke-selected { + border: 1px solid #5690D2; + background-color: #E9EFF6; +} +.ke-toolbar .ke-disabled { + cursor: default; +} +.ke-toolbar .ke-separator { + height: 16px; + margin: 2px 3px; + border-left: 1px solid #A0A0A0; + border-right: 1px solid #FFFFFF; + border-top:0; + border-bottom:0; + width: 0; + font-size: 0; + line-height: 0; + overflow: hidden; + display: block; + float: left; +} +.ke-toolbar .ke-hr { + overflow: hidden; + height: 1px; + clear: both; +} +/* edit */ +.ke-edit { + padding: 0; +} +.ke-edit-iframe, +.ke-edit-textarea { + border: 0; + margin: 0; + padding: 0; + overflow: auto; +} +.ke-edit-textarea { + font: 12px/1.5 "Consolas", "Monaco", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; + color: #000; + overflow: auto; + resize: none; +} +.ke-edit-textarea:focus { + outline: none; +} +/* statusbar */ +.ke-statusbar { + position: relative; + background-color: #F0F0EE; + border-top: 1px solid #CCCCCC; + font-size: 0; + line-height: 0; + *height: 12px; + overflow: hidden; + text-align: center; + cursor: s-resize; +} +.ke-statusbar-center-icon { + background-position: -0px -754px; + width: 15px; + height: 11px; + background-image: url(default.png); +} +.ke-statusbar-right-icon { + position: absolute; + right: 0; + bottom: 0; + cursor: se-resize; + background-position: -5px -741px; + width: 11px; + height: 11px; + background-image: url(default.png); +} +/* menu */ +.ke-menu { + border: 1px solid #A0A0A0; + background-color: #F1F1F1; + color: #222222; + padding: 2px; + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + text-align: left; + overflow: hidden; +} +.ke-menu-item { + border: 1px solid #F1F1F1; + background-color: #F1F1F1; + color: #222222; + height: 24px; + overflow: hidden; + cursor: pointer; +} +.ke-menu-item-on { + border: 1px solid #5690D2; + background-color: #E9EFF6; +} +.ke-menu-item-left { + width: 27px; + text-align: center; + overflow: hidden; +} +.ke-menu-item-center { + width: 0; + height: 24px; + border-left: 1px solid #E3E3E3; + border-right: 1px solid #FFFFFF; + border-top: 0; + border-bottom: 0; +} +.ke-menu-item-center-on { + border-left: 1px solid #E9EFF6; + border-right: 1px solid #E9EFF6; +} +.ke-menu-item-right { + border: 0; + padding: 0 0 0 5px; + line-height: 24px; + text-align: left; + overflow: hidden; +} +.ke-menu-separator { + margin: 2px 0; + height: 0; + overflow: hidden; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #FFFFFF; + border-left: 0; + border-right: 0; +} +/* colorpicker */ +.ke-colorpicker { + border: 1px solid #A0A0A0; + background-color: #F1F1F1; + color: #222222; + padding: 2px; +} +.ke-colorpicker-table { + border:0; + margin:0; + padding:0; + border-collapse: separate; +} +.ke-colorpicker-cell { + font-size: 0; + line-height: 0; + border: 1px solid #F0F0EE; + cursor: pointer; + margin:3px; + padding:0; +} +.ke-colorpicker-cell-top { + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + line-height: 24px; + border: 1px solid #F0F0EE; + cursor: pointer; + margin:0; + padding:0; + text-align: center; +} +.ke-colorpicker-cell-on { + border: 1px solid #5690D2; +} +.ke-colorpicker-cell-selected { + border: 1px solid #2446AB; +} +.ke-colorpicker-cell-color { + width: 14px; + height: 14px; + margin: 3px; + padding: 0; + border: 0; +} +/* dialog */ +.ke-dialog { + position: absolute; + margin: 0; + padding: 0; +} +.ke-dialog .ke-header { + width: 100%; + margin-bottom: 10px; +} +.ke-dialog .ke-header .ke-left { + float: left; +} +.ke-dialog .ke-header .ke-right { + float: right; +} +.ke-dialog .ke-header label { + margin-right: 0; + cursor: pointer; + font-weight: normal; + display: inline; + vertical-align: top; +} +.ke-dialog-content { + background-color: #FFF; + width: 100%; + height: 100%; + color: #333; + border: 1px solid #A0A0A0; +} +.ke-dialog-shadow { + position: absolute; + z-index: -1; + top: 0; + left: 0; + width: 100%; + height: 100%; + box-shadow: 3px 3px 7px #999; + -moz-box-shadow: 3px 3px 7px #999; + -webkit-box-shadow: 3px 3px 7px #999; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='3', MakeShadow='true', ShadowOpacity='0.4'); + background-color: #F0F0EE; +} +.ke-dialog-header { + border:0; + margin:0; + padding: 0 10px; + background: url(background.png) repeat scroll 0 0 #F0F0EE; + border-bottom: 1px solid #CFCFCF; + height: 24px; + font: 12px/24px "sans serif",tahoma,verdana,helvetica; + text-align: left; + color: #222; + cursor: move; +} +.ke-dialog-icon-close { + display: block; + background: url(default.png) no-repeat scroll 0px -688px; + width: 16px; + height: 16px; + position: absolute; + right: 6px; + top: 6px; + cursor: pointer; +} +.ke-dialog-body { + font: 12px/1.5 "sans serif",tahoma,verdana,helvetica; + text-align: left; + overflow: hidden; + width: 100%; +} +.ke-dialog-body textarea { + display: block; + overflow: auto; + padding: 0; + resize: none; +} +.ke-dialog-body textarea:focus, +.ke-dialog-body input:focus, +.ke-dialog-body select:focus { + outline: none; +} +.ke-dialog-body label { + margin-right: 10px; + cursor: pointer; + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; +} +.ke-dialog-body img { + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; +} +.ke-dialog-body select { + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; + width: auto; +} +.ke-dialog-body .ke-textarea { + display: block; + width: 408px; + height: 260px; + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + border-color: #848484 #E0E0E0 #E0E0E0 #848484; + border-style: solid; + border-width: 1px; +} +.ke-dialog-body .ke-form { + margin: 0; + padding: 0; +} +.ke-dialog-loading { + position: absolute; + top: 0; + left: 1px; + z-index: 1; + text-align: center; +} +.ke-dialog-loading-content { + background: url("../common/loading.gif") no-repeat; + color: #666; + font-size: 14px; + font-weight: bold; + height: 31px; + line-height: 31px; + padding-left: 36px; +} +.ke-dialog-row { + margin-bottom: 10px; +} +.ke-dialog-footer { + font: 12px/1 "sans serif",tahoma,verdana,helvetica; + text-align: right; + padding:0 0 5px 0; + background-color: #FFF; + width: 100%; +} +.ke-dialog-preview, +.ke-dialog-yes { + margin: 5px; +} +.ke-dialog-no { + margin: 5px 10px 5px 5px; +} +.ke-dialog-mask { + background-color:#FFF; + filter:alpha(opacity=50); + opacity:0.5; +} +.ke-button-common { + background: url(background.png) no-repeat; + cursor: pointer; + height: 23px; + line-height: 23px; + overflow: visible; + display: inline-block; + vertical-align: top; + cursor: pointer; +} +.ke-button-outer { + background-position: 0 -25px; + padding: 0; + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; +} +.ke-button { + background-position: right -25px; + padding: 0 14px 0 12px; + margin: 0 0 0 2px; + font-family: "sans serif",tahoma,verdana,helvetica; + border: 0 none; + color: #333; + font-size: 12px; + text-decoration: none; +} +/* inputbox */ +.ke-input-text { + background-color:#FFFFFF; + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + line-height: 17px; + height: 17px; + padding: 2px 4px; + border-color: #848484 #E0E0E0 #E0E0E0 #848484; + border-style: solid; + border-width: 1px; + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; +} +.ke-input-number { + width: 50px; +} +.ke-input-color { + border: 1px solid #A0A0A0; + background-color: #FFFFFF; + font-size: 12px; + width: 60px; + height: 20px; + line-height: 20px; + padding-left: 5px; + overflow: hidden; + cursor: pointer; + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + zoom: 1; + *display: inline; +} +.ke-upload-button { + position: relative; +} +.ke-upload-area { + position: relative; + overflow: hidden; + margin: 0; + padding: 0; + *height: 25px; +} +.ke-upload-area .ke-upload-file { + position: absolute; + font-size: 60px; + top: 0; + right: 0; + padding: 0; + margin: 0; + z-index: 811212; + border: 0 none; + opacity: 0; + filter: alpha(opacity=0); +} +/* tabs */ +.ke-tabs { + font: 12px/1 "sans serif",tahoma,verdana,helvetica; + border-bottom:1px solid #A0A0A0; + padding-left:5px; + margin-bottom:20px; +} +.ke-tabs-ul { + list-style-image:none; + list-style-position:outside; + list-style-type:none; + margin:0; + padding:0; +} +.ke-tabs-li { + position: relative; + border: 1px solid #A0A0A0; + background-color: #F0F0EE; + margin: 0 2px -1px 0; + padding: 0 20px; + float: left; + line-height: 25px; + text-align: center; + color: #555555; + cursor: pointer; +} +.ke-tabs-li-selected { + background-color: #FFF; + border-bottom: 1px solid #FFF; + color: #000; + cursor: default; +} +.ke-tabs-li-on { + background-color: #FFF; + color: #000; +} +/* progressbar */ +.ke-progressbar { + position: relative; + margin: 0; + padding: 0; +} +.ke-progressbar-bar { + border: 1px solid #6FA5DB; + width: 80px; + height: 5px; + margin: 10px 10px 0 10px; + padding: 0; +} +.ke-progressbar-bar-inner { + width: 0; + height: 5px; + background-color: #6FA5DB; + overflow: hidden; + margin: 0; + padding: 0; +} +.ke-progressbar-percent { + position: absolute; + top: 0; + left: 40%; + display: none; +} +/* swfupload */ +.ke-swfupload-top { + position: relative; + margin-bottom: 10px; + _width: 608px; +} +.ke-swfupload-button { + height: 23px; + line-height: 23px; +} +.ke-swfupload-desc { + padding: 0 10px; + height: 23px; + line-height: 23px; +} +.ke-swfupload-startupload { + position: absolute; + top: 0; + right: 0; +} +.ke-swfupload-body { + overflow: scroll; + background-color:#FFFFFF; + border-color: #848484 #E0E0E0 #E0E0E0 #848484; + border-style: solid; + border-width: 1px; + width: auto; + height: 370px; + padding: 5px; +} +.ke-swfupload-body .ke-item { + width: 100px; + margin: 5px; +} +.ke-swfupload-body .ke-photo { + position: relative; + border: 1px solid #DDDDDD; + background-color:#FFFFFF; + padding: 10px; +} +.ke-swfupload-body .ke-delete { + display: block; + background: url(default.png) no-repeat scroll 0px -688px; + width: 16px; + height: 16px; + position: absolute; + right: 0; + top: 0; + cursor: pointer; +} +.ke-swfupload-body .ke-status { + position: absolute; + left: 0; + bottom: 5px; + width: 100px; + height: 17px; +} +.ke-swfupload-body .ke-message { + width: 100px; + text-align: center; + overflow: hidden; + height:17px; +} +.ke-swfupload-body .ke-error { + color: red; +} +.ke-swfupload-body .ke-name { + width: 100px; + text-align: center; + overflow: hidden; + height:16px; +} +.ke-swfupload-body .ke-on { + border: 1px solid #5690D2; + background-color: #E9EFF6; +} + +/* emoticons */ +.ke-plugin-emoticons { + position: relative; +} +.ke-plugin-emoticons .ke-preview { + position: absolute; + text-align: center; + margin: 2px; + padding: 10px; + top: 0; + border: 1px solid #A0A0A0; + background-color: #FFFFFF; + display: none; +} +.ke-plugin-emoticons .ke-preview-img { + border:0; + margin:0; + padding:0; +} +.ke-plugin-emoticons .ke-table { + border:0; + margin:0; + padding:0; + border-collapse:separate; +} +.ke-plugin-emoticons .ke-cell { + margin:0; + padding:1px; + border:1px solid #F0F0EE; + cursor:pointer; +} +.ke-plugin-emoticons .ke-on { + border: 1px solid #5690D2; + background-color: #E9EFF6; +} +.ke-plugin-emoticons .ke-img { + display:block; + background-repeat:no-repeat; + overflow:hidden; + margin:2px; + width:24px; + height:24px; + margin: 0; + padding: 0; + border: 0; +} +.ke-plugin-emoticons .ke-page { + text-align: right; + margin: 5px; + padding: 0; + border: 0; + font: 12px/1 "sans serif",tahoma,verdana,helvetica; + color: #333; + text-decoration: none; +} +.ke-plugin-plainpaste-textarea, +.ke-plugin-wordpaste-iframe { + display: block; + width: 408px; + height: 260px; + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + border-color: #848484 #E0E0E0 #E0E0E0 #848484; + border-style: solid; + border-width: 1px; +} +/* filemanager */ +.ke-plugin-filemanager-header { + width: 100%; + margin-bottom: 10px; +} +.ke-plugin-filemanager-header .ke-left { + float: left; +} +.ke-plugin-filemanager-header .ke-right { + float: right; +} +.ke-plugin-filemanager-body { + overflow: scroll; + background-color:#FFFFFF; + border-color: #848484 #E0E0E0 #E0E0E0 #848484; + border-style: solid; + border-width: 1px; + width: auto; + height: 370px; + padding: 5px; +} +.ke-plugin-filemanager-body .ke-item { + width: 100px; + margin: 5px; +} +.ke-plugin-filemanager-body .ke-photo { + border: 1px solid #DDDDDD; + background-color:#FFFFFF; + padding: 10px; +} +.ke-plugin-filemanager-body .ke-name { + width: 100px; + text-align: center; + overflow: hidden; + height:16px; +} +.ke-plugin-filemanager-body .ke-on { + border: 1px solid #5690D2; + background-color: #E9EFF6; +} +.ke-plugin-filemanager-body .ke-table { + width: 95%; + border: 0; + margin: 0; + padding: 0; + border-collapse: separate; +} +.ke-plugin-filemanager-body .ke-table .ke-cell { + margin: 0; + padding: 0; + border: 0; +} +.ke-plugin-filemanager-body .ke-table .ke-name { + width: 55%; + text-align: left; +} +.ke-plugin-filemanager-body .ke-table .ke-size { + width: 15%; + text-align: left; +} +.ke-plugin-filemanager-body .ke-table .ke-datetime { + width: 30%; + text-align: center; +} + diff --git a/php/kindeditor_demo/kindeditor/themes/default/default.png b/php/kindeditor_demo/kindeditor/themes/default/default.png new file mode 100755 index 0000000..cc9e72d Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/default/default.png differ diff --git a/php/kindeditor_demo/kindeditor/themes/qq/editor.gif b/php/kindeditor_demo/kindeditor/themes/qq/editor.gif new file mode 100755 index 0000000..b256841 Binary files /dev/null and b/php/kindeditor_demo/kindeditor/themes/qq/editor.gif differ diff --git a/php/kindeditor_demo/kindeditor/themes/qq/qq.css b/php/kindeditor_demo/kindeditor/themes/qq/qq.css new file mode 100755 index 0000000..75aac1e --- /dev/null +++ b/php/kindeditor_demo/kindeditor/themes/qq/qq.css @@ -0,0 +1,163 @@ +/* container */ +.ke-container-qq { + display: block; + border: 1px solid #c3c3c3; + background-color: #FFF; + overflow: hidden; + margin: 0; + padding: 0; +} +/* toolbar */ +.ke-container-qq .ke-toolbar { + border-bottom: 1px solid #c3c3c3; + background-color: #FFFFFF; + padding: 2px 5px; + text-align: left; + overflow: hidden; + zoom: 1; +} +.ke-toolbar-icon-url { + background-image: url(editor.gif); + width:18px; + *xwidth:20px; + height:18px; + *xheight:20px; +} +.ke-icon-checked{ + background-image: url(../default/default.png); + width:16px; + height:16px; +} +.ke-container-qq .ke-icon-bold{ + background-position: 4px 1px; +} +.ke-container-qq .ke-icon-italic{ + background-position: -27px 1px; +} +.ke-container-qq .ke-icon-italic{ + background-position: -28px 1px; +} +.ke-container-qq .ke-icon-underline{ + background-position: -60px 1px; +} +.ke-container-qq .ke-icon-fontname{ + background-position: -95px 1px; +} +.ke-container-qq .ke-icon-fontsize{ + background-position: -128px 1px; +} +.ke-container-qq .ke-icon-forecolor{ + background-position: -159px 1px; +} +.ke-container-qq .ke-icon-hilitecolor{ + background-position: -190px 1px; +} +.ke-container-qq .ke-icon-plug-align{ + background-position: -223px 1px; +} +/*这是2016年添加的img图标 ----start*/ +.ke-container-qq .ke-icon-image{ + background-image: url(../default/default.png); + background-position: 0px -496px; + width: 16px; + height: 16px; +} +.ke-container-qq .ke-icon-multiimage{ + background-image: url(../default/default.png); + background-position: 0px -1232px; + width: 16px; + height: 16px; +} +.ke-container-qq .ke-icon-baidumap{ + background-image: url(../default/default.png); + background-position: 0px -976px; + width: 16px; + height: 16px; +} +/*这是2016年添加的img图标 ----end*/ +.plug-align-justifyleft{ + background-position: -350px 1px; +} +.plug-align-justifycenter{ + background-position: -382px 1px; +} +.plug-align-justifyright{ + background-position: -414px 1px; +} +.plug-order-insertorderedlist{ + background-position: -446px 1px; +} +.plug-order-insertunorderedlist{ + background-position: -477px 1px; +} +.plug-indent-indent{ + background-position: -513px 1px; +} +.plug-indent-outdent{ + background-position: -545px 1px; +} +.ke-container-qq .ke-icon-plug-order{ + background-position: -255px 1px; +} +.ke-container-qq .ke-icon-plug-indent{ + background-position: -287px 1px; +} +.ke-container-qq .ke-icon-link{ + background-position: -319px 1px; +} + +.ke-container-qq .ke-toolbar .ke-outline { + cursor: default; + padding:0px; + border:1px solid #fff; +} +.ke-container-qq .ke-toolbar .ke-on { + border-left:1px solid white; + border-top:1px solid white; + border-right:1px solid gray; + border-bottom:1px solid gray; + background-color: #FFFFFF; +} +.ke-container-qq .ke-toolbar .ke-selected { + border-left:1px solid gray; + border-top:1px solid gray; + border-right:1px solid white; + border-bottom:1px solid white; + background-color: #FFFFFF; +} +.ke-container-qq .ke-toolbar .ke-disabled { + cursor: default; +} + +.ke-colorpicker-qq{ + background:#fff; +} +/* statusbar */ +.ke-container-qq .ke-statusbar { + display:none; +} +/* menu */ +.ke-menu-qq { + border:1px solid #a6a6a6; + position:absolute; + background:#fff; + -moz-box-shadow:2px 2px 4px #DDDDDD; + z-index:999; + left:-400px; + top:-386px; + right:218px; + width:130px; +} +.ke-menu-qq .ke-menu-item { + padding:0px; + background:#fff; +} +.ke-menu-qq .ke-menu-item-on { + border:1px solid #000080;background:#FFEEC2;color:#036; +} +.ke-menu-qq .ke-toolbar .ke-selected { + border:1px solid #9a9afb; +} +.ke-menu-qq .ke-menu-item-left{ + width:auto; +} diff --git a/php/kindeditor_demo/kindeditor/themes/simple/simple.css b/php/kindeditor_demo/kindeditor/themes/simple/simple.css new file mode 100755 index 0000000..4c76cf9 --- /dev/null +++ b/php/kindeditor_demo/kindeditor/themes/simple/simple.css @@ -0,0 +1,100 @@ +/* container */ +.ke-container-simple { + display: block; + border: 1px solid #CCC; + background-color: #FFF; + overflow: hidden; +} +/* toolbar */ +.ke-container-simple .ke-toolbar { + border-bottom: 1px solid #CCC; + background-color: #FFF; + padding: 2px 5px; + overflow: hidden; +} +.ke-container-simple .ke-toolbar .ke-outline { + border: 1px solid #FFF; + background-color: transparent; + margin: 1px; + padding: 1px 2px; + font-size: 0; + line-height: 0; + overflow: hidden; + cursor: pointer; +} +.ke-container-simple .ke-toolbar .ke-on { + border: 1px solid #5690D2; +} +.ke-container-simple .ke-toolbar .ke-selected { + border: 1px solid #5690D2; + background-color: #E9EFF6; +} +.ke-container-simple .ke-toolbar .ke-disabled { + cursor: default; +} +/* statusbar */ +.ke-container-simple .ke-statusbar { + position: relative; + background-color: #FFF; + border-top: 1px solid #CCCCCC; + font-size: 0; + line-height: 0; + *height: 12px; + overflow: hidden; + text-align: center; + cursor: s-resize; +} +/* menu */ +.ke-menu-simple { + border: 1px solid #A0A0A0; + background-color: #FFF; + color: #222222; + padding: 2px; + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + text-align: left; + overflow: hidden; +} +.ke-menu-simple .ke-menu-item { + border: 1px solid #FFF; + background-color: #FFF; + color: #222222; + height: 24px; + overflow: hidden; + cursor: pointer; +} +.ke-menu-simple .ke-menu-item-on { + border: 1px solid #5690D2; + background-color: #FFF; +} +/* colorpicker */ +.ke-colorpicker-simple { + border: 1px solid #A0A0A0; + background-color: #FEFEFE; + color: #222222; + padding: 2px; +} +.ke-colorpicker-simple .ke-colorpicker-cell { + font-size: 0; + line-height: 0; + border: 1px solid #FEFEFE; + cursor: pointer; + margin:3px; + padding:0; +} +.ke-colorpicker-simple .ke-colorpicker-cell-top { + font-family: "sans serif",tahoma,verdana,helvetica; + font-size: 12px; + line-height: 24px; + border: 1px solid #FEFEFE; + cursor: pointer; + margin:0; + padding:0; + text-align: center; +} +.ke-colorpicker-simple .ke-colorpicker-cell-on { + border: 1px solid #5690D2; +} +.ke-colorpicker-simple .ke-colorpicker-cell-selected { + border: 1px solid #2446AB; +}