1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/object",
  5     "firebug/firebug",
  6     "firebug/lib/domplate",
  7     "firebug/lib/locale",
  8     "firebug/lib/events",
  9     "firebug/lib/url",
 10     "firebug/lib/css",
 11     "firebug/lib/dom",
 12     "firebug/lib/array",
 13     "firebug/net/netUtils",
 14 ],
 15 function(Obj, Firebug, Domplate, Locale, Events, Url, Css, Dom, Arr, NetUtils) {
 16 
 17 // ********************************************************************************************* //
 18 // Constants
 19 
 20 const Cc = Components.classes;
 21 const Ci = Components.interfaces;
 22 const Cr = Components.results;
 23 
 24 var panelName = "net";
 25 
 26 // ********************************************************************************************* //
 27 // Breakpoints
 28 
 29 function NetBreakpointGroup()
 30 {
 31     this.breakpoints = [];
 32 }
 33 
 34 NetBreakpointGroup.prototype = Obj.extend(new Firebug.Breakpoint.BreakpointGroup(),
 35 {
 36     name: "netBreakpoints",
 37     title: Locale.$STR("net.label.XHR Breakpoints"),
 38 
 39     addBreakpoint: function(href)
 40     {
 41         this.breakpoints.push(new Breakpoint(href));
 42     },
 43 
 44     removeBreakpoint: function(href)
 45     {
 46         var bp = this.findBreakpoint(href);
 47         Arr.remove(this.breakpoints, bp);
 48     },
 49 
 50     matchBreakpoint: function(bp, args)
 51     {
 52         var href = args[0];
 53         return bp.href == href;
 54     }
 55 });
 56 
 57 // ********************************************************************************************* //
 58 
 59 function Breakpoint(href)
 60 {
 61     this.href = href;
 62     this.checked = true;
 63     this.condition = "";
 64     this.onEvaluateFails = Obj.bind(this.onEvaluateFails, this);
 65     this.onEvaluateSucceeds =  Obj.bind(this.onEvaluateSucceeds, this);
 66 }
 67 
 68 Breakpoint.prototype =
 69 {
 70     evaluateCondition: function(context, file)
 71     {
 72         try
 73         {
 74             var scope = {};
 75 
 76             var params = file.urlParams;
 77             for (var i=0; params && i<params.length; i++)
 78             {
 79                 var param = params[i];
 80                 scope[param.name] = param.value;
 81             }
 82 
 83             scope["$postBody"] = NetUtils.getPostText(file, context);
 84 
 85             // The properties of scope are all strings; we pass them in then
 86             // unpack them using 'with'. The function is called immediately.
 87             var expr = "(function (){var scope = " + JSON.stringify(scope) +
 88                 "; with (scope) { return  " + this.condition + ";}})();"
 89 
 90             // The callbacks will set this if the condition is true or if the eval faults.
 91             delete context.breakingCause;
 92 
 93             var rc = Firebug.CommandLine.evaluate(expr, context, null, context.window,
 94                 this.onEvaluateSucceeds, this.onEvaluateFails );
 95 
 96             if (FBTrace.DBG_NET)
 97                 FBTrace.sysout("net.evaluateCondition; rc " + rc, {expr: expr,scope: scope,
 98                     json: JSON.stringify(scope)});
 99 
100             return !!context.breakingCause;
101         }
102         catch (err)
103         {
104             if (FBTrace.DBG_NET)
105                 FBTrace.sysout("net.evaluateCondition; EXCEPTION "+err, err);
106         }
107 
108         return false;
109     },
110 
111     onEvaluateSucceeds: function(result, context)
112     {
113         // Don't break if the result is false.
114         if (!result)
115             return;
116 
117         context.breakingCause = {
118             title: Locale.$STR("net.Break On XHR"),
119             message: this.condition
120         };
121     },
122 
123     onEvaluateFails: function(result, context)
124     {
125         // Break if there is an error when evaluating the condition (to display the error).
126         context.breakingCause = {
127             title: Locale.$STR("net.Break On XHR"),
128             message: "Breakpoint condition evaluation fails ",
129             prevValue: this.condition,
130             newValue:result
131         };
132     },
133 }
134 
135 // ********************************************************************************************* //
136 // Breakpoint UI
137 
138 with (Domplate) {
139 var BreakpointRep = domplate(Firebug.Rep,
140 {
141     inspectable: false,
142 
143     tag:
144         DIV({"class": "breakpointRow focusRow", $disabled: "$bp|isDisabled", _repObject: "$bp",
145             role: "option", "aria-checked": "$bp.checked"},
146             DIV({"class": "breakpointBlockHead"},
147                 INPUT({"class": "breakpointCheckbox", type: "checkbox",
148                     _checked: "$bp.checked", tabindex: "-1", onclick: "$onEnable"}),
149                 SPAN({"class": "breakpointName", title: "$bp|getTitle"}, "$bp|getName"),
150                 IMG({"class": "closeButton", src: "blank.gif", onclick: "$onRemove"})
151             ),
152             DIV({"class": "breakpointCondition"},
153                 SPAN("$bp.condition")
154             )
155         ),
156 
157     getTitle: function(bp)
158     {
159         return bp.href;
160     },
161 
162     getName: function(bp)
163     {
164         return Url.getFileName(bp.href);
165     },
166 
167     isDisabled: function(bp)
168     {
169         return !bp.checked;
170     },
171 
172     onRemove: function(event)
173     {
174         Events.cancelEvent(event);
175 
176         if (!Css.hasClass(event.target, "closeButton"))
177             return;
178 
179         var bpPanel = Firebug.getElementPanel(event.target);
180         var context = bpPanel.context;
181 
182         // Remove from list of breakpoints.
183         var row = Dom.getAncestorByClass(event.target, "breakpointRow");
184         var bp = row.repObject;
185         context.netProgress.breakpoints.removeBreakpoint(bp.href);
186 
187         bpPanel.refresh();
188 
189         var panel = context.getPanel(panelName, true);
190         if (!panel)
191             return;
192 
193         panel.enumerateRequests(function(file)
194         {
195             if (file.getFileURL() == bp.href)
196             {
197                 file.row.removeAttribute("breakpoint");
198                 file.row.removeAttribute("disabledBreakpoint");
199             }
200         })
201     },
202 
203     onEnable: function(event)
204     {
205         var checkBox = event.target;
206         var bpRow = Dom.getAncestorByClass(checkBox, "breakpointRow");
207 
208         if (checkBox.checked)
209         {
210             Css.removeClass(bpRow, "disabled");
211             bpRow.setAttribute("aria-checked", "true");
212         }
213         else
214         {
215             Css.setClass(bpRow, "disabled");
216             bpRow.setAttribute("aria-checked", "false");
217         }
218 
219         var bp = bpRow.repObject;
220         bp.checked = checkBox.checked;
221 
222         var bpPanel = Firebug.getElementPanel(event.target);
223         var context = bpPanel.context;
224 
225         var panel = context.getPanel(panelName, true);
226         if (!panel)
227             return;
228 
229         panel.enumerateRequests(function(file)
230         {
231             if (file.getFileURL() == bp.href)
232                 file.row.setAttribute("disabledBreakpoint", bp.checked ? "false" : "true");
233         });
234     },
235 
236     supportsObject: function(object, type)
237     {
238         return object instanceof Breakpoint;
239     }
240 })};
241 
242 // ********************************************************************************************* //
243 // Registration
244 
245 Firebug.registerRep(BreakpointRep);
246 
247 return {
248     NetBreakpointGroup: NetBreakpointGroup
249 };
250 
251 // ********************************************************************************************* //
252 });
253