Полезная информация

Хотите узнать больше о расширениях? Посмотрите ролики, рассказывающие о работе с расширениями Firefox.

№1555111-05-2021 13:10:20

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 25
UA: Chrome 90.0

Re: Custom Buttons

Извините что отвлёк...

Отредактировано Deriax (13-05-2021 21:30:08)

Отсутствует

 

№1555211-05-2021 13:25:03

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 87.0

Re: Custom Buttons

Dumby - ещё просьба для кода Сохранения картинки жестом: перетаскивание заменить кликом средней кнопки мыши на картинке.

в Firefox 87 ошибка Uncaught (in promise) TypeError: ref is undefined на этих строках:
this[e.type](e);
url && this.save(url, name);
if (ref.spec.startsWith("http"))
})(url, name);


Dumby пишет

Я же без понятия что имеется в виду под «папка Загрузки», тем более на Мак.

Но ведь в коде видно, что это папка Загрузки по-умолчанию, указанная в Настройках.
Ещё по значку браузера видно, что я проверял скрипт не на Маке, а на Линуксе.

Отредактировано Dobrov (11-05-2021 15:55:05)

Отсутствует

 

№1555311-05-2021 16:33:55

xrun1
Участник
 
Группа: Members
Зарегистрирован: 12-12-2013
Сообщений: 829
UA: Firefox 88.0

Re: Custom Buttons

del

Отредактировано xrun1 (12-05-2021 10:43:22)

Отсутствует

 

№1555411-05-2021 20:49:51

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 1517
UA: Firefox 78.0

Re: Custom Buttons

Cytrus пишет

Подскажите, почему не получается сделать запись в локальное хранилище?
Выдаёт сообщение, типа недоступно.

Ну и вопрос. Это так важно «почему»? Нет и всё.
Попробовал чуток порыться, и, если я правильно понял,
то для SystemPrincipal окон localStorage не создаётся вообще.
Но мысль интересная — хранить своё добро в localStorage окна браузера (browser.xhtml).
Увы, затейникам отказано.


Deriax пишет

как получить originAttributes кук

Куки (nsICookie) уже имеют свойство originAttributes, код-то запускал?
Как-то особо получать не требуется, достаточно просто обратиться к этому свойству.


А если имеется в виду «активной вкладки» и не понравилось gBrowser.contentPrincipal.originAttributes
то, возможно, подойдёт gBrowser.selectedBrowser.browsingContext.originAttributes
Хотя, видимо, это не совсем одно и то же. В первом случае там заполняется firstPartyDomain
если включено privacy.firstparty.isolate, так что, наверно, лучше взять вообще все куки (Services.cookies.cookies),
и фильтровать, в зависимости от представления что есть «куки вкладки».


Dobrov пишет

в Firefox 87 ошибка Uncaught (in promise) TypeError: ref is undefined

Хм, действительно, browsingContext.currentURI добавили только в Firefox 88.
Можно заменить var ref = bc.currentURI; на
var ref = bc.currentWindowGlobal?.documentURI || {spec: ""};

Но ведь в коде видно, что это папка Загрузки по-умолчанию, указанная в Настройках.
Ещё по значку браузера видно, что я проверял скрипт не на Маке, а на Линуксе.

По значку браузера да, видно, проявил невнимательность.
А вот по коду — ничего не видно. В Настройках папка Загрузки — это что угодно,
но только не "browser.download.lastDir". По-умолчанию? А что у тебя возвращает
Services.dirsvc.get("DfltDwnld", Ci.nsIFile).path

перетаскивание заменить кликом

Заменить?! Затрудняюсь даже прокомментировать это.

Отсутствует

 

№1555512-05-2021 02:02:38

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 87.0

Re: Custom Buttons

Dumby пишет

Заменить?! Затрудняюсь даже прокомментировать это.
А что у тебя возвращает Services.dirsvc.get("DfltDwnld", Ci.nsIFile).path

Это чтобы картинка сохранялась не Перетаскиванием, а по клику Колёсиком мыши на изображении (так быстрее).
Services.dirsvc… возвращает путь к папке Загрузки, указанной в настройках.


Сделал сохранение в путь: [Загрузки]/_Images/Имя вкладки, но вместо имени вкладки получаю "Mozilla Firefox" или "Новая вкладка". :-(
Dumby, почини код, чтобы файл сохранялся в указанный путь!

Выделить код

Код:

(async id => { // Firefox 85+ сохранить изображение жестом
	var Title = function (type) { // получить заголовок (type >0 обрезка)
		var title = (gBrowser.selectedTab.label || window.document.title);
		return title.substr(0, type).trim(); // ограничить длину заголовка
	}
	var path = OS.Path.join(Services.dirsvc.get("DfltDwnld", Ci.nsIFile).path, "_Images", Title(100)); // папка [Загрузки]/_Images/Имя вкладки
	var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
	file.initWithPath(path);
	if ( !file.exists() || !file.isDirectory() ) file.create(Ci.nsIFile.DIRECTORY_TYPE, 0777); // создать папку, если не существует…
// … далее код не менял, только исправил var ref = bc.currentURI;
xrun1 пишет

Просьбами Вы, конечно, только достали лично меня

Какими просьбами? Ведь вы мне не помогали, ваши посты неинформативны - а у меня всё работает…  Спасибо, получилось.  так значительно лучше!  Спасибо, всё отлично!


xrun1 пишет

Вы интересный человек, Вам нужен мак. А кому он здесь нужен?

У меня Хакинтош и на 2020 год ваш скепсис опровергнут более четверти пользователей компьютеров:
статистика Операционных систем в США | Мире: Windows — 65,95|76,58% OS X — 27,77|18,93 Linux — 1,7%|1,62%.

Отредактировано Dobrov (12-05-2021 04:34:17)

Отсутствует

 

№1555612-05-2021 03:48:28

kazarin
Участник
 
Группа: Members
Зарегистрирован: 23-11-2016
Сообщений: 24
UA: unknown 0.0

Re: Custom Buttons

Dobrov пишет

kazarin - у меня на обложке-ссылке фильма Гости из прошлого не появляется кнопка загрузки, только курсор в виде руки.

kazarin пишет

настройка Show a download button on hover создаёт над изображением кнопку, с которой можно сохранять без запроса.

Эту опцию надо включить, она не выставлена по умолчанию.

Отсутствует

 

№1555712-05-2021 04:18:13

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 88.0

Re: Custom Buttons

kazarin пишет

Эту опцию надо включить, она не выставлена по умолчанию.

Извините, я всегда проверяю настройки и думал, вы поймёте, что эта опция у меня конечно же включена. Результат тот же.
Кроме того, ведь здесь вообще-то тема по обсуждению скриптов / кнопок, а не расширений. ;-)

Отредактировано Dobrov (12-05-2021 04:35:15)

Отсутствует

 

№1555812-05-2021 06:06:26

Stkvsky
Участник
 
Группа: Members
Зарегистрирован: 26-06-2012
Сообщений: 1578
UA: Firefox 78.0

Re: Custom Buttons

Dumby пишет
Stkvsky пишет

Если закрыть браузер и запустить заново удаляется

А, наверно имеется ввиду не закрыть браузер как приложение (Выход, Ctrl+Shift+Q),
а когда последнее/единственное браузерное окно закрывается.
Хорошо, попробую.

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

Выделить код

Код:

(async (sel, self) => ({

	icon: "circle",
	colors: [
		"mediumseagreen",
		"silver",
		"crimson",
		"blue",
		"peru",
	],

	initColors() {
		var colorName = "ucf-gen";
		var css = "@-moz-document url(about:preferences#containers),"
			+ " url-prefix(chrome://browser/content/browser.x) {\n";
		this.colors.forEach((color, ind) => {
			var [ic, tc] = color.split(/\s*\|\s*/);
			css += `\t.identity-color-${colorName}${ind} {\n`
				+ `\t\t--identity-tab-color: ${tc || ic};\n`
				+ `\t\t--identity-icon-color: ${ic};\n\t}\n`
		});
		var url = "data:text/css;charset=utf-8," + encodeURIComponent(css + "}");
		var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
			.getService(Ci.nsIStyleSheetService);
		sss.loadAndRegisterSheet(Services.io.newURI(url), sss.USER_SHEET);

		var len = this.colors.length;
		var pref = "ucf.openInGeneratedContainer.lastColor";
		var ind = Math.min(Services.prefs.getIntPref(pref, -1), len - 1);
		this.nextColor = () => {
			var next = ind + 1;
			Services.prefs.setIntPref(pref, ind = next == len ? 0 : next);
			return colorName + ind;
		}
	},
	quit: false,
	init(topic) {
		Services.obs.addObserver(self = this, topic);

		var lt = "browser-lastwindow-close-granted";
		var lw = () => this.quit = true;
		Services.obs.addObserver(lw, lt);

		Services.obs.addObserver(function quit(s, t) {
			self.quit = true;
			Services.obs.removeObserver(self, topic);
			Services.obs.removeObserver(lw, lt);
			Services.obs.removeObserver(quit, t);
		}, "quit-application-granted");
		this.initColors();
		this.newUsercontext = name => {
			var id = this.cis.create(
				name || `[ ${this.cis._lastUserContextId + 1} ]`, this.icon, this.nextColor()
			).userContextId;
			this.saveGens(this.gens.add(id));
			return id;
		}
		var cpref = "ucf.openInGeneratedContainer.containers";
		var arr = Services.prefs.getStringPref(cpref, "").split(",").map(Number).filter(Boolean);
		if (arr.length) {
			var ids = this.cis.getPublicIdentities().map(i => i.userContextId);
			arr = arr.filter(id => ids.includes(id));
		}
		this.gens = new Set(arr);
		(this.saveGens = () => Services.prefs.setStringPref(cpref, Array.from(this.gens).join(",")))();
	},
	observe(doc) {
		var list = doc.querySelectorAll(sel);
		if (!list.length) return;

		var menuitem = doc.createXULElement("menuitem");
		for(var args of Object.entries({
			selectiontype: "single",
			oncommand: "cmd(window)",
			nodetype: "folder|query",
			selection: "folder|query",
			label: "Открыть всё в контейнере",
			id: "placesContext_openContainer:tabs:newUsercontext"
		}))
			menuitem.setAttribute(...args);
		menuitem.cmd = this.cmd;
		menuitem.rnd = menuitem.constructor.prototype.render;
		menuitem.render = this.render;
		var [m1, m2] = menuitem.list = Array.from(list);
		(m2 || m1).after(menuitem);

		if (doc.documentElement.getAttribute("windowtype") != "navigator:browser") return;

		for(var btn of [
			doc.getElementById("tabs-newtab-button"),
			doc.getElementById("new-tab-button") ||
				doc.ownerGlobal.gNavToolbox.palette.querySelector("#new-tab-button")
		])
			if (btn) btn.checkForMiddleClick = this.click;

		var win = doc.ownerGlobal;
		this.redefDoSearch(win, win.customElements.get("searchbar").prototype);

		win.gBrowser.tabContainer.addEventListener("TabClose", this.tabClose);
		win.addEventListener("unload", this.winUnload, {once: true});
		this.quit = false;
	},
	winUnload(e) {
		var win = e.target.ownerGlobal;
		win.removeEventListener("TabClose", self.tabClose);
		if (self.quit) return;
		var gb = win.gBrowser;
		if (gb) for(var tab of gb.tabs) self.tabClose(null, tab);
	},
	closed: new Set(),
	cis: ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm")
		.ContextualIdentityService,
	tabClose(e, tab = e.target) {
		var id = +tab.getAttribute("usercontextid");
		id && self.gens.has(id) && self.closed.add(id);
		self.closed.size == 1 && ChromeUtils.idleDispatch(self.meaybeRemove);
	},
	meaybeRemove() {
		var ids = Array.from(self.closed);
		self.closed.clear();
		for(var id of ids) self.meaybeRemoveById(id);
	},
	meaybeRemoveById(id) {
		for(var win of CustomizableUI.windows)
			if (win.document.querySelector(`tab.tabbrowser-tab[usercontextid="${id}"]`))
				return;
		this.saveGens(this.gens.delete(id));
		this.cis.remove(id);
	},
	redefDoSearch(win, proto) {
		var code = `(openTrustedLinkIn => [
			{${proto.doSearch}}, openTrustedLinkIn
		])(
			function otl(url, where, params) {
				if (where != "current")
					params.userContextId = otl.newUsercontext(
						document.getElementById("searchbar").value
					);
				openTrustedLinkIn(url, where, params);
			}
		);`;
		(this.redefDoSearch = (win, proto) => {
			var [obj, func] = win.eval(code);
			Object.assign(proto, obj);
			func.newUsercontext = this.newUsercontext;
		})(win, proto);
	},
	click(btn, e) {
		if (!(e.button != 2 || e.ctrlKey || e.shiftKey)) {
			var txt = e.view.readFromClipboard();
			if (txt) {
				var urls = txt.split("\n").map(self.map).filter(Boolean);
				if (urls.length) return e.preventDefault(),
					self.openFromClipboard(e.view, urls);
			}
		}
		e.view.checkForMiddleClick(btn, e);
	},
	eo: Object.create(null),
	map(str) {
		str = str.trim();
		try {
			var scheme = Services.io.extractScheme(str);
			var ph = Services.io.getProtocolHandler(scheme);
			if (ph.scheme == scheme)
				return Services.io.newURI(str) && {uri: str};
		} catch {}
	},
	openFromClipboard(win, urls) {
		if (win.OpenInTabsUtils.confirmOpenInTabs(urls.length, win))
			urls.load = true,
			this.open(win, this.eo, urls);
	},
	async render() {
		this.rnd();
		await new Promise(this.ownerGlobal.requestAnimationFrame);
		this.hidden || (this.hidden = this.list.every(self.every));
	},
	every: node => node.disabled || node.hidden,
	cmd(win) {
		var view = this.parentNode._view;
		var node = win.document.popupNode;
		node = node._placesView && node._placesView.result.root;
		self.open(win, node || view.selectedNode || view.result.root);
	},
	open(win, node, list) {
		var gbw = Cu.import("resource:///modules/PlacesUIUtils.jsm", {}).getBrowserWindow;
		var w = gbw(win);
		this.pu = w.PlacesUIUtils;
		this.fs = w.PlacesUtils.favicons;
		this.sysp = w.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL;

		(this.open = (win, node, list) => {
			this.openURLs(gbw(win), list || win.PlacesUtils.getURLsForContainerNode(node));
			node.bookmarkGuid && this.pu.doCommand(win, "placesCmd_delete");
		})(win, node, list);
	},
	async openURLs(win, urls) {
		var userContextId = this.newUsercontext();
		var mark = !win.PrivateBrowsingUtils.isWindowPrivate(win);
		var {load} = urls, gb = win.gBrowser, pos = gb.selectedTab._tPos;

		for(var {uri, title, isBookmark} of urls) try {
			if (mark) isBookmark
				? this.pu.markPageAsFollowedBookmark(uri)
				: this.pu.markPageAsTyped(uri);

			if (load) {
				gb.addTrustedTab(uri, {index: ++pos, userContextId});
				continue;
			}
			var state = {userContextId, entries: [{
				url: uri,
				title: title || uri,
				triggeringPrincipal_base64: this.sysp
			}]};
			var [,, data, mime] = await new Promise(
				resolve => this.fs.getFaviconDataForPage(
					Services.io.newURI(uri), (...args) => resolve(args), 16
				)
			);
			if (data.length) state.image = `data:${
				mime || "image/x-icon"
			};base64,${
				btoa(String.fromCharCode(...data))
			}`;
			var tab = gb.addTrustedTab(null, {index: ++pos, userContextId});
			win.SessionStore.setTabState(tab, state);
		} catch {};
	}
}).init("chrome-document-loaded"))(
	"#placesContext_openBookmarkContainer\\:tabs,#placesContext_openContainer\\:tabs"
);


Просто супер, спасибо огромное, работает как часы

скрытый текст
Капец, ваше сообщение было на новой странице форума, а я обновлял несколько дней и не видел, думал праздники тишина на форуме :dumb:

Можно вас еще попросить добавить чтобы со строки поиска результат поиска открывался в конце списка вкладок?

Отредактировано Stkvsky (12-05-2021 06:07:22)

Отсутствует

 

№1555912-05-2021 17:07:34

kazarin
Участник
 
Группа: Members
Зарегистрирован: 23-11-2016
Сообщений: 24
UA: unknown 0.0

Re: Custom Buttons

Dobrov, ну вы же спрашивали про расширение в том числе.
Да я понял уже, что вам такой вариант решения неинтересен, надоедать больше не буду.

Отсутствует

 

№1556012-05-2021 21:29:50

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 1517
UA: Firefox 78.0

Re: Custom Buttons

Dobrov пишет

Это чтобы картинка сохранялась не Перетаскиванием, а по клику Колёсиком мыши на изображении

Это я понял (только тогда не понял почему ничего
не сказано что делать с autoscroller'ом и картинками-ссылками).
Я к тому, что это не называется «для кода заменить», это называется
сделать новый, совсем другой, ну кроме, собственно, сохранялки.

Сделал сохранение в путь: [Загрузки]/_Images/Имя вкладки, но вместо имени вкладки получаю "Mozilla Firefox" или "Новая вкладка". :-(

Нет, не сделал. Просто прицепил к path [Загрузки]/_Images
имя вкладки, такое, какое было на момент исполнения кода,
то есть при старте окна браузера (ничего удивительного в имени нет).
1. Это удалить

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

Выделить код

Код:

…
	var path = OS.Path.join(Services.dirsvc.get("DfltDwnld", Ci.nsIFile).path, "_Images", Title(100)); // папка [Загрузки]/_Images/Имя вкладки
	var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
	file.initWithPath(path);
	if ( !file.exists() || !file.isDirectory() ) file.create(Ci.nsIFile.DIRECTORY_TYPE, 0777); // создать папку, если не существует…


2. В коде, вместо статического path, определить геттер.
Строку «создать папку, если не существует» можно вынести наверх,
как следующую за var {path}…, если нет угрозы удаления папки _Images
за время использования кода.
скрытый текст

Выделить код

Код:

/*
				"browser.download.dir": {type: "String", set: path}
*/
				"browser.download.dir": {type: "String", get set() {
					var dir = Services.dirsvc.get("DfltDwnld", Ci.nsIFile);
					dir.append("_Images");
					var {path} = dir; // папка [Загрузки]/_Images

					Object.defineProperty(this, "set", {get() {
						dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать папку, если не существует…
						return PathUtils.join(path, DownloadPaths.sanitize(Title(100)));
					}});
					return this.set;
				}}

Stkvsky пишет

чтобы со строки поиска результат поиска открывался в конце списка вкладок

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

Выделить код

Код:

/*
				if (where != "current")
*/
				if (where != "current") params.resolveOnNewTabCreated =
					br => gBrowser.moveTabTo(
						gBrowser.getTabForBrowser(br), Infinity
					),

Отсутствует

 

№1556113-05-2021 03:25:45

Stkvsky
Участник
 
Группа: Members
Зарегистрирован: 26-06-2012
Сообщений: 1578
UA: Firefox 78.0

Re: Custom Buttons

Dumby
Класс, спасибо

Отсутствует

 

№1556213-05-2021 12:36:18

foxboy
Участник
 
Группа: Members
Зарегистрирован: 06-06-2015
Сообщений: 30
UA: Palemoon 24.0

Re: Custom Buttons

Dobrov пишет

Stkvsky пишетПодскажите как поставить Custom Buttons на 781) В папку, куда установлен Firefox, скопируй одноимённую папку из данного архива. (Костыли для FF)2) ставь обычным способом расширение custom_buttons-0.0.7.0.0.17-fx-bootstrap.xpi

На 78.10.1 ESR portable не ставится.

Отредактировано foxboy (13-05-2021 12:37:24)

Отсутствует

 

№1556313-05-2021 16:20:32

kokoss
Участник
 
Группа: Members
Зарегистрирован: 15-02-2018
Сообщений: 1119
UA: Firefox 52.0

Re: Custom Buttons

foxboy пишет

На 78.10.1 ESR portable не ставится.

custom_buttons-0.0.7.0.0.17-fx-paxmod.xpi


Win7

Отсутствует

 

№1556413-05-2021 19:56:07

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 25
UA: Chrome 90.0

Re: Custom Buttons

Здравствуйте форумчане. Как получить ip, активной вкладки?

Отсутствует

 

№1556514-05-2021 02:43:11

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 88.0

Re: Custom Buttons

Вопрос: как получить текст первого конкретного html-тэга текущей страницы? Так не работает: doc.getElementsByTagName("label")[0];


Dumby пишет

В коде, вместо статического path, определить геттер.

Расширение Text Linky Tool открывает страницу moz-extension://…/imglist.html, хочу доработать Сохранение картинки перетаскиванием,
чтобы создаваемое имя папки было осмысленным, а не moz-extension.
То есть, в код, где получаю Заголовок текущей вкладки, хочу добавить проверку, что это страница moz-extension:// и тогда брать заголовок из label-тэга текущей страницы.

Выделить код

Код:

<body>
    <label id="lblFrom">Custom Buttons | Форум Mozilla Россия(https://forum.mozilla-russia.org/viewtopic.php?id=9591&amp;p=623/page/2)</label>
    <label>Images Viewer</label><span id="spnCount"> - 65 pics</span>
kazarin пишет

Да я понял уже, что вам такой вариант решения неинтересен, надоедать больше не буду.

Не в интересе дело, а в том, что расширение Image Picka не подгружает картинки, по которым не кликали, то есть оно бесполезно!

Отредактировано Dobrov (14-05-2021 02:51:24)

Отсутствует

 

№1556614-05-2021 16:14:00

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 489
UA: Firefox 86.0

Re: Custom Buttons

Dumby
Посмотрите, пожалуйста, кнопкуSave, от 07.03.2017. .............
Идет неправильное сохранение через пункт "Сохранить всю страницу или выбранное как HTML"
Не сохраняются изображения и стили. При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда,
например здесь.

Отсутствует

 

№1556714-05-2021 18:12:24

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3038
UA: Firefox 88.0

Re: Custom Buttons

rubel
№15464

Отсутствует

 

№1556815-05-2021 01:44:38

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 25
UA: Chrome 90.0

Re: Custom Buttons

Подскажите пожалуйста, как можно сделать так, чтобы вкладка оставалась активной, даже после того, как осуществлён переход на другую вкладку?

Отредактировано Deriax (15-05-2021 12:25:43)

Отсутствует

 

№1556915-05-2021 02:41:25

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 489
UA: Firefox 86.0

Re: Custom Buttons

voqabuhe
Кнопка с твоей ссылки точно также не сохраняет изображения и стили. При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда.
Твой код применяю для UCF.

Отсутствует

 

№1557015-05-2021 03:56:16

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3038
UA: Firefox 88.0

Re: Custom Buttons

rubel пишет

При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда.

Точно, без инета не проверял. Действительно ерунда получается.

Отсутствует

 

№1557115-05-2021 10:00:03

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 87.0

Re: Custom Buttons

rubel пишет

Кнопка с твоей ссылки точно также не сохраняет изображения и стили. При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда.
Твой код применяю для UCF.

вот кнопка SaveHTML от Dumby, с моими доработками. Данная ссылка с рецептами без интернета открывается нормально.

Выделить код

Код:

(async (id, func) => { // дополнительные клики на downloads-button для custom_script_win.js
	await window.delayedStartupPromise;
	var btn = document.getElementById("downloads-button");
	if (!btn) return;
	btn.setAttribute("context", "event.stopPropagation()"); // откл контекстное меню
	btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) +`

ПКМ:	Сохранить единый .html
…Shift	Обзор папки «Загрузки»
Ролик:	Сохранить как файл .txt
		всё | выделенный текст
…Shift	Сайт: графика Вкл/Выкл
Alt⇧S	нажать SingleSave`; // если такой кнопки нет, то выполнить save()

	var addDestructor = nextDestructor => {
		var {destructor} = ucf[id];
		ucf[id].destructor = () => {
			try {destructor();} catch(ex) {Cu.reportError(ex);}
			nextDestructor();
		}
	}
	var saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt
		var splice = saveURL.length == 10;
		var msgName = id + ":Save:GetSelection";

		var receiver = msg => {
			var title = document.title || gBrowser.selectedTab.label;
			var args = [
				"data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data),
				title.replace(/[:\\\/<>?*|"]+/g,'_').replace(/\s+/g,' ').slice(0, 100).trim() + '_' + new Date().toLocaleString('ru').replace(', ','-').replace(/:/g, '։') + '.txt',
				null, false, true, null, window.document
			];
			splice && args.splice(5, 0, null);
			saveURL(...args);
		}
		messageManager.addMessageListener(msgName, receiver);
		addDestructor(() => messageManager.removeMessageListener(msgName, receiver));

		var func = fm => {
			var res, fed, win = {};
			var fe = fm.getFocusedElementForWindow(content, true, win);
			var sel = (win = win.value).getSelection();
			if (sel.isCollapsed) {
				var ed = fe && fe.editor;
				if (ed && ed instanceof Ci.nsIEditor)
					sel = ed.selection, fed = fe;
			}
			if (sel.isCollapsed)
				fed && fed.blur(),
				docShell.doCommand("cmd_selectAll"),
				res = win.getSelection().toString(),
				docShell.doCommand("cmd_selectNone"),
				fed && fed.focus();

			res = res || sel.toString();
			/\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res);
		}
		var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));';

		(saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	} // end

	var save = async () => { // автор: Лекс, правка: Dumby, Dobrov
		var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML";
		if (typeof IOUtils != "object") { // Firefox 78 ESR
			var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
			var PathUtils = {join: (...args) => OS.Path.join(...args)};
			var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))};
		}
		var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8";

		var Title = function (type) { // получить заголовок (без обрезки, если type не указан) или домен (type <0)
			var title = (document.title || gBrowser.selectedTab.label);
			if ( !type ) return title; // заголовок
			if ( type > 0 ) return title.substr(0, type).trim(); // ограничить длину имени
			var host = (/^file:\/\//.test(gURLBar.value)) ? '' : gURLBar.value.replace(/^.*url=/,'').replace(/^https?:\/\//,'').replace(/\/.*/,'');
			return host.replace(/^www\./,'').replace(/^ru\./,'').replace(/^m\./,'').replace(/^forum\./,'').replace(/^club\.dns/,'dns');
		}
		var FatMs = (str) => {return str.replace(/[:\\\/<>?*|"'`]+/g,'').replace(/\s+/g,' ').replace(/  /g,' ');}
		var msgListener = async msg => {
			var [fileContent, fileName] = msg.data;
			var savedir = PathUtils.join(await Downloads.getPreferredDownloadsDirectory(), "_Web", FatMs(Title(-1))); // каталог Загрузки + домен
			var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
			file.initWithPath(savedir);
			if ( !file.exists() || !file.isDirectory() ) file.create(Ci.nsIFile.DIRECTORY_TYPE, 0777); // создать папку, если не существует…
			var path = PathUtils.join(savedir, FatMs(fileName));
			await IOUtils[write](path, fileContent);
			var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(path)});
			(await Downloads.getList(Downloads.ALL)).add(d);
			d.refresh(d.succeeded = true); // кнопка Загрузки мигает
		}
		messageManager.addMessageListener(msgName, msgListener);
		addDestructor(() => messageManager.removeMessageListener(msgName, msgListener));

		var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services';
		var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName));
		(save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	} // end save

	var listener = e => { // Clicks
		var trg = e.target, {prefs} = Services;
		if (e.button == 1) {
			if (e.shiftKey) { // СКМ + Shift
				if ( prefs.getIntPref("permissions.default.image", 1) == 1)
					prefs.setIntPref("permissions.default.image", 2), trg.style.filter = "hue-rotate(180deg) brightness(95%)"
				else
					prefs.setIntPref("permissions.default.image", 1), trg.style.filter = "";
				BrowserReload();
			} else	// СКМ Click
				saveSelectionToTxt(); // сохранить .txt
		} else if (e.button == 2) {
			if (e.shiftKey)
				Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки»
			else	// ПКМ Click
				save(); // Single HTML
		}
	}
	var keydown_win = e => { // нажатие клавиш
		if (!(e.keyCode == 83 && e.shiftKey && e.altKey)) return;
		var singlesave = document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"); // SingleSave
		singlesave ? singlesave.click() : save(); // имитировать клик по кнопке, используя её ID
	}
	btn.addEventListener("click", listener);
	window.addEventListener("keydown", keydown_win);
	var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win;
	ucf[id] = {destructor() {
		btn.removeEventListener("click", listener);
		window.removeEventListener("keydown", keydown_win);
	}};
	ucf.unloadlisteners.push(id);

})("downloads-button-click-listener", ({io, focus}) => {

	var resolveURL = function (url, base) {
		try {
			return io.newURI(url, null, io.newURI(base)).spec;
		} catch {}
	};
	var getSelWin = function (w) {
		if (w.getSelection().toString()) return w;
		for (var i = 0, f, r; f = w.frames[i]; i++) {
			try {
				if (r = getSelWin(f)) return r;
			} catch(e) {}
		}
	};
	var encodeImg = function (src, obj) {
		var canvas, img, ret = src;
		if (/^https?:\/\//.test(src)) {
			canvas = doc.createElement('canvas');
			if (!obj || obj.nodeName.toLowerCase() != 'img') {
				img = doc.createElement('img');
				img.src = src;
			} else {
				img = obj;
			};
			if (img.complete) try{
				canvas.width = img.width;
				canvas.height = img.height;
				canvas.getContext('2d').drawImage(img, 0, 0);
				ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png'));
			} catch (e) {};
			if (img != obj) img.src = 'about:blank';
		};
		return ret;
	};
	var toSrc = function (obj) {
		var strToSrc = function (str) {
			var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'};
			while (chr = str.charAt(i++)) {
				ret += meta[chr] || chr;
			};
			return '\x22' + ret + '\x22';
		},
		arrToSrc = function (arr) {
			var ret = [];
			for (var i = 0; i < arr.length; i++) {
				ret[i] = toSrc(arr[i]) || 'null';
			};
			return '[' + ret.join(',') + ']';
		},
		objToSrc = function (obj) {
			var val, ret = [];
			for (var prop in obj) {
				if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val);
			};
			return '{' + ret.join(',') + '}';
		};
		switch (Object.prototype.toString.call(obj).slice(8, -1)) {
			case 'Array': return arrToSrc(obj);
			case 'Boolean':
			case 'Function':
			case 'RegExp': return obj.toString();
			case 'Date': return 'new Date(' + obj.getTime() + ')';
			case 'Math': return 'Math';
			case 'Number': return isFinite(obj) ? String(obj) : 'null';
			case 'Object': return objToSrc(obj);
			case 'String': return strToSrc(obj);
			default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null';
		}
	};
	var mainWin = {};
	focus.getFocusedElementForWindow(content, true, mainWin);
	mainWin = mainWin.value;

	var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location;
	var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g;

	if (selWin) {
		var rng = win.getSelection().getRangeAt(0);
		pEle = rng.commonAncestorContainer;
		ele = rng.cloneContents();
	} else {
		pEle = doc.documentElement;
		ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true);
	};
	while (pEle) {
		if (pEle.nodeType == 1) {
			clone = pEle.cloneNode(false);
			clone.appendChild(ele);
			ele = clone;
		};
		pEle = pEle.parentNode
	};
	var sel = doc.createElement('div');
	sel.appendChild(ele);

	for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) {
		el = all[i];
		if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) {
			if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href);
			return prev + encodeImg(url) + next;
		});
		switch (el.nodeName.toLowerCase()) {
			case 'link':
			case 'style':
			case 'script': el.parentNode.removeChild(el); break;
			case 'a': 
			case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break;
			case 'img':
			case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break;
			case 'audio':
			case 'video':
			case 'embed':
			case 'frame':
			case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break;
			case 'object': if (el.hasAttribute('data')) el.data = el.data; break;
			case 'form': if (el.hasAttribute('action')) el.action = el.action; break;
		}
	};
	var head = ele.insertBefore(doc.createElement('head'), ele.firstChild);
	var meta = doc.createElement('meta');
	meta.httpEquiv = 'content-type';
	meta.content = 'text/html; charset=utf-8';
	head.appendChild(meta);
	var title = doc.getElementsByTagName('title')[0];
	if (title) head.appendChild(title.cloneNode(true));

	head.copyScript = function (unsafeWin) {
		if ('$' in unsafeWin) return;
		var f = doc.createElement('iframe');
		f.src = 'about:blank';
		f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;');
		doc.documentElement.appendChild(f);
		var str, script = doc.createElement('script');
		script.type = 'text/javascript';
		for (var name in unsafeWin) {
			if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue;
			try {
				str = toSrc(unsafeWin[name]);
				if (!/\{\s*\[native code\]\s*\}/.test(str)) {
					script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n'));
				}
			} catch (e) {};
		};
		f.parentNode.removeChild(f);
		if (script.childNodes.length) this.nextSibling.appendChild(script);
	};
	head.copyScript(win.wrappedJSObject || win);

	head.copyStyle = function (s) {
		if (!s) return;
		var style = doc.createElement('style');
		style.type = 'text/css';
		if (s.media && s.media.mediaText) style.media = s.media.mediaText;
		try {
			for (var i = 0, rule; rule = s.cssRules[i]; i++) {
				if (rule.type != 3) {
					if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
						var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
							if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
							if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
							return prev + url + next;
						});
						style.appendChild(doc.createTextNode(css + '\n'));
					}
				} else {
					this.copyStyle(rule.styleSheet);
				}
			}
		} catch(e) {
			if (s.ownerNode) style = s.ownerNode.cloneNode(false);
		};
		this.appendChild(style);
	};
	var sheets = doc.styleSheets;
	for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
	head.appendChild(doc.createTextNode('\n'));

	var doctype = '', dt = doc.doctype;
	if (dt && dt.name) {
		doctype += '<!DOCTYPE ' + dt.name;
		if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
		if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
		doctype += '>\n';
	};

	var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop());
	fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).trim();
	fileName += "_" + new Date().toLocaleString("ru").replace(", ","-").replace(/:/g, "։");
	if (!/\.html?$/.test(fileName)) fileName += '.html';

	sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', fileName]);

}); // END hookClicks

Отсутствует

 

№1557216-05-2021 03:27:43

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 87.0

Re: Custom Buttons

Dumby - есть два кода, показывающих при наведении на Звёздочку адрес закладки или последнюю папку, куда добавлялась закладка.


Первый работает в custom_script_win.js , а Второй почему-то только в кнопке CustomButton.
Нужно устранить три недостатка либо первого либо второго скрипта (ещё второй не работает в custom_script_win.js):
1) Оба скрипта зачем-то удаляют стандартную подсказку Звёздочки: у меня это «Добавить страницу в Закладки (⌘D)».
2) Нет строки "Недавняя папка\n:" перед текстом последней папки, куда добавлялась закладка [как в этом же коде "Адрес закладки:\n"]. Я не смог найти строку кода, где нужно добавить этот текст!
3) нет обработки кликов Звёздочки, я их добавил в более старый вариант, но у него нет "Недавней папки":

Выделить код

Код:

try {((bu, bm, {star} = bu) => { // показать расположение закладки в Избранном. Клики на Звёздочке:
	var listener = { 	// СКМ: Вернуть вкладку, СКМ+Alt страница about:newtab, СКМ+Shift google.ru
		async handleEvent() {
			var result = [];
			await this.fetch();
			for(var guid of this.guids) {
				var arr = [];
				while(true) {
					if (!this.hover) return;
					var res = await bm.fetch(guid);
					if ((guid = res.parentGuid) == bm.rootGuid) {
						arr.unshift(bm.getLocalizedTitle(res));
						break;
					}
					arr.unshift(res.title || "[Безымянная папка]");
				}
				result.push(arr.join("\\"));
			}
			this.hover && this.setTooltip(result);
		},
		get fetch() {
			var set = this.guids = new Set();
			var args = [b => set.add(b.parentGuid), {concurrent: true}];
			delete this.fetch; return this.fetch = () => set.clear()
				|| bm.fetch({url: gBrowser.currentURI.spec}, ...args);
		},
		setTooltip(arr) {
			var m = arr.length > 1;
			var help = '\nРолик:	Вернуть вкладку \n…+Alt	Быстрый доступ\n…+Shift	поиск в Google', text = `Адрес${m ? "а" : ""} заклад${m ? "ок" : "ки"}:\n${arr.join("\n")}\n`+ help;
			if (bu._itemGuids.size)
				star.tooltipText = "\u3164"
			else
				text = star.tooltipText + help;
			if (/Ролик/.test(star.tooltipText)) return;
			document.tooltipNode == star ? this.tt.label = text : star.tooltipText = text;
		},
		get tt() {
			var list = InspectorUtils.getChildrenForNode(document.documentElement, true);
			delete this.tt; return this.tt = list.item(list.length - 1);
		},
		get hover() {return star.matches(":hover");}
	},
	loadURI_ex = (url, newtab) => { newtab = newtab || false; // параметры по-умолчанию
		if (newtab)
			switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()})
		else
			gBrowser.loadURI(url, {triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
	},
	clicks = e => { if (e.button != 1) return; // CKM Click
		if (e.shiftKey)
			loadURI_ex('https://www.google.ru', true)
		else if (e.altKey)
			loadURI_ex('about:newtab')
		else
			document.defaultView.undoCloseTab();
	};
	star.addEventListener("mouseenter", listener);
	star.addEventListener("click", clicks);
	addEventListener("unload", () => {
			star.removeEventListener("mouseenter", listener);
			star.removeEventListener("click", clicks)
		}
	, {once: true});
})(BookmarkingUI, PlacesUtils.bookmarks);} catch(ex) {Cu.reportError(ex);}

Отсутствует

 

№1557316-05-2021 05:38:15

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 489
UA: Firefox 86.0

Re: Custom Buttons

Dobrov пишет

вот кнопка SaveHTML от Dumby, с моими доработками

Что-то у меня ничего не получилось с этим кодом. Создал файл SaveHTML.js,  прописал его в загрузчик custom_script_win.js.
Никаких кнопок, меню ни где не появилось, в коде написано дополнительные клики на downloads-button для custom_script_win.js. А что это такое downloads-button ? у меня вроде нигде нет такого.:)

Отсутствует

 

№1557416-05-2021 06:57:09

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 207
UA: Firefox 87.0

Re: Custom Buttons

rubel это стандартная кнопка «Загрузки», всё и так ясно по названию downloads-button.


Alt+Shift+S для сохранения страницы или жми на «Загрузки» правой кнопкой мыши, включив постоянный показ:
Персонализация > Правый клик на кнопке «Загрузки» > Снять флажок: Автоматически скрывать на панели инструментов.

Отсутствует

 

№1557516-05-2021 07:20:59

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 489
UA: Firefox 86.0

Re: Custom Buttons

Dobrov
ОК. Спасибо, все работает и сохраняет как надо ! Но вот путь сохранения для меня не удобен, да еще и по домену.
У меня все сохраняется в "D:\Downloads" вот нужно и прописать в ваш скрипт этот путь. Как правильно прописать ?
И еще бы сделать при сохранение открытие  диалогового окна, чтобы корректировать имя файла. :)

Отредактировано rubel (16-05-2021 07:32:26)

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]