3

我有一个 Web 应用程序,我的客户将其用于现金登记处。我需要做的是创建一个本地文件,因为收银机的软件需要从该文件中读取才能打印。

直到现在我一直在使用这个代码:

netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);

不幸的是,使用最新版本的 Firefox,这不再有效,所以我被告知我需要和附加组件来创建文件。我尝试开发一个附加组件(不知道是否成功)并且我有main.js 看起来像这样:

var FileManager =
{
Write:
    function (File, Text)
    {
        if (!File) return;
        const unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
            .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);

        unicodeConverter.charset = "UTF-8";

        Text = unicodeConverter.ConvertFromUnicode(Text);
        const os = Components.classes["@mozilla.org/network/file-output-stream;1"]
          .createInstance(Components.interfaces.nsIFileOutputStream);
        os.init(File, 0x02 | 0x08 | 0x20, 0700, 0);
        os.write(Text, Text.length);
        os.close();
    },

Read:
    function (File)
    {
        if (!File) return;
        var res;

        const is = Components.classes["@mozilla.org/network/file-input-stream;1"]
            .createInstance(Components.interfaces.nsIFileInputStream);
        const sis = Components.classes["@mozilla.org/scriptableinputstream;1"]
            .createInstance(Components.interfaces.nsIScriptableInputStream);
        is.init(File, 0x01, 0400, null);
        sis.init(is);

        res = sis.read(sis.available());

        is.close();

        return res;
    },
}; 

任何想法我应该如何使用 main.js?安装插件后我在哪里找到它?我需要使用这样的东西:FileManager.Write(path,text)。

4

1 回答 1

1

很抱歉超迟回复。

如果我正确理解您的问题,您有一个在 Firefox 中运行的 POS 应用程序,它通过 HTTP 与某种本地网络服务器通信。应用程序的客户端 JavaScript 需要能够从浏览器 PC 的本地文件系统读取和写入文件。

如果这是正确的,那么您可以按照以下方式进行操作。您需要创建一个 Firefox 插件,其中最简单的一种称为“引导式”(或“无重启”)插件。


无需重启的插件由两个文件组成:

  • bootstrap.js(包含您的“特权”代码的 JavaScript 文件)
  • install.rdf(描述您的 Firefrox 插件的 XML 文件)

要构建插件,只需将两个文件放在文件扩展名为 .zip 的 ZIP 文件的顶层(没有文件夹!)中.xpi。要安装插件,about:addons请从工具菜单导航到然后,单击Install from file,找到您的 XPI,打开它,然后在短暂延迟后选择Install


install.rdf这样的东西:

<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
    <Description about="urn:mozilla:install-manifest">
        <em:id>youraddonname@yourdomain</em:id>
        <em:type>2</em:type>
        <em:name>Name of your addon</em:name>
        <em:version>1.0</em:version>
        <em:bootstrap>true</em:bootstrap>
        <em:description>Describe your addon.</em:description>
        <em:creator>Your name</em:creator>

        <!-- Firefox Desktop -->
        <em:targetApplication>
            <Description>
                <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
                <em:minVersion>4.0.*</em:minVersion>
                <em:maxVersion>29.0.*</em:maxVersion>
            </Description>
        </em:targetApplication>
    </Description>
</RDF>

您需要在以下代码中实现两个必需的 JavaScript 函数bootstrap.js

  • startup()- 在您安装插件和浏览器启动时调用。
  • shutdown()- 在您卸载插件和关闭浏览器时调用。

您应该在startup(). 为了卫生,您也可以(并且可能应该)实现install()uninstall()功能。

首先在中实现以下代码bootstrap.js

const Cc = Components.classes;
const Ci = Components.interfaces;
let consoleService = Cc["@mozilla.org/consoleservice;1"]
                        .getService(Ci.nsIConsoleService);
let wm             = Cc["@mozilla.org/appshell/window-mediator;1"]
                        .getService(Ci.nsIWindowMediator);

function LOG(msg) {
  consoleService.logStringMessage("EXTENSION: "+msg);    
}

function startup() {
  try {
    LOG("starting up...");
    let windows = wm.getEnumerator("navigator:browser");
    while (windows.hasMoreElements()) {
      let chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
      WindowListener.setupBrowserUI(chromeWindow);
    }
    wm.addListener(WindowListener);
    LOG("done startup.");
  } catch (e) {
    LOG("error starting up: "+e);
  }
}

function shutdown() {
  try {
    LOG("shutting down...");
    let windows = wm.getEnumerator("navigator:browser");
    while (windows.hasMoreElements()) {
      let chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
      WindowListener.tearDownBrowserUI(chromeWindow);
    }
    wm.addListener(WindowListener);
    LOG("done shutdown.");
  } catch (e) {
    LOG("error shutting down: "+e);
  }
}

基本上,这需要WindowListener.setupBrowserUI()您的网络浏览器的每个当前和未来窗口。WindowListener定义如下:

var WindowListener = {
  setupBrowserUI: function(chromeWindow) {
    chromeWindow.gBrowser.addEventListener('load', my_load_handler, true);
  },
  tearDownBrowserUI: function(chromeWindow) {
    chromeWindow.gBrowser.removeEventListener('load', my_load_handler, true);
  },
  onOpenWindow: function(xulWindow) {
    let chromeWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIDOMWindow);
    chromeWindow.addEventListener("load", function listener() {
      chromeWindow.removeEventListener("load", listener, false);
      var domDocument = chromeWindow.document.documentElement;
      var windowType = domDocument.getAttribute("windowtype");
      if (windowType == "navigator:browser")
        WindowListener.setupBrowserUI(chromeWindow);
    }, false);
  },
  onCloseWindow: function(chromeWindow) { },
  onWindowTitleChange: function(chromeWindow, newTitle) { }
};

这会为事件设置一个事件侦听器,然后为每个 ChromeWindow中OpenWindow的事件安装一个事件侦听器。事件处理程序定义为:loadTabBrowserload

var my_load_handler = function (evt) {
  try {
    var browserEnumerator = wm.getEnumerator("navigator:browser");
    while (browserEnumerator.hasMoreElements()) {
      var browserWin = browserEnumerator.getNext();
      var tabbrowser = browserWin.gBrowser;
      var numTabs = tabbrowser.browsers.length;
      for (var index = 0; index < numTabs; index++) {
        var currentBrowser = tabbrowser.getBrowserAtIndex(index);
        var domWindow = currentBrowser.contentWindow.wrappedJSObject;
        // identify your target page(s)...
        if (domWindow.location.href == 'http://yourserver/yourpage') {
          // install the privileged methods (if not already there)
          if (!domWindow.hasOwnProperty('__my_priv_members__') {
            install_my_privileged_methods(browserWin, domWindow);
          }
        }
      }
    }
  } catch (e) {
    LOG(e);
  }
}

以正确的页面为目标(通过检查其对象的window.location.hrefand 调用,该对象定义为:install_my_privileged_methodswindow

function install_my_privileged_methods(chromeWindow, domWindow) {
  install_privileged_method(chromeWindow, domWindow, 'WriteFile', 
    function(priv) {
      return function(File, Text, cb) {
        priv.call([File, Text], function(rstatus, rdata, rerror){
          if (cb) cb(rstatus, rerror);
        });
      };
    },
    function (chromeWindow, args, cb) {
      var [File, Text] = args;
      if (!File) return cb(0, null, "need a filename");
      try {
        const unicodeConverter = 
           Cc["@mozilla.org/intl/scriptableunicodeconverter"]
             .createInstance(Ci.nsIScriptableUnicodeConverter);
        unicodeConverter.charset = "UTF-8";
        Text = unicodeConverter.ConvertFromUnicode(Text);
        const os = Cc["@mozilla.org/network/file-output-stream;1"]
                     .createInstance(Ci.nsIFileOutputStream);
        os.init(File, 0x02 | 0x08 | 0x20, 0700, 0);
        os.write(Text, Text.length);
        os.close();
        cb(1, null, null);
      } catch (e) {
        cb(0, null, "error writing file: "+e);
      }
    }
  );

  install_privileged_method(chromeWindow, domWindow, 'ReadFile', 
    function(priv) {
      return function(File, cb) {
        priv.call([File], function(rstatus, rdata, rerror){
          if (cb) cb(rstatus, rdata, rerror);
        });
      };
    },
    function (chromeWindow, args, cb) {
      var [File] = args;
      if (!File) return cb(0, null, "need a filename");
      try {
        const is = Cc["@mozilla.org/network/file-input-stream;1"]
                     .createInstance(Ci.nsIFileInputStream);
        const sis = Cc["@mozilla.org/scriptableinputstream;1"]
                      .createInstance(Ci.nsIScriptableInputStream);
        is.init(File, 0x01, 0400, null);
        sis.init(is);
        var Text = sis.read(sis.available());    
        is.close();
        cb(1, Text, null);
      } catch (e) {
        cb(0, null, "error reading file: "+e);
      }
    }
  );
}

我没有测试这段代码。这是对您上面所写内容的直截了当的翻译……我认为这是可行的!

这向所选对象添加了两个特殊方法WriteFile& 。在您的 Web 应用程序的(非特权)JavaScript 代码中,像这样使用它们:ReadFilewindow

var buffer = '...'; // the text to be written
window.WriteFile('C:\\path\\to\\file.txt', buffer, function(ok, errmsg) {
  if (!ok) alert(errmsg);
});

window.ReadFile('C:\\path\\to\\file.txt', function(ok, buffer, errmsg) { 
  if (!ok) return alert(errmsg);
  // use buffer here!
});

最后,install_privileged_method定义为:

var install_privileged_method = (function(){
  var gensym = (function (){
    var __sym = 0;
    return function () { return '__sym_'+(__sym++); }
  })();
  return function (chromeWindow, target, slot, handler, methodFactory) {
    try {
      target.__pmcache__ = target.hasOwnProperty('__pmcache__')
        ? target.__pmcache__
        : { ticket_no: 0, callbacks: {}, namespace: gensym() };
      target[slot] = methodFactory({ call: function(fargs, fcb) {
        try {
          var ticket_no = target.__pmcache__.ticket_no++;
          target.__pmcache__.callbacks[ticket_no] = fcb;
          var cevent = target.document.createEvent("CustomEvent");
          cevent.initCustomEvent(
            target.__pmcache__.namespace+'.'+slot,
            true, true, { fargs: fargs, ticket_no: ticket_no }
          );
          target.dispatchEvent(cevent);
        } catch (ue) {
          fcb(0, null, 'untrusted dispatcher error: '+ue);
        }
      }});
      LOG("installed untrusted dispatcher for method '"+slot+"'.");
      target.addEventListener(
        target.__pmcache__.namespace+'.'+slot,
        function(cevent){
          var ticket_no = cevent.detail.ticket_no;
          var fargs = cevent.detail.fargs;
          var fcb = target.__pmcache__.callbacks[ticket_no];
          try {
            handler(chromeWindow, fargs, fcb);
          } catch (pe) {
            fcb(0, null, 'privileged handler error: '+pe);
          }
        },
        false,
        true
      );
      LOG("installed privileged handler for method '"+slot+"'.");
    } catch (ie) {
      LOG("ERROR installing handler/factory for privileged "+
          "method '"+slot+"': "+ie);
    }
  };
})();
于 2014-02-05T09:00:13.603 回答