/** * @fileOverview Tab Related Confirmation Library for Firefox 3.5 or later * @author SHIMODA "Piro" Hiroshi * @version 5 * Basic usage: * * @example * Components.utils.import('resource://my-modules/confirmWithTab.js'); * * var checkbox = { * label : 'Never ask me', * checked : false * }; * * confirmWithTab({ * tab : gBrowser.selectedTab, // the related tab * label : 'Ara you ready?', // the message * value : 'treestyletab-undo-close-tree', // the internal key (optional) * buttons : ['Yes', 'No'], // button labels * checkbox : checkbox, // checkbox definition (optional) * cancelEvents : ['SSTabRestoring'] // events to cancel this deferred (optional) * }) * .next(function(aButtonIndex) { * // the next callback receives the index of the clicked button. * switch (aButtonIndex) { * case 0: // Yes * ... * break; * case 1: // No * ... * break; * } * // after the notification bar is closed, "checked" indicates * // the state of the checkbox when the user clicks a button. * var checked = checkbox.checked; * ... * }) * .error(function(aError) { * // if the tab is closed, or any event in the cancelEvents array * // is fired, then an exception is raised. * ... * }); * * @license * The MIT License, Copyright (c) 2010-2011 SHIMODA "Piro" Hiroshi * http://github.com/piroor/fxaddonlibs/blob/master/license.txt * @url http://github.com/piroor/fxaddonlibs/blob/master/confirmWithTab.js * @url http://github.com/piroor/fxaddonlibs */ if (typeof window == 'undefined') this.EXPORTED_SYMBOLS = ['confirmWithTab']; // var namespace; if (typeof namespace == 'undefined') { // If namespace.jsm is available, export symbols to the shared namespace. // See: http://github.com/piroor/fxaddonlibs/blob/master/namespace.jsm try { let ns = {}; Components.utils.import('resource://treestyletab-modules/lib/namespace.jsm', ns); namespace = ns.getNamespaceFor('piro.sakura.ne.jp'); } catch(e) { namespace = (typeof window != 'undefined' ? window : null ) || {}; } } // This depends on JSDeferred. // See: https://github.com/cho45/jsdeferred if (typeof namespace.Deferred == 'undefined') Components.utils.import('resource://treestyletab-modules/lib/jsdeferred.js', namespace); var confirmWithTab; (function() { const currentRevision = 6; var loadedRevision = 'confirmWithTab' in namespace ? namespace.confirmWithTab.revision : 0 ; if (loadedRevision && loadedRevision > currentRevision) { confirmWithTab = namespace.confirmWithTab; return; } const Ci = Components.interfaces; confirmWithTab = function confirmWithTab(aOptions) { var deferred = new namespace.Deferred(); if (!aOptions.buttons) { return deferred .next(function() { throw new Error('confirmWithTab requires one or more buttons!'); }); } var buttonClicked = false; var checkbox; namespace.Deferred.next(function() { aOptions.cancelEvents = (aOptions.cancelEvents || []) .concat(['TabClose']) .sort() .join('\n') .replace(/^(.+)$\n(\1\n)+/gm, '$1\n') .split('\n'); var tab = aOptions.tab; var b = getTabBrowserFromChild(tab); var box = b.getNotificationBox(tab.linkedBrowser); var accessKeys = []; var numericAccessKey = 0; var notification = box.appendNotification( aOptions.label, aOptions.value || 'confirmWithTab-'+encodeURIComponent(aOptions.label), aOptions.image || null, (aOptions.priority ? (typeof aOptions.priority == 'number' ? aOptions.priority : box[aOptions.priority] ) : box.PRIORITY_INFO_MEDIUM ), aOptions.buttons.map(function(aLabel, aIndex) { var accessKey; var match = aLabel.match(/\s*\(&([0-9a-z])\)/i); if (match) { accessKey = match[1]; aLabel = aLabel.replace(match[0], ''); } else { let lastUniqueKey; let sanitizedLabel = []; for (let i = 0, maxi = aLabel.length; i < maxi; i++) { let possibleAccessKey = aLabel.charAt(i); if (possibleAccessKey == '&' && i < maxi-1) { possibleAccessKey = aLabel.charAt(i+1); if (possibleAccessKey != '&') { accessKey = possibleAccessKey; } i++; } else if (!lastUniqueKey && accessKeys.indexOf(possibleAccessKey) < 0) { lastUniqueKey = possibleAccessKey; } sanitizedLabel.push(possibleAccessKey); } if (!accessKey) accessKey = lastUniqueKey; if (!accessKey || !/[0-9a-z]/i.test(accessKey)) accessKey = ++numericAccessKey; aLabel = sanitizedLabel.join(''); } accessKeys.push(accessKey); return { label : aLabel, accessKey : accessKey, callback : function() { buttonClicked = true; deferred.call(aIndex); } }; }) ); if (aOptions.checkbox) { checkbox = notification.ownerDocument.createElement('checkbox'); checkbox.setAttribute('label', aOptions.checkbox.label); if (aOptions.checkbox.checked) checkbox.setAttribute('checked', 'true'); let container = notification.ownerDocument.createElement('hbox'); container.setAttribute('align', 'center'); container.appendChild(checkbox); notification.appendChild(container); } var strip = b.tabContainer || b.mTabContainer; var handleEvent = function handleEvent(aEvent) { if (aEvent.type == 'DOMNodeRemoved' && aEvent.target != notification) return; if (aOptions.cancelEvents) aOptions.cancelEvents.forEach(function(aEventType) { strip.removeEventListener(aEventType, handleEvent, false); }); if (notification.parentNode) notification.parentNode.removeEventListener('DOMNodeRemoved', handleEvent, false); if (aEvent.type != 'DOMNodeRemoved') notification.close(); if (!buttonClicked) deferred.fail(aEvent); }; if (aOptions.cancelEvents) aOptions.cancelEvents.forEach(function(aEventType) { strip.addEventListener(aEventType, handleEvent, false); }); notification.parentNode.addEventListener('DOMNodeRemoved', handleEvent, false); }); return deferred .next(function(aButtonIndex) { buttonClicked = true; if (aOptions.checkbox) aOptions.checkbox.checked = checkbox.checked; return aButtonIndex; }); }; function getTabBrowserFromChild(aTabBrowserChild) { var b = aTabBrowserChild.ownerDocument.evaluate( 'ancestor::*[local-name()="tabbrowser"] | '+ 'ancestor::*[local-name()="tabs"][@tabbrowser] |'+ 'ancestor::*[local-name()="toolbar"]/descendant::*[local-name()="tabs"]', aTabBrowserChild, null, Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; return (b && b.tabbrowser) || b; } namespace.confirmWithTab = confirmWithTab; })();