2014-11-01 2 views
4

Firefox 용 애드온 개발 사용자가 요청한 것처럼 다운로드를 시작할 수 있어야합니다. 즉, 일반 파일 저장 대화 상자를 표시하거나 파일을 저장해야합니다. 환경 설정> 콘텐츠에서 구성 할 수 있으므로 사용자가 좋아하는 곳이면 어디든 좋습니다.addon에서 정상적인 다운로드를 시작하는 방법

다운로드에 관한 모든 단일 게시물 또는 문서는 파일 다운로드 위치를 알고있는 상황을 고려한 것으로 보입니다. 그러나이 경우에는 내가 필요한 경우가 아닙니다.이 경우에는 사용자 다운로드를 시작했습니다.

어떻게하면 SDK의 방법을 통해 수행 할 수 있습니까?

+0

니스 Q를 사용합니다. 나는 또한 대답에 관심이있다. 다운로드는 너무 좋은 메신저가 아니다. – Noitidart

+1

나는 [Download.jsm] (https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Downloads.jsm)을 파고 파이어 폭스에서 어떻게 시작되는지 알아야한다고 생각한다. UI. 좋은 질문 때문에 upvoted. :) – canuckistani

답변

2

글쎄, 실제 저장을 시작할 수 있습니다. 요구시 작동되는 값이 gContextMenu.saveLink();이다 컨텍스트 메뉴에서
: 세이브 코드에서 링크를 초기화

. saveLink()는 chrome://browser/content/nsContextMenu.js에 정의되어 있습니다. 약간의 청소를 한 다음 saveHelper() which is defined in the same file으로 전화합니다. 적절한 인수를 사용하여 saveHelper()를 호출 할 수 있습니다. 이어서 nullchrome://browser/content/browser.js에서 선언 gContextMenu 변수 할당

<script type="application/javascript" 
      src="chrome://browser/content/nsContextMenu.js"/> 

: 컨텍스트 메뉴 용 onpopupshowing 이벤트 핸들러
gContextMenu = new nsContextMenu(this, event.shiftKey);
그것은 함께 chrome://browser/content/web-panels.xul에서 패널에 포함된다.
'gContextMenu = null;'
onpopuphiding 이벤트 처리기에서 반환됩니다. 당신이 당신의 자신의 코드에서 사용하려면

당신은 할 수 있습니다 :

let urlToSave = "http://stackoverflow.com/questions/26694442"; 
let linkText = "Some Link text"; 

// Add a "/" to un-comment the code appropriate for your add-on type. 
/* Overlay and bootstrap: 
const Cc = Components.classes; 
const Ci = Components.interfaces; 
const Cr = Components.results; 
//*/ 
/* Add-on SDK: 
var {Cc, Ci, Cr} = require("chrome"); 
//*/ 

if (window === null || typeof window !== "object") { 
    //If you do not already have a window reference, you need to obtain one: 
    // Add a "/" to un-comment the code appropriate for your add-on type. 
    /* Add-on SDK: 
    var window = require('sdk/window/utils').getMostRecentBrowserWindow(); 
    //*/ 
    /* Overlay and bootstrap (from almost any context/scope): 
    var window=Components.classes["@mozilla.org/appshell/window-mediator;1"] 
         .getService(Components.interfaces.nsIWindowMediator) 
         .getMostRecentWindow("navigator:browser");   
    //*/ 
} 

//Create an object in which we attach nsContextMenu.js. 
// It needs some support properties/functions which 
// nsContextMenu.js assumes are part of its context. 
let contextMenuObj = { 
    makeURI: function (aURL, aOriginCharset, aBaseURI) { 
     var ioService = Cc["@mozilla.org/network/io-service;1"] 
           .getService(Ci.nsIIOService); 
     return ioService.newURI(aURL, aOriginCharset, aBaseURI); 
    }, 
    gPrefService: Cc["@mozilla.org/preferences-service;1"] 
          .getService(Ci.nsIPrefService) 
          .QueryInterface(Ci.nsIPrefBranch), 
    Cc: Cc, 
    Ci: Ci, 
    Cr: Cr 
}; 

Cc["@mozilla.org/moz/jssubscript-loader;1"] 
     .getService(Ci.mozIJSSubScriptLoader) 
     .loadSubScript("chrome://browser/content/nsContextMenu.js" 
         ,contextMenuObj); 

//Re-define the initMenu function, as there is not a desire to actually 
// initialize a menu.   
contextMenuObj.nsContextMenu.prototype.initMenu = function() { }; 

let myContextMenu = new contextMenuObj.nsContextMenu(); 
//Save the specified URL 
myContextMenu.saveHelper(urlToSave,linkText,null,true,window.content.document); 

대안을 nsContextMenu.js을로드 loadSubScript를 사용하여 :
내 취향이 nsContextMenu.js에서 saveHelper 코드를로드 할 loadSubScript을 사용하는 것입니다 . 이렇게하면 앞으로 출시 될 Firefox에서 변경된 사항을 최신 상태로 유지할 수 있습니다. 그러나 비공식 API의 함수를 사용한다는 종속성이 있습니다. 따라서, 향후 Firefox 릴리스에서 어떤 식 으로든 변경 될 수 있으며 추가 기능이 변경되어야합니다. 대안은 내선 번호에 saveHelper() 코드를 복제하는 것입니다. 그것은 다음과 같이 정의된다 :

@canuckistani 말했듯이
// Helper function to wait for appropriate MIME-type headers and 
// then prompt the user with a file picker 
saveHelper: function(linkURL, linkText, dialogTitle, bypassCache, doc) { 
    // canonical def in nsURILoader.h 
    const NS_ERROR_SAVE_LINK_AS_TIMEOUT = 0x805d0020; 

    // an object to proxy the data through to 
    // nsIExternalHelperAppService.doContent, which will wait for the 
    // appropriate MIME-type headers and then prompt the user with a 
    // file picker 
    function saveAsListener() {} 
    saveAsListener.prototype = { 
    extListener: null, 

    onStartRequest: function saveLinkAs_onStartRequest(aRequest, aContext) { 

     // if the timer fired, the error status will have been caused by that, 
     // and we'll be restarting in onStopRequest, so no reason to notify 
     // the user 
     if (aRequest.status == NS_ERROR_SAVE_LINK_AS_TIMEOUT) 
     return; 

     timer.cancel(); 

     // some other error occured; notify the user... 
     if (!Components.isSuccessCode(aRequest.status)) { 
     try { 
      const sbs = Cc["@mozilla.org/intl/stringbundle;1"]. 
         getService(Ci.nsIStringBundleService); 
      const bundle = sbs.createBundle(
        "chrome://mozapps/locale/downloads/downloads.properties"); 

      const title = bundle.GetStringFromName("downloadErrorAlertTitle"); 
      const msg = bundle.GetStringFromName("downloadErrorGeneric"); 

      const promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"]. 
          getService(Ci.nsIPromptService); 
      promptSvc.alert(doc.defaultView, title, msg); 
     } catch (ex) {} 
     return; 
     } 

     var extHelperAppSvc = 
     Cc["@mozilla.org/uriloader/external-helper-app-service;1"]. 
     getService(Ci.nsIExternalHelperAppService); 
     var channel = aRequest.QueryInterface(Ci.nsIChannel); 
     this.extListener = 
     extHelperAppSvc.doContent(channel.contentType, aRequest, 
            doc.defaultView, true); 
     this.extListener.onStartRequest(aRequest, aContext); 
    }, 

    onStopRequest: function saveLinkAs_onStopRequest(aRequest, aContext, 
                aStatusCode) { 
     if (aStatusCode == NS_ERROR_SAVE_LINK_AS_TIMEOUT) { 
     // do it the old fashioned way, which will pick the best filename 
     // it can without waiting. 
     saveURL(linkURL, linkText, dialogTitle, bypassCache, false, 
       doc.documentURIObject, doc); 
     } 
     if (this.extListener) 
     this.extListener.onStopRequest(aRequest, aContext, aStatusCode); 
    }, 

    onDataAvailable: function saveLinkAs_onDataAvailable(aRequest, aContext, 
                 aInputStream, 
                 aOffset, aCount) { 
     this.extListener.onDataAvailable(aRequest, aContext, aInputStream, 
             aOffset, aCount); 
    } 
    } 

    function callbacks() {} 
    callbacks.prototype = { 
    getInterface: function sLA_callbacks_getInterface(aIID) { 
     if (aIID.equals(Ci.nsIAuthPrompt) || aIID.equals(Ci.nsIAuthPrompt2)) { 
     // If the channel demands authentication prompt, we must cancel it 
     // because the save-as-timer would expire and cancel the channel 
     // before we get credentials from user. Both authentication dialog 
     // and save as dialog would appear on the screen as we fall back to 
     // the old fashioned way after the timeout. 
     timer.cancel(); 
     channel.cancel(NS_ERROR_SAVE_LINK_AS_TIMEOUT); 
     } 
     throw Cr.NS_ERROR_NO_INTERFACE; 
    } 
    } 

    // if it we don't have the headers after a short time, the user 
    // won't have received any feedback from their click. that's bad. so 
    // we give up waiting for the filename. 
    function timerCallback() {} 
    timerCallback.prototype = { 
    notify: function sLA_timer_notify(aTimer) { 
     channel.cancel(NS_ERROR_SAVE_LINK_AS_TIMEOUT); 
     return; 
    } 
    } 

    // set up a channel to do the saving 
    var ioService = Cc["@mozilla.org/network/io-service;1"]. 
        getService(Ci.nsIIOService); 
    var channel = ioService.newChannelFromURI(makeURI(linkURL)); 
    if (channel instanceof Ci.nsIPrivateBrowsingChannel) { 
    let docIsPrivate = PrivateBrowsingUtils.isWindowPrivate(doc.defaultView); 
    channel.setPrivate(docIsPrivate); 
    } 
    channel.notificationCallbacks = new callbacks(); 

    let flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS; 

    if (bypassCache) 
    flags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; 

    if (channel instanceof Ci.nsICachingChannel) 
    flags |= Ci.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE_IF_BUSY; 

    channel.loadFlags |= flags; 

    if (channel instanceof Ci.nsIHttpChannel) { 
    channel.referrer = doc.documentURIObject; 
    if (channel instanceof Ci.nsIHttpChannelInternal) 
     channel.forceAllowThirdPartyCookie = true; 
    } 

    // fallback to the old way if we don't see the headers quickly 
    var timeToWait = 
    gPrefService.getIntPref("browser.download.saveLinkAsFilenameTimeout"); 
    var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 
    timer.initWithCallback(new timerCallback(), timeToWait, 
         timer.TYPE_ONE_SHOT); 

    // kick off the channel with our proxy object as the listener 
    channel.asyncOpen(new saveAsListener(), null); 
} 
+0

linkText를 어떻게 결정합니까? –

+0

@ РоманКоптев, 나는 당신이 무엇을 요구하고 있는지 확실히 모르겠습니다. 정확히 링크의 텍스트를 결정하는 방법은 이미 가지고있는 정보에 달려 있습니다. 이 질문은 다운로드 할 링크 원본을 지정하지 않습니다. 따라서, 나는 당신에게 대답을 제공하기 위해 일할 수있는 많은 맥락이 없습니다. 이미 ''요소가 있다면, [Node.textContent'] (https://developer.mozilla.org/en-US/docs/Web/API/)로 원하는 것을 달성 할 수 있습니다. Node/textContent).나는 당신이 새로운 질문을하고 당신이 알고 싶은 것에 관해서 좀 더 자세하게 제안 할 것을 제안합니다. [청하다] – Makyen

0

Downloads.jsm

let { Downloads } = require("resource://gre/modules/Downloads.jsm"); 
let { OS } = require("resource://gre/modules/osfile.jsm") 
let { Task } = require("resource://gre/modules/Task.jsm"); 

Task.spawn(function() { 

    yield Downloads.fetch("http://www.mozilla.org/", 
         OS.Path.join(OS.Constants.Path.tmpDir, 
            "example-download.html")); 

    console.log("example-download.html has been downloaded."); 

}).then(null, Components.utils.reportError); 
관련 문제