Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 <?xml version="1.0"?>
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
3 - License, v. 2.0. If a copy of the MPL was not distributed with this
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
7 <!DOCTYPE page [
8 <!ENTITY % extensionsDTD SYSTEM "chrome://mozapps/locale/extensions/extensions.dtd">
9 %extensionsDTD;
10 ]>
12 <bindings id="addonBindings"
13 xmlns="http://www.mozilla.org/xbl"
14 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
15 xmlns:xbl="http://www.mozilla.org/xbl">
18 <!-- Rating - displays current/average rating, allows setting user rating -->
19 <binding id="rating">
20 <content>
21 <xul:image class="star"
22 onmouseover="document.getBindingParent(this)._hover(1);"
23 onclick="document.getBindingParent(this).userRating = 1;"/>
24 <xul:image class="star"
25 onmouseover="document.getBindingParent(this)._hover(2);"
26 onclick="document.getBindingParent(this).userRating = 2;"/>
27 <xul:image class="star"
28 onmouseover="document.getBindingParent(this)._hover(3);"
29 onclick="document.getBindingParent(this).userRating = 3;"/>
30 <xul:image class="star"
31 onmouseover="document.getBindingParent(this)._hover(4);"
32 onclick="document.getBindingParent(this).userRating = 4;"/>
33 <xul:image class="star"
34 onmouseover="document.getBindingParent(this)._hover(5);"
35 onclick="document.getBindingParent(this).userRating = 5;"/>
36 </content>
38 <implementation>
39 <constructor><![CDATA[
40 this._updateStars();
41 ]]></constructor>
43 <property name="stars" readonly="true">
44 <getter><![CDATA[
45 return document.getAnonymousNodes(this);
46 ]]></getter>
47 </property>
49 <property name="averageRating">
50 <getter><![CDATA[
51 if (this.hasAttribute("averagerating"))
52 return this.getAttribute("averagerating");
53 return -1;
54 ]]></getter>
55 <setter><![CDATA[
56 this.setAttribute("averagerating", val);
57 if (this.showRating == "average")
58 this._updateStars();
59 ]]></setter>
60 </property>
62 <property name="userRating">
63 <getter><![CDATA[
64 if (this.hasAttribute("userrating"))
65 return this.getAttribute("userrating");
66 return -1;
67 ]]></getter>
68 <setter><![CDATA[
69 if (this.showRating != "user")
70 return;
71 this.setAttribute("userrating", val);
72 if (this.showRating == "user")
73 this._updateStars();
74 ]]></setter>
75 </property>
77 <property name="showRating">
78 <getter><![CDATA[
79 if (this.hasAttribute("showrating"))
80 return this.getAttribute("showrating");
81 return "average";
82 ]]></getter>
83 <setter><![CDATA[
84 if (val != "average" || val != "user")
85 throw Components.Exception("Invalid value", Components.results.NS_ERROR_ILLEGAL_VALUE);
86 this.setAttribute("showrating", val);
87 this._updateStars();
88 ]]></setter>
89 </property>
91 <method name="_updateStars">
92 <body><![CDATA[
93 var stars = this.stars;
94 var rating = this[this.showRating + "Rating"];
95 // average ratings can be non-whole numbers, round them so they
96 // match to their closest star
97 rating = Math.round(rating);
98 for (let i = 0; i < stars.length; i++)
99 stars[i].setAttribute("on", rating > i);
100 ]]></body>
101 </method>
103 <method name="_hover">
104 <parameter name="aScore"/>
105 <body><![CDATA[
106 if (this.showRating != "user")
107 return;
108 var stars = this.stars;
109 for (let i = 0; i < stars.length; i++)
110 stars[i].setAttribute("on", i <= (aScore -1));
111 ]]></body>
112 </method>
114 </implementation>
116 <handlers>
117 <handler event="mouseout">
118 this._updateStars();
119 </handler>
120 </handlers>
121 </binding>
123 <!-- Download progress - shows graphical progress of download and any
124 related status message. -->
125 <binding id="download-progress">
126 <content>
127 <xul:stack flex="1">
128 <xul:hbox flex="1">
129 <xul:hbox class="start-cap"/>
130 <xul:progressmeter anonid="progress" class="progress" flex="1"
131 min="0" max="100"/>
132 <xul:hbox class="end-cap"/>
133 </xul:hbox>
134 <xul:hbox class="status-container">
135 <xul:spacer flex="1"/>
136 <xul:label anonid="status" class="status"/>
137 <xul:spacer flex="1"/>
138 <xul:button anonid="cancel-btn" class="cancel"
139 tooltiptext="&progress.cancel.tooltip;"
140 oncommand="document.getBindingParent(this).cancel();"/>
141 </xul:hbox>
142 </xul:stack>
143 </content>
145 <implementation>
146 <constructor><![CDATA[
147 var progress = 0;
148 if (this.hasAttribute("progress"))
149 progress = parseInt(this.getAttribute("progress"));
150 this.progress = progress;
151 ]]></constructor>
153 <field name="_progress">
154 document.getAnonymousElementByAttribute(this, "anonid", "progress");
155 </field>
156 <field name="_cancel">
157 document.getAnonymousElementByAttribute(this, "anonid", "cancel-btn");
158 </field>
159 <field name="_status">
160 document.getAnonymousElementByAttribute(this, "anonid", "status");
161 </field>
163 <property name="progress">
164 <getter><![CDATA[
165 return this._progress.value;
166 ]]></getter>
167 <setter><![CDATA[
168 this._progress.value = val;
169 if (val == this._progress.max)
170 this.setAttribute("complete", true);
171 else
172 this.removeAttribute("complete");
173 ]]></setter>
174 </property>
176 <property name="maxProgress">
177 <getter><![CDATA[
178 return this._progress.max;
179 ]]></getter>
180 <setter><![CDATA[
181 if (val == -1) {
182 this._progress.mode = "undetermined";
183 } else {
184 this._progress.mode = "determined";
185 this._progress.max = val;
186 }
187 this.setAttribute("mode", this._progress.mode);
188 ]]></setter>
189 </property>
191 <property name="status">
192 <getter><![CDATA[
193 return this._status.value;
194 ]]></getter>
195 <setter><![CDATA[
196 this._status.value = val;
197 ]]></setter>
198 </property>
200 <method name="cancel">
201 <body><![CDATA[
202 this.mInstall.cancel();
203 ]]></body>
204 </method>
205 </implementation>
206 </binding>
209 <!-- Sorters - displays and controls the sort state of a list. -->
210 <binding id="sorters">
211 <content orient="horizontal">
212 <xul:button anonid="name-btn" class="sorter"
213 label="&sort.name.label;" tooltiptext="&sort.name.tooltip;"
214 oncommand="this.parentNode._handleChange('name');"/>
215 <xul:button anonid="date-btn" class="sorter"
216 label="&sort.dateUpdated.label;"
217 tooltiptext="&sort.dateUpdated.tooltip;"
218 oncommand="this.parentNode._handleChange('updateDate');"/>
219 <xul:button anonid="price-btn" class="sorter" hidden="true"
220 label="&sort.price.label;"
221 tooltiptext="&sort.price.tooltip;"
222 oncommand="this.parentNode._handleChange('purchaseAmount');"/>
223 <xul:button anonid="relevance-btn" class="sorter" hidden="true"
224 label="&sort.relevance.label;"
225 tooltiptext="&sort.relevance.tooltip;"
226 oncommand="this.parentNode._handleChange('relevancescore');"/>
227 </content>
229 <implementation>
230 <constructor><![CDATA[
231 if (!this.hasAttribute("sortby"))
232 this.setAttribute("sortby", "name");
234 if (this.getAttribute("showrelevance") == "true")
235 this._btnRelevance.hidden = false;
237 if (this.getAttribute("showprice") == "true")
238 this._btnPrice.hidden = false;
240 this._refreshState();
241 ]]></constructor>
243 <field name="handler">null</field>
244 <field name="_btnName">
245 document.getAnonymousElementByAttribute(this, "anonid", "name-btn");
246 </field>
247 <field name="_btnDate">
248 document.getAnonymousElementByAttribute(this, "anonid", "date-btn");
249 </field>
250 <field name="_btnPrice">
251 document.getAnonymousElementByAttribute(this, "anonid", "price-btn");
252 </field>
253 <field name="_btnRelevance">
254 document.getAnonymousElementByAttribute(this, "anonid", "relevance-btn");
255 </field>
257 <property name="sortBy">
258 <getter><![CDATA[
259 return this.getAttribute("sortby");
260 ]]></getter>
261 <setter><![CDATA[
262 if (val != this.sortBy) {
263 this.setAttribute("sortBy", val);
264 this._refreshState();
265 }
266 ]]></setter>
267 </property>
269 <property name="ascending">
270 <getter><![CDATA[
271 return (this.getAttribute("ascending") == "true");
272 ]]></getter>
273 <setter><![CDATA[
274 val = !!val;
275 if (val != this.ascending) {
276 this.setAttribute("ascending", val);
277 this._refreshState();
278 }
279 ]]></setter>
280 </property>
282 <property name="showrelevance">
283 <getter><![CDATA[
284 return (this.getAttribute("showrelevance") == "true");
285 ]]></getter>
286 <setter><![CDATA[
287 val = !!val;
288 this.setAttribute("showrelevance", val);
289 this._btnRelevance.hidden = !val;
290 ]]></setter>
291 </property>
293 <property name="showprice">
294 <getter><![CDATA[
295 return (this.getAttribute("showprice") == "true");
296 ]]></getter>
297 <setter><![CDATA[
298 val = !!val;
299 this.setAttribute("showprice", val);
300 this._btnPrice.hidden = !val;
301 ]]></setter>
302 </property>
304 <method name="setSort">
305 <parameter name="aSort"/>
306 <parameter name="aAscending"/>
307 <body><![CDATA[
308 var sortChanged = false;
309 if (aSort != this.sortBy) {
310 this.setAttribute("sortby", aSort);
311 sortChanged = true;
312 }
314 aAscending = !!aAscending;
315 if (this.ascending != aAscending) {
316 this.setAttribute("ascending", aAscending);
317 sortChanged = true;
318 }
320 if (sortChanged)
321 this._refreshState();
322 ]]></body>
323 </method>
325 <method name="_handleChange">
326 <parameter name="aSort"/>
327 <body><![CDATA[
328 const ASCENDING_SORT_FIELDS = ["name", "purchaseAmount"];
330 // Toggle ascending if sort by is not changing, otherwise
331 // name sorting defaults to ascending, others to descending
332 if (aSort == this.sortBy)
333 this.ascending = !this.ascending;
334 else
335 this.setSort(aSort, ASCENDING_SORT_FIELDS.indexOf(aSort) >= 0);
336 ]]></body>
337 </method>
339 <method name="_refreshState">
340 <body><![CDATA[
341 var sortBy = this.sortBy;
342 var checkState = this.ascending ? 2 : 1;
344 if (sortBy == "name") {
345 this._btnName.checkState = checkState;
346 this._btnName.checked = true;
347 } else {
348 this._btnName.checkState = 0;
349 this._btnName.checked = false;
350 }
352 if (sortBy == "updateDate") {
353 this._btnDate.checkState = checkState;
354 this._btnDate.checked = true;
355 } else {
356 this._btnDate.checkState = 0;
357 this._btnDate.checked = false;
358 }
360 if (sortBy == "purchaseAmount") {
361 this._btnPrice.checkState = checkState;
362 this._btnPrice.checked = true;
363 } else {
364 this._btnPrice.checkState = 0;
365 this._btnPrice.checked = false;
366 }
368 if (sortBy == "relevancescore") {
369 this._btnRelevance.checkState = checkState;
370 this._btnRelevance.checked = true;
371 } else {
372 this._btnRelevance.checkState = 0;
373 this._btnRelevance.checked = false;
374 }
376 if (this.handler && "onSortChanged" in this.handler)
377 this.handler.onSortChanged(sortBy, this.ascending);
378 ]]></body>
379 </method>
380 </implementation>
381 </binding>
384 <!-- Categories list - displays the list of categories on the left pane. -->
385 <binding id="categories-list"
386 extends="chrome://global/content/bindings/richlistbox.xml#richlistbox">
387 <implementation>
388 <!-- This needs to be overridden to allow the fancy animation while not
389 allowing that item to be selected when hiding. -->
390 <method name="_canUserSelect">
391 <parameter name="aItem"/>
392 <body>
393 <![CDATA[
394 if (aItem.hasAttribute("disabled") &&
395 aItem.getAttribute("disabled") == "true")
396 return false;
397 var style = document.defaultView.getComputedStyle(aItem, "");
398 return style.display != "none" && style.visibility == "visible";
399 ]]>
400 </body>
401 </method>
402 </implementation>
403 </binding>
406 <!-- Category item - an item in the category list. -->
407 <binding id="category"
408 extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
409 <content align="center">
410 <xul:image anonid="icon" class="category-icon"/>
411 <xul:label anonid="name" class="category-name" flex="1" xbl:inherits="value=name"/>
412 <xul:label anonid="badge" class="category-badge" xbl:inherits="value=count"/>
413 </content>
415 <implementation>
416 <constructor><![CDATA[
417 if (!this.hasAttribute("count"))
418 this.setAttribute("count", 0);
419 ]]></constructor>
421 <property name="badgeCount">
422 <getter><![CDATA[
423 return this.getAttribute("count");
424 ]]></getter>
425 <setter><![CDATA[
426 if (this.getAttribute("count") == val)
427 return;
429 this.setAttribute("count", val);
430 var event = document.createEvent("Events");
431 event.initEvent("CategoryBadgeUpdated", true, true);
432 this.dispatchEvent(event);
433 ]]></setter>
434 </property>
435 </implementation>
436 </binding>
439 <!-- Creator link - Name of a user/developer, providing a link if relevant. -->
440 <binding id="creator-link">
441 <content>
442 <xul:label anonid="label" value="&addon.createdBy.label;"/>
443 <xul:label anonid="creator-link" class="creator-link text-link"/>
444 <xul:label anonid="creator-name" class="creator-name"/>
445 </content>
447 <implementation>
448 <constructor><![CDATA[
449 if (this.hasAttribute("nameonly") &&
450 this.getAttribute("nameonly") == "true") {
451 this._label.hidden = true;
452 }
453 ]]></constructor>
455 <field name="_label">
456 document.getAnonymousElementByAttribute(this, "anonid", "label");
457 </field>
458 <field name="_creatorLink">
459 document.getAnonymousElementByAttribute(this, "anonid", "creator-link");
460 </field>
461 <field name="_creatorName">
462 document.getAnonymousElementByAttribute(this, "anonid", "creator-name");
463 </field>
465 <method name="setCreator">
466 <parameter name="aCreator"/>
467 <parameter name="aHomepageURL"/>
468 <body><![CDATA[
469 if (!aCreator) {
470 this.collapsed = true;
471 return;
472 }
473 this.collapsed = false;
474 var url = aCreator.url || aHomepageURL;
475 var showLink = !!url;
476 if (showLink) {
477 this._creatorLink.value = aCreator.name;
478 this._creatorLink.href = url;
479 } else {
480 this._creatorName.value = aCreator.name;
481 }
482 this._creatorLink.hidden = !showLink;
483 this._creatorName.hidden = showLink;
484 ]]></body>
485 </method>
486 </implementation>
487 </binding>
490 <!-- Install status - Displays the status of an install/upgrade. -->
491 <binding id="install-status">
492 <content>
493 <xul:label anonid="message"/>
494 <xul:progressmeter anonid="progress" class="download-progress"/>
495 <xul:button anonid="purchase-remote-btn" hidden="true"
496 class="addon-control"
497 oncommand="document.getBindingParent(this).purchaseRemote();"/>
498 <xul:button anonid="install-remote-btn" hidden="true"
499 class="addon-control install" label="&addon.install.label;"
500 tooltiptext="&addon.install.tooltip;"
501 oncommand="document.getBindingParent(this).installRemote();"/>
502 </content>
504 <implementation>
505 <constructor><![CDATA[
506 if (this.mInstall)
507 this.initWithInstall(this.mInstall);
508 else if (this.mControl.mAddon.install)
509 this.initWithInstall(this.mControl.mAddon.install);
510 else
511 this.refreshState();
512 ]]></constructor>
514 <destructor><![CDATA[
515 if (this.mInstall)
516 this.mInstall.removeListener(this);
517 ]]></destructor>
519 <field name="_message">
520 document.getAnonymousElementByAttribute(this, "anonid", "message");
521 </field>
522 <field name="_progress">
523 document.getAnonymousElementByAttribute(this, "anonid", "progress");
524 </field>
525 <field name="_purchaseRemote">
526 document.getAnonymousElementByAttribute(this, "anonid",
527 "purchase-remote-btn");
528 </field>
529 <field name="_installRemote">
530 document.getAnonymousElementByAttribute(this, "anonid",
531 "install-remote-btn");
532 </field>
533 <field name="_restartNeeded">
534 document.getAnonymousElementByAttribute(this, "anonid",
535 "restart-needed");
536 </field>
537 <field name="_undo">
538 document.getAnonymousElementByAttribute(this, "anonid",
539 "undo-btn");
540 </field>
542 <method name="initWithInstall">
543 <parameter name="aInstall"/>
544 <body><![CDATA[
545 if (this.mInstall) {
546 this.mInstall.removeListener(this);
547 this.mInstall = null;
548 }
549 this.mInstall = aInstall;
550 this._progress.mInstall = aInstall;
551 this.refreshState();
552 this.mInstall.addListener(this);
553 ]]></body>
554 </method>
556 <method name="refreshState">
557 <body><![CDATA[
558 var showInstallRemote = false;
559 var showPurchase = false;
561 if (this.mInstall) {
563 switch (this.mInstall.state) {
564 case AddonManager.STATE_AVAILABLE:
565 if (this.mControl.getAttribute("remote") != "true")
566 break;
568 this._progress.hidden = true;
569 showInstallRemote = true;
570 break;
571 case AddonManager.STATE_DOWNLOADING:
572 this.showMessage("installDownloading");
573 break;
574 case AddonManager.STATE_CHECKING:
575 this.showMessage("installVerifying");
576 break;
577 case AddonManager.STATE_DOWNLOADED:
578 this.showMessage("installDownloaded");
579 break;
580 case AddonManager.STATE_DOWNLOAD_FAILED:
581 // XXXunf expose what error occured (bug 553487)
582 this.showMessage("installDownloadFailed", true);
583 break;
584 case AddonManager.STATE_INSTALLING:
585 this.showMessage("installInstalling");
586 break;
587 case AddonManager.STATE_INSTALL_FAILED:
588 // XXXunf expose what error occured (bug 553487)
589 this.showMessage("installFailed", true);
590 break;
591 case AddonManager.STATE_CANCELLED:
592 this.showMessage("installCancelled", true);
593 break;
594 }
596 } else if (this.mControl.mAddon.purchaseURL) {
597 this._progress.hidden = true;
598 showPurchase = true;
599 this._purchaseRemote.label =
600 gStrings.ext.formatStringFromName("addon.purchase.label",
601 [this.mControl.mAddon.purchaseDisplayAmount], 1);
602 this._purchaseRemote.tooltiptext =
603 gStrings.ext.GetStringFromName("addon.purchase.tooltip");
604 }
606 this._purchaseRemote.hidden = !showPurchase;
607 this._installRemote.hidden = !showInstallRemote;
609 if ("refreshInfo" in this.mControl)
610 this.mControl.refreshInfo();
611 ]]></body>
612 </method>
614 <method name="showMessage">
615 <parameter name="aMsgId"/>
616 <parameter name="aHideProgress"/>
617 <body><![CDATA[
618 this._message.setAttribute("hidden", !aHideProgress);
619 this._progress.setAttribute("hidden", !!aHideProgress);
621 var msg = gStrings.ext.GetStringFromName(aMsgId);
622 if (aHideProgress)
623 this._message.value = msg;
624 else
625 this._progress.status = msg;
626 ]]></body>
627 </method>
629 <method name="purchaseRemote">
630 <body><![CDATA[
631 openURL(this.mControl.mAddon.purchaseURL);
632 ]]></body>
633 </method>
635 <method name="installRemote">
636 <body><![CDATA[
637 if (this.mControl.getAttribute("remote") != "true")
638 return;
640 if (this.mControl.mAddon.eula) {
641 var data = {
642 addon: this.mControl.mAddon,
643 accepted: false
644 };
645 window.openDialog("chrome://mozapps/content/extensions/eula.xul", "_blank",
646 "chrome,dialog,modal,centerscreen,resizable=no", data);
647 if (!data.accepted)
648 return;
649 }
651 delete this.mControl.mAddon;
652 this.mControl.mInstall = this.mInstall;
653 this.mControl.setAttribute("status", "installing");
654 this.mInstall.install();
655 ]]></body>
656 </method>
658 <method name="undoAction">
659 <body><![CDATA[
660 if (!this.mAddon)
661 return;
662 var pending = this.mAddon.pendingOperations;
663 if (pending & AddonManager.PENDING_ENABLE)
664 this.mAddon.userDisabled = true;
665 else if (pending & AddonManager.PENDING_DISABLE)
666 this.mAddon.userDisabled = false;
667 this.refreshState();
668 ]]></body>
669 </method>
671 <method name="onDownloadStarted">
672 <body><![CDATA[
673 this.refreshState();
674 ]]></body>
675 </method>
677 <method name="onDownloadEnded">
678 <body><![CDATA[
679 this.refreshState();
680 ]]></body>
681 </method>
683 <method name="onDownloadFailed">
684 <body><![CDATA[
685 this.refreshState();
686 ]]></body>
687 </method>
689 <method name="onDownloadProgress">
690 <body><![CDATA[
691 this._progress.maxProgress = this.mInstall.maxProgress;
692 this._progress.progress = this.mInstall.progress;
693 ]]></body>
694 </method>
696 <method name="onInstallStarted">
697 <body><![CDATA[
698 this._progress.progress = 0;
699 this.refreshState();
700 ]]></body>
701 </method>
703 <method name="onInstallEnded">
704 <body><![CDATA[
705 this.refreshState();
706 if ("onInstallCompleted" in this.mControl)
707 this.mControl.onInstallCompleted();
708 ]]></body>
709 </method>
711 <method name="onInstallFailed">
712 <body><![CDATA[
713 this.refreshState();
714 ]]></body>
715 </method>
716 </implementation>
717 </binding>
720 <!-- Addon - base - parent binding of any item representing an addon. -->
721 <binding id="addon-base"
722 extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
723 <implementation>
724 <method name="hasPermission">
725 <parameter name="aPerm"/>
726 <body><![CDATA[
727 var perm = AddonManager["PERM_CAN_" + aPerm.toUpperCase()];
728 return !!(this.mAddon.permissions & perm);
729 ]]></body>
730 </method>
732 <method name="opRequiresRestart">
733 <parameter name="aOperation"/>
734 <body><![CDATA[
735 var operation = AddonManager["OP_NEEDS_RESTART_" + aOperation.toUpperCase()];
736 return !!(this.mAddon.operationsRequiringRestart & operation);
737 ]]></body>
738 </method>
740 <method name="isPending">
741 <parameter name="aAction"/>
742 <body><![CDATA[
743 var action = AddonManager["PENDING_" + aAction.toUpperCase()];
744 return !!(this.mAddon.pendingOperations & action);
745 ]]></body>
746 </method>
748 <method name="onUninstalled">
749 <body><![CDATA[
750 this.parentNode.removeChild(this);
751 ]]></body>
752 </method>
753 </implementation>
754 </binding>
757 <!-- Addon - generic - A normal addon item, or an update to one -->
758 <binding id="addon-generic"
759 extends="chrome://mozapps/content/extensions/extensions.xml#addon-base">
760 <content>
761 <xul:hbox anonid="warning-container"
762 class="warning">
763 <xul:image class="warning-icon"/>
764 <xul:label anonid="warning" flex="1"/>
765 <xul:label anonid="warning-link" class="text-link"/>
766 <xul:button anonid="warning-btn" class="button-link"/>
767 <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
768 </xul:hbox>
769 <xul:hbox anonid="error-container"
770 class="error">
771 <xul:image class="error-icon"/>
772 <xul:label anonid="error" flex="1"/>
773 <xul:label anonid="error-link" class="text-link"/>
774 <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
775 </xul:hbox>
776 <xul:hbox anonid="pending-container"
777 class="pending">
778 <xul:image class="pending-icon"/>
779 <xul:label anonid="pending" flex="1"/>
780 <xul:button anonid="restart-btn" class="button-link"
781 label="&addon.restartNow.label;"
782 oncommand="document.getBindingParent(this).restart();"/>
783 <xul:button anonid="undo-btn" class="button-link"
784 label="&addon.undoAction.label;"
785 tooltipText="&addon.undoAction.tooltip;"
786 oncommand="document.getBindingParent(this).undo();"/>
787 <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
788 </xul:hbox>
790 <xul:hbox class="content-container">
791 <xul:vbox class="icon-container">
792 <xul:image anonid="icon" class="icon"/>
793 </xul:vbox>
794 <xul:vbox class="content-inner-container" flex="1">
795 <xul:hbox class="basicinfo-container">
796 <xul:hbox class="name-container">
797 <xul:label anonid="name" class="name" crop="end" flex="1"
798 xbl:inherits="value=name,tooltiptext=name"/>
799 <xul:label anonid="version" class="version"/>
800 <xul:label class="disabled-postfix" value="&addon.disabled.postfix;"/>
801 <xul:label class="update-postfix" value="&addon.update.postfix;"/>
802 <xul:spacer flex="5000"/> <!-- Necessary to make the name crop -->
803 </xul:hbox>
804 <xul:label anonid="date-updated" class="date-updated"
805 unknown="&addon.unknownDate;"/>
806 </xul:hbox>
807 <xul:hbox class="experiment-container">
808 <svg width="6" height="6" viewBox="0 0 6 6" version="1.1"
809 xmlns="http://www.w3.org/2000/svg"
810 class="experiment-bullet-container">
811 <circle cx="3" cy="3" r="3" class="experiment-bullet"/>
812 </svg>
813 <xul:label anonid="experiment-state" class="experiment-state"/>
814 <xul:label anonid="experiment-time" class="experiment-time"/>
815 </xul:hbox>
817 <xul:hbox class="advancedinfo-container" flex="1">
818 <xul:vbox class="description-outer-container" flex="1">
819 <xul:hbox class="description-container">
820 <xul:label anonid="description" class="description" crop="end" flex="1"/>
821 <xul:button anonid="details-btn" class="details button-link"
822 label="&addon.details.label;"
823 tooltiptext="&addon.details.tooltip;"
824 oncommand="document.getBindingParent(this).showInDetailView();"/>
825 <xul:spacer flex="5000"/> <!-- Necessary to make the description crop -->
826 </xul:hbox>
827 <xul:vbox anonid="relnotes-container" class="relnotes-container">
828 <xul:label class="relnotes-header" value="&addon.releaseNotes.label;"/>
829 <xul:label anonid="relnotes-loading" value="&addon.loadingReleaseNotes.label;"/>
830 <xul:label anonid="relnotes-error" hidden="true"
831 value="&addon.errorLoadingReleaseNotes.label;"/>
832 <xul:vbox anonid="relnotes" class="relnotes"/>
833 </xul:vbox>
834 <xul:hbox class="relnotes-toggle-container">
835 <xul:button anonid="relnotes-toggle-btn" class="relnotes-toggle"
836 hidden="true" label="&cmd.showReleaseNotes.label;"
837 tooltiptext="&cmd.showReleaseNotes.tooltip;"
838 showlabel="&cmd.showReleaseNotes.label;"
839 showtooltip="&cmd.showReleaseNotes.tooltip;"
840 hidelabel="&cmd.hideReleaseNotes.label;"
841 hidetooltip="&cmd.hideReleaseNotes.tooltip;"
842 oncommand="document.getBindingParent(this).toggleReleaseNotes();"/>
843 </xul:hbox>
844 </xul:vbox>
845 <xul:vbox class="status-control-wrapper">
846 <xul:hbox class="status-container">
847 <xul:hbox anonid="checking-update" hidden="true">
848 <xul:image class="spinner"/>
849 <xul:label value="&addon.checkingForUpdates.label;"/>
850 </xul:hbox>
851 <xul:vbox anonid="update-available" class="update-available"
852 hidden="true">
853 <xul:checkbox anonid="include-update" class="include-update"
854 label="&addon.includeUpdate.label;" checked="true"
855 oncommand="document.getBindingParent(this).onIncludeUpdateChanged();"/>
856 <xul:hbox class="update-info-container">
857 <xul:label class="update-available-notice"
858 value="&addon.updateAvailable.label;"/>
859 <xul:button anonid="update-btn" class="addon-control update"
860 label="&addon.updateNow.label;"
861 tooltiptext="&addon.updateNow.tooltip;"
862 oncommand="document.getBindingParent(this).upgrade();"/>
863 </xul:hbox>
864 </xul:vbox>
865 <xul:hbox anonid="install-status" class="install-status"
866 hidden="true"/>
867 </xul:hbox>
868 <xul:hbox anonid="control-container" class="control-container">
869 <xul:button anonid="preferences-btn"
870 class="addon-control preferences"
871 #ifdef XP_WIN
872 label="&cmd.showPreferencesWin.label;"
873 tooltiptext="&cmd.showPreferencesWin.tooltip;"
874 #else
875 label="&cmd.showPreferencesUnix.label;"
876 tooltiptext="&cmd.showPreferencesUnix.tooltip;"
877 #endif
878 oncommand="document.getBindingParent(this).showPreferences();"/>
879 <!-- label="&cmd.debugAddon.label;" -->
880 <xul:button anonid="debug-btn" class="addon-control debug"
881 label="&cmd.debugAddon.label;"
882 oncommand="document.getBindingParent(this).debug();"/>
884 <xul:button anonid="enable-btn" class="addon-control enable"
885 label="&cmd.enableAddon.label;"
886 oncommand="document.getBindingParent(this).userDisabled = false;"/>
887 <xul:button anonid="disable-btn" class="addon-control disable"
888 label="&cmd.disableAddon.label;"
889 oncommand="document.getBindingParent(this).userDisabled = true;"/>
890 <xul:button anonid="remove-btn" class="addon-control remove"
891 label="&cmd.uninstallAddon.label;"
892 oncommand="document.getBindingParent(this).uninstall();"/>
893 <xul:menulist anonid="state-menulist"
894 class="addon-control state"
895 tooltiptext="&cmd.stateMenu.tooltip;">
896 <xul:menupopup>
897 <xul:menuitem anonid="ask-to-activate-menuitem"
898 class="addon-control"
899 label="&cmd.askToActivate.label;"
900 tooltiptext="&cmd.askToActivate.tooltip;"
901 oncommand="document.getBindingParent(this).userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE;"/>
902 <xul:menuitem anonid="always-activate-menuitem"
903 class="addon-control"
904 label="&cmd.alwaysActivate.label;"
905 tooltiptext="&cmd.alwaysActivate.tooltip;"
906 oncommand="document.getBindingParent(this).userDisabled = false;"/>
907 <xul:menuitem anonid="never-activate-menuitem"
908 class="addon-control"
909 label="&cmd.neverActivate.label;"
910 tooltiptext="&cmd.neverActivate.tooltip;"
911 oncommand="document.getBindingParent(this).userDisabled = true;"/>
912 </xul:menupopup>
913 </xul:menulist>
914 </xul:hbox>
915 </xul:vbox>
916 </xul:hbox>
917 </xul:vbox>
918 </xul:hbox>
919 </content>
921 <implementation>
922 <constructor><![CDATA[
923 this._installStatus.mControl = this;
925 this.setAttribute("contextmenu", "addonitem-popup");
927 this._showStatus("none");
929 this._initWithAddon(this.mAddon);
931 gEventManager.registerAddonListener(this, this.mAddon.id);
932 ]]></constructor>
934 <destructor><![CDATA[
935 gEventManager.unregisterAddonListener(this, this.mAddon.id);
936 ]]></destructor>
938 <field name="_warningContainer">
939 document.getAnonymousElementByAttribute(this, "anonid",
940 "warning-container");
941 </field>
942 <field name="_warning">
943 document.getAnonymousElementByAttribute(this, "anonid",
944 "warning");
945 </field>
946 <field name="_warningLink">
947 document.getAnonymousElementByAttribute(this, "anonid",
948 "warning-link");
949 </field>
950 <field name="_warningBtn">
951 document.getAnonymousElementByAttribute(this, "anonid",
952 "warning-btn");
953 </field>
954 <field name="_errorContainer">
955 document.getAnonymousElementByAttribute(this, "anonid",
956 "error-container");
957 </field>
958 <field name="_error">
959 document.getAnonymousElementByAttribute(this, "anonid",
960 "error");
961 </field>
962 <field name="_errorLink">
963 document.getAnonymousElementByAttribute(this, "anonid",
964 "error-link");
965 </field>
966 <field name="_pendingContainer">
967 document.getAnonymousElementByAttribute(this, "anonid",
968 "pending-container");
969 </field>
970 <field name="_pending">
971 document.getAnonymousElementByAttribute(this, "anonid",
972 "pending");
973 </field>
974 <field name="_infoContainer">
975 document.getAnonymousElementByAttribute(this, "anonid",
976 "info-container");
977 </field>
978 <field name="_info">
979 document.getAnonymousElementByAttribute(this, "anonid",
980 "info");
981 </field>
982 <field name="_version">
983 document.getAnonymousElementByAttribute(this, "anonid", "version");
984 </field>
985 <field name="_experimentState">
986 document.getAnonymousElementByAttribute(this, "anonid", "experiment-state");
987 </field>
988 <field name="_experimentTime">
989 document.getAnonymousElementByAttribute(this, "anonid", "experiment-time");
990 </field>
991 <field name="_icon">
992 document.getAnonymousElementByAttribute(this, "anonid", "icon");
993 </field>
994 <field name="_dateUpdated">
995 document.getAnonymousElementByAttribute(this, "anonid",
996 "date-updated");
997 </field>
998 <field name="_description">
999 document.getAnonymousElementByAttribute(this, "anonid",
1000 "description");
1001 </field>
1002 <field name="_stateMenulist">
1003 document.getAnonymousElementByAttribute(this, "anonid",
1004 "state-menulist");
1005 </field>
1006 <field name="_askToActivateMenuitem">
1007 document.getAnonymousElementByAttribute(this, "anonid",
1008 "ask-to-activate-menuitem");
1009 </field>
1010 <field name="_alwaysActivateMenuitem">
1011 document.getAnonymousElementByAttribute(this, "anonid",
1012 "always-activate-menuitem");
1013 </field>
1014 <field name="_neverActivateMenuitem">
1015 document.getAnonymousElementByAttribute(this, "anonid",
1016 "never-activate-menuitem");
1017 </field>
1018 <field name="_preferencesBtn">
1019 document.getAnonymousElementByAttribute(this, "anonid",
1020 "preferences-btn");
1021 </field>
1022 <field name="_enableBtn">
1023 document.getAnonymousElementByAttribute(this, "anonid",
1024 "enable-btn");
1025 </field>
1026 <field name="_debugBtn">
1027 document.getAnonymousElementByAttribute(this, "anonid",
1028 "debug-btn");
1029 </field>
1030 <field name="_disableBtn">
1031 document.getAnonymousElementByAttribute(this, "anonid",
1032 "disable-btn");
1033 </field>
1034 <field name="_removeBtn">
1035 document.getAnonymousElementByAttribute(this, "anonid",
1036 "remove-btn");
1037 </field>
1038 <field name="_updateBtn">
1039 document.getAnonymousElementByAttribute(this, "anonid",
1040 "update-btn");
1041 </field>
1042 <field name="_controlContainer">
1043 document.getAnonymousElementByAttribute(this, "anonid",
1044 "control-container");
1045 </field>
1046 <field name="_installStatus">
1047 document.getAnonymousElementByAttribute(this, "anonid",
1048 "install-status");
1049 </field>
1050 <field name="_checkingUpdate">
1051 document.getAnonymousElementByAttribute(this, "anonid",
1052 "checking-update");
1053 </field>
1054 <field name="_updateAvailable">
1055 document.getAnonymousElementByAttribute(this, "anonid",
1056 "update-available");
1057 </field>
1058 <field name="_includeUpdate">
1059 document.getAnonymousElementByAttribute(this, "anonid",
1060 "include-update");
1061 </field>
1062 <field name="_relNotesLoaded">false</field>
1063 <field name="_relNotesToggle">
1064 document.getAnonymousElementByAttribute(this, "anonid",
1065 "relnotes-toggle-btn");
1066 </field>
1067 <field name="_relNotesLoading">
1068 document.getAnonymousElementByAttribute(this, "anonid",
1069 "relnotes-loading");
1070 </field>
1071 <field name="_relNotesError">
1072 document.getAnonymousElementByAttribute(this, "anonid",
1073 "relnotes-error");
1074 </field>
1075 <field name="_relNotesContainer">
1076 document.getAnonymousElementByAttribute(this, "anonid",
1077 "relnotes-container");
1078 </field>
1079 <field name="_relNotes">
1080 document.getAnonymousElementByAttribute(this, "anonid",
1081 "relnotes");
1082 </field>
1084 <property name="userDisabled">
1085 <getter><![CDATA[
1086 return this.mAddon.userDisabled;
1087 ]]></getter>
1088 <setter><![CDATA[
1089 this.mAddon.userDisabled = val;
1090 ]]></setter>
1091 </property>
1093 <property name="includeUpdate">
1094 <getter><![CDATA[
1095 return this._includeUpdate.checked && !!this.mManualUpdate;
1096 ]]></getter>
1097 <setter><![CDATA[
1098 //XXXunf Eventually, we'll want to persist this for individual
1099 // updates - see bug 594619.
1100 this._includeUpdate.checked = !!val;
1101 ]]></setter>
1102 </property>
1104 <method name="_initWithAddon">
1105 <parameter name="aAddon"/>
1106 <body><![CDATA[
1107 this.mAddon = aAddon;
1109 this._installStatus.mAddon = this.mAddon;
1110 this._updateDates();
1111 this._updateState();
1113 this.setAttribute("name", aAddon.name);
1115 var iconURL = this.mAddon.iconURL;
1116 if (iconURL)
1117 this._icon.src = iconURL;
1118 else
1119 this._icon.src = "";
1121 if (shouldShowVersionNumber(this.mAddon))
1122 this._version.value = this.mAddon.version;
1123 else
1124 this._version.hidden = true;
1126 if (this.mAddon.description)
1127 this._description.value = this.mAddon.description;
1128 else
1129 this._description.hidden = true;
1131 if (!("applyBackgroundUpdates" in this.mAddon) ||
1132 (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE ||
1133 (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT &&
1134 !AddonManager.autoUpdateDefault))) {
1135 var self = this;
1136 AddonManager.getAllInstalls(function(aInstallsList) {
1137 // This can return after the binding has been destroyed,
1138 // so try to detect that and return early
1139 if (!("onNewInstall" in self))
1140 return;
1141 for (let install of aInstallsList) {
1142 if (install.existingAddon &&
1143 install.existingAddon.id == self.mAddon.id &&
1144 install.state == AddonManager.STATE_AVAILABLE) {
1145 self.onNewInstall(install);
1146 self.onIncludeUpdateChanged();
1147 }
1148 }
1149 });
1150 }
1151 ]]></body>
1152 </method>
1154 <method name="_showStatus">
1155 <parameter name="aType"/>
1156 <body><![CDATA[
1157 this._controlContainer.hidden = aType != "none" &&
1158 !(aType == "update-available" && !this.hasAttribute("upgrade"));
1160 this._installStatus.hidden = aType != "progress";
1161 if (aType == "progress")
1162 this._installStatus.refreshState();
1163 this._checkingUpdate.hidden = aType != "checking-update";
1164 this._updateAvailable.hidden = aType != "update-available";
1165 this._relNotesToggle.hidden = !(this.mManualUpdate ?
1166 this.mManualUpdate.releaseNotesURI :
1167 this.mAddon.releaseNotesURI);
1168 ]]></body>
1169 </method>
1171 <method name="_updateDates">
1172 <body><![CDATA[
1173 function formatDate(aDate) {
1174 return Cc["@mozilla.org/intl/scriptabledateformat;1"]
1175 .getService(Ci.nsIScriptableDateFormat)
1176 .FormatDate("",
1177 Ci.nsIScriptableDateFormat.dateFormatLong,
1178 aDate.getFullYear(),
1179 aDate.getMonth() + 1,
1180 aDate.getDate()
1181 );
1182 }
1184 if (this.mAddon.updateDate)
1185 this._dateUpdated.value = formatDate(this.mAddon.updateDate);
1186 else
1187 this._dateUpdated.value = this._dateUpdated.getAttribute("unknown");
1188 ]]></body>
1189 </method>
1191 <method name="_updateState">
1192 <body><![CDATA[
1193 if (this.parentNode.selectedItem == this)
1194 gViewController.updateCommands();
1196 var pending = this.mAddon.pendingOperations;
1197 if (pending != AddonManager.PENDING_NONE) {
1198 this.removeAttribute("notification");
1200 var pending = null;
1201 const PENDING_OPERATIONS = ["enable", "disable", "install",
1202 "uninstall", "upgrade"];
1203 for (let op of PENDING_OPERATIONS) {
1204 if (this.isPending(op))
1205 pending = op;
1206 }
1208 this.setAttribute("pending", pending);
1209 this._pending.textContent = gStrings.ext.formatStringFromName(
1210 "notification." + pending,
1211 [this.mAddon.name, gStrings.brandShortName], 2
1212 );
1213 } else {
1214 this.removeAttribute("pending");
1216 var isUpgrade = this.hasAttribute("upgrade");
1217 var install = this._installStatus.mInstall;
1219 if (install && install.state == AddonManager.STATE_DOWNLOAD_FAILED) {
1220 this.setAttribute("notification", "warning");
1221 this._warning.textContent = gStrings.ext.formatStringFromName(
1222 "notification.downloadError",
1223 [this.mAddon.name], 1
1224 );
1225 this._warningBtn.label = gStrings.ext.GetStringFromName("notification.downloadError.retry");
1226 this._warningBtn.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
1227 this._warningBtn.setAttribute("oncommand", "document.getBindingParent(this).retryInstall();");
1228 this._warningBtn.hidden = false;
1229 this._warningLink.hidden = true;
1230 } else if (install && install.state == AddonManager.STATE_INSTALL_FAILED) {
1231 this.setAttribute("notification", "warning");
1232 this._warning.textContent = gStrings.ext.formatStringFromName(
1233 "notification.installError",
1234 [this.mAddon.name], 1
1235 );
1236 this._warningBtn.label = gStrings.ext.GetStringFromName("notification.installError.retry");
1237 this._warningBtn.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
1238 this._warningBtn.setAttribute("oncommand", "document.getBindingParent(this).retryInstall();");
1239 this._warningBtn.hidden = false;
1240 this._warningLink.hidden = true;
1241 } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) {
1242 this.setAttribute("notification", "error");
1243 this._error.textContent = gStrings.ext.formatStringFromName(
1244 "notification.blocked",
1245 [this.mAddon.name], 1
1246 );
1247 this._errorLink.value = gStrings.ext.GetStringFromName("notification.blocked.link");
1248 this._errorLink.href = this.mAddon.blocklistURL;
1249 this._errorLink.hidden = false;
1250 } else if ((!isUpgrade && !this.mAddon.isCompatible) && (AddonManager.checkCompatibility
1251 || (this.mAddon.blocklistState != Ci.nsIBlocklistService.STATE_SOFTBLOCKED))) {
1252 this.setAttribute("notification", "warning");
1253 this._warning.textContent = gStrings.ext.formatStringFromName(
1254 "notification.incompatible",
1255 [this.mAddon.name, gStrings.brandShortName, gStrings.appVersion], 3
1256 );
1257 this._warningLink.hidden = true;
1258 this._warningBtn.hidden = true;
1259 } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) {
1260 this.setAttribute("notification", "warning");
1261 this._warning.textContent = gStrings.ext.formatStringFromName(
1262 "notification.softblocked",
1263 [this.mAddon.name], 1
1264 );
1265 this._warningLink.value = gStrings.ext.GetStringFromName("notification.softblocked.link");
1266 this._warningLink.href = this.mAddon.blocklistURL;
1267 this._warningLink.hidden = false;
1268 this._warningBtn.hidden = true;
1269 } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
1270 this.setAttribute("notification", "warning");
1271 this._warning.textContent = gStrings.ext.formatStringFromName(
1272 "notification.outdated",
1273 [this.mAddon.name], 1
1274 );
1275 this._warningLink.value = gStrings.ext.GetStringFromName("notification.outdated.link");
1276 this._warningLink.href = Services.urlFormatter.formatURLPref("plugins.update.url");
1277 this._warningLink.hidden = false;
1278 this._warningBtn.hidden = true;
1279 } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) {
1280 this.setAttribute("notification", "error");
1281 this._error.textContent = gStrings.ext.formatStringFromName(
1282 "notification.vulnerableUpdatable",
1283 [this.mAddon.name], 1
1284 );
1285 this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableUpdatable.link");
1286 this._errorLink.href = this.mAddon.blocklistURL;
1287 this._errorLink.hidden = false;
1288 } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE) {
1289 this.setAttribute("notification", "error");
1290 this._error.textContent = gStrings.ext.formatStringFromName(
1291 "notification.vulnerableNoUpdate",
1292 [this.mAddon.name], 1
1293 );
1294 this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableNoUpdate.link");
1295 this._errorLink.href = this.mAddon.blocklistURL;
1296 this._errorLink.hidden = false;
1297 } else {
1298 this.removeAttribute("notification");
1299 }
1300 }
1302 this._preferencesBtn.hidden = (!this.mAddon.optionsURL) ||
1303 this.mAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO;
1305 let addonType = AddonManager.addonTypes[this.mAddon.type];
1306 if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE &&
1307 (this.hasPermission("ask_to_activate") ||
1308 this.hasPermission("enable") ||
1309 this.hasPermission("disable"))) {
1310 this._enableBtn.disabled = true;
1311 this._disableBtn.disabled = true;
1312 this._askToActivateMenuitem.disabled = !this.hasPermission("ask_to_activate");
1313 this._alwaysActivateMenuitem.disabled = !this.hasPermission("enable");
1314 this._neverActivateMenuitem.disabled = !this.hasPermission("disable");
1315 if (this.mAddon.userDisabled === true) {
1316 this._stateMenulist.selectedItem = this._neverActivateMenuitem;
1317 } else if (this.mAddon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) {
1318 this._stateMenulist.selectedItem = this._askToActivateMenuitem;
1319 } else {
1320 this._stateMenulist.selectedItem = this._alwaysActivateMenuitem;
1321 }
1322 this._stateMenulist.selectedItem.disabled = false;
1323 this._stateMenulist.disabled = false;
1324 } else {
1325 this._stateMenulist.disabled = true;
1326 if (this.hasPermission("enable")) {
1327 this._enableBtn.hidden = false;
1328 let tooltip = gViewController.commands["cmd_enableItem"]
1329 .getTooltip(this.mAddon);
1330 this._enableBtn.setAttribute("tooltiptext", tooltip);
1331 } else {
1332 this._enableBtn.hidden = true;
1333 }
1335 if (this.hasPermission("disable")) {
1336 this._disableBtn.hidden = false;
1337 let tooltip = gViewController.commands["cmd_disableItem"]
1338 .getTooltip(this.mAddon);
1339 this._disableBtn.setAttribute("tooltiptext", tooltip);
1340 } else {
1341 this._disableBtn.hidden = true;
1342 }
1343 }
1345 if (this.hasPermission("uninstall")) {
1346 this._removeBtn.hidden = false;
1347 let tooltip = gViewController.commands["cmd_uninstallItem"]
1348 .getTooltip(this.mAddon);
1349 this._removeBtn.setAttribute("tooltiptext", tooltip);
1350 } else {
1351 this._removeBtn.hidden = true;
1352 }
1354 this.setAttribute("active", this.mAddon.isActive);
1356 var showProgress = this.mAddon.purchaseURL || (this.mAddon.install &&
1357 this.mAddon.install.state != AddonManager.STATE_INSTALLED);
1358 this._showStatus(showProgress ? "progress" : "none");
1360 let debuggable = this.mAddon.isDebuggable &&
1361 Services.prefs.getBoolPref('devtools.chrome.enabled') &&
1362 Services.prefs.getBoolPref('devtools.debugger.remote-enabled');
1364 this._debugBtn.disabled = this._debugBtn.hidden = !debuggable
1366 if (this.mAddon.type == "experiment") {
1367 this.removeAttribute("notification");
1368 let prefix = "experiment.";
1369 let active = this.mAddon.isActive;
1371 if (!showProgress) {
1372 let stateKey = prefix + "state." + (active ? "active" : "complete");
1373 this._experimentState.value = gStrings.ext.GetStringFromName(stateKey);
1375 let now = Date.now();
1376 let end = this.endDate;
1377 let days = Math.abs(end - now) / (24 * 60 * 60 * 1000);
1379 let timeKey = prefix + "time.";
1380 let timeMessage;
1382 if (days < 1) {
1383 timeKey += (active ? "endsToday" : "endedToday");
1384 timeMessage = gStrings.ext.GetStringFromName(timeKey);
1385 } else {
1386 timeKey += (active ? "daysRemaining" : "daysPassed");
1387 days = Math.round(days);
1388 let timeString = gStrings.ext.GetStringFromName(timeKey);
1389 timeMessage = PluralForm.get(days, timeString)
1390 .replace("#1", days);
1391 }
1393 this._experimentTime.value = timeMessage;
1394 }
1395 }
1396 ]]></body>
1397 </method>
1399 <method name="_updateUpgradeInfo">
1400 <body><![CDATA[
1401 // Only update the version string if we're displaying the upgrade info
1402 if (this.hasAttribute("upgrade") && shouldShowVersionNumber(this.mAddon))
1403 this._version.value = this.mManualUpdate.version;
1404 ]]></body>
1405 </method>
1407 <method name="_fetchReleaseNotes">
1408 <parameter name="aURI"/>
1409 <body><![CDATA[
1410 var self = this;
1411 if (!aURI || this._relNotesLoaded) {
1412 sendToggleEvent();
1413 return;
1414 }
1416 var relNotesData = null, transformData = null;
1418 this._relNotesLoaded = true;
1419 this._relNotesLoading.hidden = false;
1420 this._relNotesError.hidden = true;
1422 function sendToggleEvent() {
1423 var event = document.createEvent("Events");
1424 event.initEvent("RelNotesToggle", true, true);
1425 self.dispatchEvent(event);
1426 }
1428 function showRelNotes() {
1429 if (!relNotesData || !transformData)
1430 return;
1432 self._relNotesLoading.hidden = true;
1434 var processor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"]
1435 .createInstance(Components.interfaces.nsIXSLTProcessor);
1436 processor.flags |= Components.interfaces.nsIXSLTProcessorPrivate.DISABLE_ALL_LOADS;
1438 processor.importStylesheet(transformData);
1439 var fragment = processor.transformToFragment(relNotesData, document);
1440 self._relNotes.appendChild(fragment);
1441 if (self.hasAttribute("show-relnotes")) {
1442 var container = self._relNotesContainer;
1443 container.style.height = container.scrollHeight + "px";
1444 }
1445 sendToggleEvent();
1446 }
1448 function handleError() {
1449 dataReq.abort();
1450 styleReq.abort();
1451 self._relNotesLoading.hidden = true;
1452 self._relNotesError.hidden = false;
1453 self._relNotesLoaded = false; // allow loading to be re-tried
1454 sendToggleEvent();
1455 }
1457 function handleResponse(aEvent) {
1458 var req = aEvent.target;
1459 var ct = req.getResponseHeader("content-type");
1460 if ((!ct || ct.indexOf("text/html") < 0) &&
1461 req.responseXML &&
1462 req.responseXML.documentElement.namespaceURI != XMLURI_PARSE_ERROR) {
1463 if (req == dataReq)
1464 relNotesData = req.responseXML;
1465 else
1466 transformData = req.responseXML;
1467 showRelNotes();
1468 } else {
1469 handleError();
1470 }
1471 }
1473 var dataReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
1474 .createInstance(Components.interfaces.nsIXMLHttpRequest);
1475 dataReq.open("GET", aURI.spec, true);
1476 dataReq.addEventListener("load", handleResponse, false);
1477 dataReq.addEventListener("error", handleError, false);
1478 dataReq.send(null);
1480 var styleReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
1481 .createInstance(Components.interfaces.nsIXMLHttpRequest);
1482 styleReq.open("GET", UPDATES_RELEASENOTES_TRANSFORMFILE, true);
1483 styleReq.addEventListener("load", handleResponse, false);
1484 styleReq.addEventListener("error", handleError, false);
1485 styleReq.send(null);
1486 ]]></body>
1487 </method>
1489 <method name="toggleReleaseNotes">
1490 <body><![CDATA[
1491 if (this.hasAttribute("show-relnotes")) {
1492 this._relNotesContainer.style.height = "0px";
1493 this.removeAttribute("show-relnotes");
1494 this._relNotesToggle.setAttribute(
1495 "label",
1496 this._relNotesToggle.getAttribute("showlabel")
1497 );
1498 this._relNotesToggle.setAttribute(
1499 "tooltiptext",
1500 this._relNotesToggle.getAttribute("showtooltip")
1501 );
1502 var event = document.createEvent("Events");
1503 event.initEvent("RelNotesToggle", true, true);
1504 this.dispatchEvent(event);
1505 } else {
1506 this._relNotesContainer.style.height = this._relNotesContainer.scrollHeight +
1507 "px";
1508 this.setAttribute("show-relnotes", true);
1509 this._relNotesToggle.setAttribute(
1510 "label",
1511 this._relNotesToggle.getAttribute("hidelabel")
1512 );
1513 this._relNotesToggle.setAttribute(
1514 "tooltiptext",
1515 this._relNotesToggle.getAttribute("hidetooltip")
1516 );
1517 var uri = this.mManualUpdate ?
1518 this.mManualUpdate.releaseNotesURI :
1519 this.mAddon.releaseNotesURI;
1520 this._fetchReleaseNotes(uri);
1521 }
1522 ]]></body>
1523 </method>
1525 <method name="restart">
1526 <body><![CDATA[
1527 gViewController.commands["cmd_restartApp"].doCommand();
1528 ]]></body>
1529 </method>
1531 <method name="undo">
1532 <body><![CDATA[
1533 gViewController.commands["cmd_cancelOperation"].doCommand(this.mAddon);
1534 ]]></body>
1535 </method>
1537 <method name="uninstall">
1538 <body><![CDATA[
1539 // If uninstalling does not require a restart then just disable it
1540 // and show the undo UI.
1541 if (!this.opRequiresRestart("uninstall")) {
1542 this.setAttribute("wasDisabled", this.mAddon.userDisabled);
1544 // We must set userDisabled to true first, this will call
1545 // _updateState which will clear any pending attribute set.
1546 this.mAddon.userDisabled = true;
1548 // This won't update any other add-on manager views (bug 582002)
1549 this.setAttribute("pending", "uninstall");
1550 } else {
1551 this.mAddon.uninstall();
1552 }
1553 ]]></body>
1554 </method>
1556 <method name="debug">
1557 <body><![CDATA[
1558 gViewController.doCommand("cmd_debugItem", this.mAddon);
1559 ]]></body>
1560 </method>
1562 <method name="showPreferences">
1563 <body><![CDATA[
1564 gViewController.doCommand("cmd_showItemPreferences", this.mAddon);
1565 ]]></body>
1566 </method>
1568 <method name="upgrade">
1569 <body><![CDATA[
1570 var install = this.mManualUpdate;
1571 delete this.mManualUpdate;
1572 install.install();
1573 ]]></body>
1574 </method>
1576 <method name="retryInstall">
1577 <body><![CDATA[
1578 var install = this._installStatus.mInstall;
1579 if (!install)
1580 return;
1581 if (install.state != AddonManager.STATE_DOWNLOAD_FAILED &&
1582 install.state != AddonManager.STATE_INSTALL_FAILED)
1583 return;
1584 install.install();
1585 ]]></body>
1586 </method>
1588 <method name="showInDetailView">
1589 <body><![CDATA[
1590 gViewController.loadView("addons://detail/" +
1591 encodeURIComponent(this.mAddon.id));
1592 ]]></body>
1593 </method>
1595 <method name="onIncludeUpdateChanged">
1596 <body><![CDATA[
1597 var event = document.createEvent("Events");
1598 event.initEvent("IncludeUpdateChanged", true, true);
1599 this.dispatchEvent(event);
1600 ]]></body>
1601 </method>
1603 <method name="onEnabling">
1604 <body><![CDATA[
1605 this._updateState();
1606 ]]></body>
1607 </method>
1609 <method name="onEnabled">
1610 <body><![CDATA[
1611 this._updateState();
1612 ]]></body>
1613 </method>
1615 <method name="onDisabling">
1616 <body><![CDATA[
1617 this._updateState();
1618 ]]></body>
1619 </method>
1621 <method name="onDisabled">
1622 <body><![CDATA[
1623 this._updateState();
1624 ]]></body>
1625 </method>
1627 <method name="onUninstalling">
1628 <parameter name="aRestartRequired"/>
1629 <body><![CDATA[
1630 this._updateState();
1631 ]]></body>
1632 </method>
1634 <method name="onOperationCancelled">
1635 <body><![CDATA[
1636 this._updateState();
1637 ]]></body>
1638 </method>
1640 <method name="onPropertyChanged">
1641 <parameter name="aProperties"/>
1642 <body><![CDATA[
1643 if (aProperties.indexOf("appDisabled") != -1 ||
1644 aProperties.indexOf("userDisabled") != -1)
1645 this._updateState();
1646 ]]></body>
1647 </method>
1649 <method name="onNoUpdateAvailable">
1650 <body><![CDATA[
1651 this._showStatus("none");
1652 ]]></body>
1653 </method>
1655 <method name="onCheckingUpdate">
1656 <body><![CDATA[
1657 this._showStatus("checking-update");
1658 ]]></body>
1659 </method>
1661 <method name="onCompatibilityUpdateAvailable">
1662 <body><![CDATA[
1663 this._updateState();
1664 ]]></body>
1665 </method>
1667 <method name="onExternalInstall">
1668 <parameter name="aAddon"/>
1669 <parameter name="aExistingAddon"/>
1670 <parameter name="aNeedsRestart"/>
1671 <body><![CDATA[
1672 if (aExistingAddon.id != this.mAddon.id)
1673 return;
1675 // If the install completed without needing a restart then switch to
1676 // using the new Addon
1677 if (!aNeedsRestart)
1678 this._initWithAddon(aAddon);
1679 else
1680 this._updateState();
1681 ]]></body>
1682 </method>
1684 <method name="onNewInstall">
1685 <parameter name="aInstall"/>
1686 <body><![CDATA[
1687 if (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE)
1688 return;
1689 if (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT &&
1690 AddonManager.autoUpdateDefault)
1691 return;
1693 this.mManualUpdate = aInstall;
1694 this._showStatus("update-available");
1695 this._updateUpgradeInfo();
1696 ]]></body>
1697 </method>
1699 <method name="onDownloadStarted">
1700 <parameter name="aInstall"/>
1701 <body><![CDATA[
1702 this._updateState();
1703 this._showStatus("progress");
1704 this._installStatus.initWithInstall(aInstall);
1705 ]]></body>
1706 </method>
1708 <method name="onInstallStarted">
1709 <parameter name="aInstall"/>
1710 <body><![CDATA[
1711 this._updateState();
1712 this._showStatus("progress");
1713 this._installStatus.initWithInstall(aInstall);
1714 ]]></body>
1715 </method>
1717 <method name="onInstallEnded">
1718 <parameter name="aInstall"/>
1719 <parameter name="aAddon"/>
1720 <body><![CDATA[
1721 // If the install completed without needing a restart then switch to
1722 // using the new Addon
1723 if (!(aAddon.pendingOperations & AddonManager.PENDING_INSTALL))
1724 this._initWithAddon(aAddon);
1725 else
1726 this._updateState();
1727 ]]></body>
1728 </method>
1730 <method name="onDownloadFailed">
1731 <body><![CDATA[
1732 this._updateState();
1733 ]]></body>
1734 </method>
1736 <method name="onInstallFailed">
1737 <body><![CDATA[
1738 this._updateState();
1739 ]]></body>
1740 </method>
1742 <method name="onInstallCancelled">
1743 <body><![CDATA[
1744 this._updateState();
1745 ]]></body>
1746 </method>
1747 </implementation>
1749 <handlers>
1750 <handler event="click" button="0"><![CDATA[
1751 switch (event.detail) {
1752 case 1:
1753 // Prevent double-click where the UI changes on the first click
1754 this._lastClickTarget = event.originalTarget;
1755 break;
1756 case 2:
1757 if (event.originalTarget.localName != 'button' &&
1758 !event.originalTarget.classList.contains('text-link') &&
1759 event.originalTarget == this._lastClickTarget) {
1760 this.showInDetailView();
1761 }
1762 break;
1763 }
1764 ]]></handler>
1765 </handlers>
1766 </binding>
1769 <!-- Addon - uninstalled - An uninstalled addon that can be re-installed. -->
1770 <binding id="addon-uninstalled"
1771 extends="chrome://mozapps/content/extensions/extensions.xml#addon-base">
1772 <content>
1773 <xul:hbox class="pending">
1774 <xul:image class="pending-icon"/>
1775 <xul:label anonid="notice" flex="1"/>
1776 <xul:button anonid="restart-btn" class="button-link"
1777 label="&addon.restartNow.label;"
1778 command="cmd_restartApp"/>
1779 <xul:button anonid="undo-btn" class="button-link"
1780 label="&addon.undoRemove.label;"
1781 tooltiptext="&addon.undoRemove.tooltip;"
1782 oncommand="document.getBindingParent(this).cancelUninstall();"/>
1783 <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
1784 </xul:hbox>
1785 </content>
1787 <implementation>
1788 <constructor><![CDATA[
1789 this._notice.textContent = gStrings.ext.formatStringFromName("uninstallNotice",
1790 [this.mAddon.name],
1791 1);
1793 if (!this.isPending("uninstall"))
1794 this._restartBtn.setAttribute("hidden", true);
1796 gEventManager.registerAddonListener(this, this.mAddon.id);
1797 ]]></constructor>
1799 <destructor><![CDATA[
1800 gEventManager.unregisterAddonListener(this, this.mAddon.id);
1801 ]]></destructor>
1803 <field name="_notice" readonly="true">
1804 document.getAnonymousElementByAttribute(this, "anonid", "notice");
1805 </field>
1806 <field name="_restartBtn" readonly="true">
1807 document.getAnonymousElementByAttribute(this, "anonid", "restart-btn");
1808 </field>
1810 <method name="cancelUninstall">
1811 <body><![CDATA[
1812 // This assumes that disabling does not require a restart when
1813 // uninstalling doesn't. Things will still work if not, the add-on
1814 // will just still be active until finally getting uninstalled.
1816 if (this.isPending("uninstall"))
1817 this.mAddon.cancelUninstall();
1818 else if (this.getAttribute("wasDisabled") != "true")
1819 this.mAddon.userDisabled = false;
1821 this.removeAttribute("pending");
1822 ]]></body>
1823 </method>
1825 <method name="onOperationCancelled">
1826 <body><![CDATA[
1827 if (!this.isPending("uninstall"))
1828 this.removeAttribute("pending");
1829 ]]></body>
1830 </method>
1832 <method name="onExternalInstall">
1833 <parameter name="aAddon"/>
1834 <parameter name="aExistingAddon"/>
1835 <parameter name="aNeedsRestart"/>
1836 <body><![CDATA[
1837 if (aExistingAddon.id != this.mAddon.id)
1838 return;
1840 // Make sure any newly installed add-on has the correct disabled state
1841 if (this.hasAttribute("wasDisabled"))
1842 aAddon.userDisabled = this.getAttribute("wasDisabled") == "true";
1844 // If the install completed without needing a restart then switch to
1845 // using the new Addon
1846 if (!aNeedsRestart)
1847 this.mAddon = aAddon;
1849 this.removeAttribute("pending");
1850 ]]></body>
1851 </method>
1853 <method name="onInstallStarted">
1854 <parameter name="aInstall"/>
1855 <body><![CDATA[
1856 // Make sure any newly installed add-on has the correct disabled state
1857 if (this.hasAttribute("wasDisabled"))
1858 aInstall.addon.userDisabled = this.getAttribute("wasDisabled") == "true";
1859 ]]></body>
1860 </method>
1862 <method name="onInstallEnded">
1863 <parameter name="aInstall"/>
1864 <parameter name="aAddon"/>
1865 <body><![CDATA[
1866 // If the install completed without needing a restart then switch to
1867 // using the new Addon
1868 if (!(aAddon.pendingOperations & AddonManager.PENDING_INSTALL))
1869 this.mAddon = aAddon;
1871 this.removeAttribute("pending");
1872 ]]></body>
1873 </method>
1874 </implementation>
1875 </binding>
1878 <!-- Addon - installing - an addon item that is currently being installed -->
1879 <binding id="addon-installing"
1880 extends="chrome://mozapps/content/extensions/extensions.xml#addon-base">
1881 <content>
1882 <xul:hbox anonid="warning-container" class="warning">
1883 <xul:image class="warning-icon"/>
1884 <xul:label anonid="warning" flex="1"/>
1885 <xul:button anonid="warning-link" class="button-link"
1886 oncommand="document.getBindingParent(this).retryInstall();"/>
1887 <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
1888 </xul:hbox>
1889 <xul:hbox class="content-container">
1890 <xul:vbox class="icon-outer-container">
1891 <xul:vbox class="icon-container">
1892 <xul:image anonid="icon" class="icon"/>
1893 </xul:vbox>
1894 </xul:vbox>
1895 <xul:vbox class="fade name-outer-container" flex="1">
1896 <xul:hbox class="name-container">
1897 <xul:label anonid="name" class="name" crop="end"/>
1898 <xul:label anonid="version" class="version" hidden="true"/>
1899 </xul:hbox>
1900 </xul:vbox>
1901 <xul:vbox class="install-status-container">
1902 <xul:hbox anonid="install-status" class="install-status"/>
1903 </xul:vbox>
1904 </xul:hbox>
1905 </content>
1907 <implementation>
1908 <constructor><![CDATA[
1909 this._installStatus.mControl = this;
1910 this._installStatus.mInstall = this.mInstall;
1911 this.refreshInfo();
1912 ]]></constructor>
1914 <field name="_icon">
1915 document.getAnonymousElementByAttribute(this, "anonid", "icon");
1916 </field>
1917 <field name="_name">
1918 document.getAnonymousElementByAttribute(this, "anonid", "name");
1919 </field>
1920 <field name="_version">
1921 document.getAnonymousElementByAttribute(this, "anonid", "version");
1922 </field>
1923 <field name="_warning">
1924 document.getAnonymousElementByAttribute(this, "anonid", "warning");
1925 </field>
1926 <field name="_warningLink">
1927 document.getAnonymousElementByAttribute(this, "anonid", "warning-link");
1928 </field>
1929 <field name="_installStatus">
1930 document.getAnonymousElementByAttribute(this, "anonid",
1931 "install-status");
1932 </field>
1934 <method name="onInstallCompleted">
1935 <body><![CDATA[
1936 this.mAddon = this.mInstall.addon;
1937 this.setAttribute("name", this.mAddon.name);
1938 this.setAttribute("value", this.mAddon.id);
1939 this.setAttribute("status", "installed");
1940 ]]></body>
1941 </method>
1943 <method name="refreshInfo">
1944 <body><![CDATA[
1945 this.mAddon = this.mAddon || this.mInstall.addon;
1946 if (this.mAddon) {
1947 this._icon.src = this.mAddon.iconURL ||
1948 (this.mInstall ? this.mInstall.iconURL : "");
1949 this._name.value = this.mAddon.name;
1951 if (this.mAddon.version) {
1952 this._version.value = this.mAddon.version;
1953 this._version.hidden = false;
1954 } else {
1955 this._version.hidden = true;
1956 }
1958 } else {
1959 this._icon.src = this.mInstall.iconURL;
1960 // AddonInstall.name isn't always available - fallback to filename
1961 if (this.mInstall.name) {
1962 this._name.value = this.mInstall.name;
1963 } else if (this.mInstall.sourceURI) {
1964 var url = Components.classes["@mozilla.org/network/standard-url;1"]
1965 .createInstance(Components.interfaces.nsIStandardURL);
1966 url.init(url.URLTYPE_STANDARD, 80, this.mInstall.sourceURI.spec,
1967 null, null);
1968 url.QueryInterface(Components.interfaces.nsIURL);
1969 this._name.value = url.fileName;
1970 }
1972 if (this.mInstall.version) {
1973 this._version.value = this.mInstall.version;
1974 this._version.hidden = false;
1975 } else {
1976 this._version.hidden = true;
1977 }
1978 }
1980 if (this.mInstall.state == AddonManager.STATE_DOWNLOAD_FAILED) {
1981 this.setAttribute("notification", "warning");
1982 this._warning.textContent = gStrings.ext.formatStringFromName(
1983 "notification.downloadError",
1984 [this._name.value], 1
1985 );
1986 this._warningLink.label = gStrings.ext.GetStringFromName("notification.downloadError.retry");
1987 this._warningLink.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
1988 } else if (this.mInstall.state == AddonManager.STATE_INSTALL_FAILED) {
1989 this.setAttribute("notification", "warning");
1990 this._warning.textContent = gStrings.ext.formatStringFromName(
1991 "notification.installError",
1992 [this._name.value], 1
1993 );
1994 this._warningLink.label = gStrings.ext.GetStringFromName("notification.installError.retry");
1995 this._warningLink.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
1996 } else {
1997 this.removeAttribute("notification");
1998 }
1999 ]]></body>
2000 </method>
2002 <method name="retryInstall">
2003 <body><![CDATA[
2004 this.mInstall.install();
2005 ]]></body>
2006 </method>
2007 </implementation>
2008 </binding>
2010 <binding id="detail-row">
2011 <content>
2012 <xul:label class="detail-row-label" xbl:inherits="value=label"/>
2013 <xul:label class="detail-row-value" xbl:inherits="value"/>
2014 </content>
2016 <implementation>
2017 <property name="value">
2018 <getter><![CDATA[
2019 return this.getAttribute("value");
2020 ]]></getter>
2021 <setter><![CDATA[
2022 if (!val)
2023 this.removeAttribute("value");
2024 else
2025 this.setAttribute("value", val);
2026 ]]></setter>
2027 </property>
2028 </implementation>
2029 </binding>
2031 </bindings>