Недавно мне понадобилась возможность экспорта стилей Stylish - всех - в один текстовый файл. Я её реализовал в своем расширении-сборнике кода, если кому понадобится - ниже кнопка, делающая то же самое.
Экспортировать стили Stylish в текстовый файл. (Firefox 12+)
Автор: hydrolizer.
Описание: Kод добавляет в меню кнопки Stylish пункт "Экспортировать стили"; при выборе пункта предлагается указать файл экспорта, в который будут выгружены все имеющиеся стили Stylish.
Использование: положите код в любую Custom Buttons кнопку, в инициализацию. Не обязательно создавать новую CB кнопку, можно использовать уже существующую.

Выделить код

Код:

(function()
{
  if (document.getElementById("stylish-export-styles-to-file")) return;  
  let sn = document.evaluate("//xul:popupset[@id='mainPopupSet']/descendant::xul:menuitem[@id='stylish-manage']/following-sibling::node()[position()=1]",
    document, function() { return "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; },
    Ci.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE, null);
  var menuitem = document.createElement("menuitem");
  menuitem.id = "stylish-export-styles";
  menuitem.setAttribute("label", "Экспортировать стили");
  sn.singleNodeValue.parentNode.insertBefore(menuitem, sn.singleNodeValue);
  menuitem.addEventListener("click", function(event)
  {
    var fp=Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
    fp.init(window, "Укажите файл экспорта", Ci.nsIFilePicker.modeSave);
    fp.appendFilter("Каскадные таблицы стилей (css)","*.css");
    var res = fp.show();
    if (res == Ci.nsIFilePicker.returnCancel)
        return null;
    var cssFile = fp.file;
    if (!/\.css/i.test(cssFile.path)) cssFile.initWithPath(cssFile.path+".css");
    Components.utils.import("resource://gre/modules/Services.jsm");
    var dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
    dbFile.append("stylish.sqlite");
    var ssvc=Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
    var mDBConn = ssvc.openDatabase(dbFile);
    var stmt = mDBConn.createStatement("SELECT name, code from styles");
    stmt.executeAsync(
    {
      results: [],
      handleResult: function(aResultSet) 
      {
        for (let row = aResultSet.getNextRow(); row; row = aResultSet.getNextRow())
          this.results = this.results.concat(
            ["/*", row.getResultByName("name"),"*/",row.getResultByName("code"),""]);
      },
      handleError: function(aError) 
      {
        Services.prompt.alert(null, "Ошибка выполнения запроса", aError.message);
      },
      handleCompletion: function(aReason) 
      {
        mDBConn.asyncClose();
        Cu.import("resource://gre/modules/FileUtils.jsm");
        Cu.import("resource://gre/modules/NetUtil.jsm");
        var ostream = FileUtils.openSafeFileOutputStream(cssFile)
        var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
        converter.charset = "UTF-8";
        var istream = converter.convertToInputStream(this.results.join("\n"));
        NetUtil.asyncCopy(istream, ostream, (function(status)
        {
          if (!Components.isSuccessCode(status))
            Services.prompt.alert(null, "Ошибка","Ошибка сохранения стилей (код: "+status+")");
          else
            custombuttons.alertSlide("Экспорт стилей Stylish", "Стили успешно экспортированы.");
        }).bind(this));
      }
    });
  }, false);
})();

удобно для миграции на User Style Manager :)
Хотя ещё удобей было бы сохранять стили по отдельности.

iDev.Pi
По отдельности - т.е. все стили, и отдельный файл для каждого стиля?

hydrolizer
да

iDev.Pi
вот:

Выделить код

Код:

function Exporter(toFileSet)
{
  Object.defineProperty(this, "toFileSet", {get: function(){ return toFileSet; }});
  var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
  converter.charset = "UTF-8";
  Object.defineProperty(this, "converter", {get: function(){ return converter; }});
};

Exporter.prototype=
{
  styles: null,
  mDBConn: null,
  exportFile: null,
  
  toString: function() { return "[custombuttons.stylish-exporter]"; },
  
  handleEvent: function(event)
  {
    this.exportFile = this.toFileSet ? this.pickDirectory() : this.pickFile();
    if (!this.exportFile) return;
    this.getStyles();
  },
  
  pickFile: function()
  {
    var fp=Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
    fp.init(window, "Укажите файл экспорта", Ci.nsIFilePicker.modeSave);
    fp.appendFilter("Каскадные таблицы стилей (css)","*.css");
    var res = fp.show();
    if (res == Ci.nsIFilePicker.returnCancel)
        return null;
    var cssFile = fp.file;
    if (!/\.css$/i.test(cssFile.path)) cssFile.initWithPath(cssFile.path+".css");
    return cssFile;
  },
  
  pickDirectory: function()
  {
    var fp=Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
    fp.init(window, "Укажите папку для экспорта", Ci.nsIFilePicker.modeGetFolder);
    return fp.show()==Ci.nsIFilePicker.returnOK ? fp.file : null;
  },
  
  getStyles: function()
  {
    var dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
    dbFile.append("stylish.sqlite");
    var ssvc=Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
    this.mDBConn = ssvc.openDatabase(dbFile);
    var stmt = this.mDBConn.createStatement("SELECT name, code from styles");
    this.styles=[];
    stmt.executeAsync(this);
  },

  prepareStyles: function()
  {
    var data;
    if (!this.toFileSet)
    {
      var content = [];
      this.styles.forEach(function(elem)
      {
        content = content.concat(["/*", elem.name,"*/", elem.style, ""]);
      });
      data=[{file: this.exportFile, content: content.join("\n")}];
    }
    else
    {
      data=this.styles.map((function(elem)
      {
        var file = this.exportFile.clone();
        file.append(elem.name.replace(/[\\\/\:\*\?"<>\|]/g,"-").replace(/^\.|\.$/g,"_")+".css");
        return {file: file, content: ["/*", elem.name,"*/", elem.style].join("\n")};
      }).bind(this));
    }
    this.saveStyles(data);
  },
  
  saveStyles: function(data)
  {
    if (data.length==0)
    {
      custombuttons.alertSlide("Экспорт стилей Stylish", "Стили успешно экспортированы.");
      return;
    }
    Cu.import("resource://gre/modules/FileUtils.jsm");
    Cu.import("resource://gre/modules/NetUtil.jsm");
    var style = data.shift();
    var ostream = FileUtils.openSafeFileOutputStream(style.file)
    var istream = this.converter.convertToInputStream(style.content);
    NetUtil.asyncCopy(istream, ostream, (function(status)
    {
      if (!Components.isSuccessCode(status))
        Services.prompt.alert(null, "Ошибка","Ошибка сохранения стилей (код: "+status+")");
      else
        this.saveStyles(data);
    }).bind(this));
  },
  
  handleResult: function(aResultSet) 
  {
    for (let row = aResultSet.getNextRow(); row; row = aResultSet.getNextRow())
      this.styles.push({name: row.getResultByName("name"), style: row.getResultByName("code")});
  },
  
  handleError: function(aError) 
  {
    Services.prompt.alert(null, "Ошибка выполнения запроса", aError.message);
  },
  
  handleCompletion: function(aReason) 
  {
    this.mDBConn.asyncClose((function()
    {
      delete this.mDBConn;
    }).bind(this));
    this.prepareStyles();
  }
};

(function()
{
  if (document.getElementById("stylish-export-styles-to-file")) return;
  var miToSingleFile = document.createElement("menuitem");
  miToSingleFile.id = "stylish-export-styles-to-file";
  miToSingleFile.setAttribute("label", "в файл");
  var miToSetFiles = document.createElement("menuitem");
  miToSetFiles.id = "stylish-export-styles-to-set-files";
  miToSetFiles.setAttribute("label", "в набор файлов");
  var popup = document.createElement("menupopup");
  popup.appendChild(miToSingleFile);
  popup.appendChild(miToSetFiles);
  var menu = document.createElement("menu");
  menu.id="stylish-export-styles";
  menu.setAttribute("label","Экспортировать стили");
  menu.appendChild(popup);
  let sn = document.evaluate("//xul:popupset[@id='mainPopupSet']/descendant::xul:menuitem[@id='stylish-manage']/following-sibling::node()[position()=1]",
    document, function() { return "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; },
    Ci.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE, null);
  sn.singleNodeValue.parentNode.insertBefore(menu, sn.singleNodeValue);
  miToSingleFile.addEventListener("click", new Exporter(false), false);
  miToSetFiles.addEventListener("click", new Exporter(true), false);
})();

Добавляется уже не пункт меню, а подменю экспорта с двумя пунктами: экспорт в файл, и экспорт в набор файлов. Во втором случае имя файла определяется названием стиля.

hydrolizer
класс, спасибо :)

Советую заменить

Выделить код

Код:

var stop;
if (stop) return;
stop = true;

на

Выделить код

Код:

if (document.getElementById("stylish-export-styles-to-file")) return;

иначе после открытия настройки панелей будет так:

скрытый текст
2cv0

bunda1
да. спасибо, всё убралось

bunda1
Заменил. Но, надо сказать, этот кусок кода был полностью скопипащен из кода вот этой кнопки - у меня же это не кнопка; пункты меню вставляются совсем другим образом, и этих проверок не требуется.

hydrolizer
Это такой баг Сustom Buttons, при открытия настройки панелей код из вкладки инициализации кнопки инициализируется повторно и это надо блокировать иначе твой код добавит новый пункт меню и так каждый раз.
Но блок if (stop) return; не сработал, не знаю почему.

Можно использовать расширение Stylish Sync >
https://addons.mozilla.org/ru/firefox/a … ylishsync/

Лично я выключаю синхронизацию и делаю вручную через бэкапы.
14932847929_956e17be78_n.jpg

почему то кнопка на мозиле 31 1 1 не работает... CB 0058

еле нашёл))

Спасибо! Очень удобная штука!

жаль что позно нашёл! Класс! appl.gif appl.gif appl.gif

02-02-2016 13:43:30
а для кнопок нечто подобное?

oleg953 пишет

а для кнопок нечто подобное?

Custom Buttons • View topic - CB Button Utility

oleg953 пишет

а для кнопок нечто подобное?

FF Exp Imp CB

bunda1 пишет

FF Exp Imp CB

отлично! спасибо :beer:

Не совсем в тему, но пригодится тем кто ищет. Есть такое расширение Stylish-Custom, помимо прочих удобств добавляемых в Stylish, добавляет возможность бекапа стилей, каждый стиль в отдельный .css файл, плюс позволяет выбрать активные или неактивные стили для бэкапа, или вообще самостоятельно выбрать, что бэкапить.
72461a71aee8.jpg

Создать кнопку или положить в инициализацию другой

скрытый текст

Выделить код

Код:

//Экспорт стилей Stylish в меню кнопки .................................................................................................................
function Exporter(toFileSet)
{
  Object.defineProperty(this, "toFileSet", {get: function(){ return toFileSet; }});
  var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
  converter.charset = "UTF-8";
  Object.defineProperty(this, "converter", {get: function(){ return converter; }});
};

Exporter.prototype=
{
  styles: null,
  mDBConn: null,
  exportFile: null,
  
  toString: function() { return "[custombuttons.stylish-exporter]"; },
  
  handleEvent: function(event)
  {
    this.exportFile = this.toFileSet ? this.pickDirectory() : this.pickFile();
    if (!this.exportFile) return;
    this.getStyles();
  },
  
  pickFile: function()
  {
    var fp=Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
    fp.init(window, "Укажите файл экспорта", Ci.nsIFilePicker.modeSave);
    fp.appendFilter("Каскадные таблицы стилей (css)","*.css");
    var res = fp.show();
    if (res == Ci.nsIFilePicker.returnCancel)
        return null;
    var cssFile = fp.file;
    if (!/\.css$/i.test(cssFile.path)) cssFile.initWithPath(cssFile.path+".css");
    return cssFile;
  },
  
  pickDirectory: function()
  {
    var fp=Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
    fp.init(window, "Укажите папку для экспорта", Ci.nsIFilePicker.modeGetFolder);
    return fp.show()==Ci.nsIFilePicker.returnOK ? fp.file : null;
  },
  
  getStyles: function()
  {
    var dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
    dbFile.append("stylish.sqlite");
    var ssvc=Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
    this.mDBConn = ssvc.openDatabase(dbFile);
    var stmt = this.mDBConn.createStatement("SELECT name, code from styles");
    this.styles=[];
    stmt.executeAsync(this);
  },

  prepareStyles: function()
  {
    var data;
    if (!this.toFileSet)
    {
      var content = [];
      this.styles.forEach(function(elem)
      {
        content = content.concat(["/*", elem.name,"*/", elem.style, ""]);
      });
      data=[{file: this.exportFile, content: content.join("\n")}];
    }
    else
    {
      data=this.styles.map((function(elem)
      {
        var file = this.exportFile.clone();
        file.append(elem.name.replace(/[\\\/\:\*\?"<>\|]/g,"-").replace(/^\.|\.$/g,"_")+".css");
        return {file: file, content: ["/*", elem.name,"*/", elem.style].join("\n")};
      }).bind(this));
    }
    this.saveStyles(data);
  },
  
  saveStyles: function(data)
  {
    if (data.length==0)
    {
      custombuttons.alertSlide("Экспорт стилей Stylish", "Стили успешно экспортированы.");
      return;
    }
    Cu.import("resource://gre/modules/FileUtils.jsm");
    Cu.import("resource://gre/modules/NetUtil.jsm");
    var style = data.shift();
    var ostream = FileUtils.openSafeFileOutputStream(style.file)
    var istream = this.converter.convertToInputStream(style.content);
    NetUtil.asyncCopy(istream, ostream, (function(status)
    {
      if (!Components.isSuccessCode(status))
        Services.prompt.alert(null, "Ошибка","Ошибка сохранения стилей (код: "+status+")");
      else
        this.saveStyles(data);
    }).bind(this));
  },
  
  handleResult: function(aResultSet) 
  {
    for (let row = aResultSet.getNextRow(); row; row = aResultSet.getNextRow())
      this.styles.push({name: row.getResultByName("name"), style: row.getResultByName("code")});
  },
  
  handleError: function(aError) 
  {
    Services.prompt.alert(null, "Ошибка выполнения запроса", aError.message);
  },
  
  handleCompletion: function(aReason) 
  {
    this.mDBConn.asyncClose((function()
    {
      delete this.mDBConn;
    }).bind(this));
    this.prepareStyles();
  }
};

(function()
{
  if (document.getElementById("stylish-export-styles-to-file")) return;
  var miToSingleFile = document.createElement("menuitem");
  miToSingleFile.id = "stylish-export-styles-to-file";
  miToSingleFile.setAttribute("label", "В файл");
  var miToSetFiles = document.createElement("menuitem");
  miToSetFiles.id = "stylish-export-styles-to-set-files";
  miToSetFiles.setAttribute("label", "В набор файлов");
  var popup = document.createElement("menupopup");
  popup.appendChild(miToSingleFile);
  popup.appendChild(miToSetFiles);
  var menu = document.createElement("menu");
  menu.id="stylish-export-styles";
  menu.setAttribute("label","Экспортировать стили");
  menu.appendChild(popup);
  let sn = document.evaluate("//xul:popupset[@id='mainPopupSet']/descendant::xul:menuitem[@id='stylish-manage']/following-sibling::node()[position()=1]",
    document, function() { return "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; },
    Ci.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE, null);
  sn.singleNodeValue.parentNode.insertBefore(menu, sn.singleNodeValue);
  miToSingleFile.addEventListener("click", new Exporter(false), false);
  miToSetFiles.addEventListener("click", new Exporter(true), false);
})();


Код создает подменю бэкапа в кнопке Stylish