Kamui
брал у bunda1 08-05-2011 18:52:05
открываю http://forum.mozilla-russia.org/img/browsers/firefox35.png
нажимаю 3й пункт и ничего. фавиконы на сайтах копирует в base64, а картинки не хочет
в чём может быть причина?
проверил на фаерфокс в которой установлены только два дополнения CB и стайлишь. тоже самое
Отредактировано skynet281978 (09-07-2012 08:57:27)
Отсутствует
Kamui
брал у bunda1 08-05-2011 18:52:05
открываю http://forum.mozilla-russia.org/img/browsers/firefox35.png
нажимаю 3й пункт и ничего. фавиконы на сайтах копирует в base64, а картинки не хочет
Дополнительные возможности;
Если нажать правой клавишей мыши пункт Сохранить изображение как… в контекстном меню изображений на странице, изображение будет сохранено как base64 код в буфере обмена.
Отсутствует
bunda1 да, теперь копируется, спасибо.
Мемори монитор: как варьировать расстояние между букв MB и разделителем справа? в кнопке или стилем?
Отсутствует
Да большие страницы не сохраняет выбрасывает эту ошибку, интересно с в чем тут проблема.
Ай, только там return нельзя делать, надо еще mainWindow.removeChild(scrollbox); сделать.
Есть вот такое:
Canvas fails with a width > 65535, unconfirmed
google maps webgl broken: "Component returned failure code: 0x8007000e (NS_ERROR_OUT_OF_MEMORY) [nsIDOMHTMLCanvasElement.width]
скорее всего в таймаутах - попробуй в конфиге выставить ожидание для скриптов побольше.
Да нет там никакого ожидания, тупо сразу ошибка:
var width = 10; var height = 33000; var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); canvas.style.display = "none"; canvas.width = width; canvas.height = height; document.documentElement.appendChild(canvas); try { var ctx = canvas.getContext("2d"); //ctx.clearRect(0, 0, width, height); var url = canvas.toDataURL("image/png"); // Error: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) alert("Ok"); } catch(e) { Components.utils.reportError(e); } document.documentElement.removeChild(canvas);
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Придумалось извращение для скриншотов больших страниц:
saveScreenshot(content || window); function saveScreenshot(win) { var ww = win.innerWidth + win.scrollMaxX; var wh = win.innerHeight + win.scrollMaxY; var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); var maxIterations = 500; var stopTime = Date.now() + 10000; var w = ww; var h = wh; var dw = ww; var dh = wh; function canNext() { return i < maxIterations && Date.now() < stopTime && (dw >= 2 || dh >= 2); } function message(title, s) { Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService) .alert(window, "Save Screenshot :: " + title, s); } var lastErr; for(var i = 0; ; ++i) { try { canvas.width = w; canvas.height = h; var context = canvas.getContext("2d"); context.drawWindow(win, 0, 0, w, h, "rgb(255, 255, 255)"); var url = canvas.toDataURL("image/png"); if(i && canNext()) { if(h > w && h < wh && dh >= 2) h += (dh /= 2); else if(w < ww) w += (dw /= 2); continue; } i && setTimeout(function() { message( "Warning", "Can't save entire page: " + ww + "x" + wh + " => " + Math.round(w) + "x" + Math.round(h) + "\nLast error:\n" + lastErr ); }, 0); var fileName = win.document.title .replace(/[\\\/:*?"<>|\s]+/g, "_"); if("saveImageURL" in window) saveImageURL(url, fileName + ".png"); else { Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator) .getMostRecentWindow("navigator:browser") .saveImageURL(url, fileName + ".png"); } return true; } catch(e) { lastErr = e; if(!canNext()) { Components.utils.reportError(e); message("Error", "Iteration: " + i + "\nError:\n" + e); break; } if(h > w && dh >= 2) h -= (dh /= 2); else w -= (dw /= 2); } } return false; }
При возникновении ошибок уменьшает высоту/ширину с ограничением времени и количества итераций.
Добавлено 09-07-2012 18:05:11
Обновил, теперь можно вызывать с помощью Mouse Gestures в любом окне.
Отредактировано Infocatcher (09-07-2012 18:05:11)
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Infocatcher
Ты реально крут, такой полезный код сделал.
Я сейчас ради эксперимента сохранил как PNG целый роман из lib.rus.ec на 1,76 МБ. При этом почему то выскакивает alert с ошибкой
Can't save entire page: 1024x104216 => 1024x32568 Last error: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMCanvasRenderingContext2D.drawWindow]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button13@code :: saveScreenshot :: line 33" data: no]
Отсутствует
bunda1
Не всю.
С ошибками при больших размерах ничего не сделать, разве что разделить на части и сохранить в несколько файлов.
1024x104216 => 1024x32568
Ну вот страничка и урезалась до 1024x32568.
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Было бы не плохо если страница после сохранения сама прокрутилас до => 1024x32568.
Типа намёк на продолжение.
Да какой-то это не намек, а дразнилка.
Можно вот так:
saveScreenshot(content || window); function saveScreenshot(win) { var ww = win.innerWidth + win.scrollMaxX; var wh = win.innerHeight + win.scrollMaxY; var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); var maxIterations = 200; var stopTime = Date.now() + 12000; var w = ww; var h = wh; var dw = ww; var dh = wh; function canNext() { return i < maxIterations && Date.now() < stopTime && (dw >= 2 || dh >= 2); } function message(title, s) { Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService) .alert(window, "Save Screenshot :: " + title, s); } function getFileName(iw, ih) { return fileName + (cw > 1 || ch > 1 ? "-part" : "") + (ch > 1 ? "-" + ih : "") + (cw > 1 ? "-" + iw : "") + ".png"; } var lastErr; for(var i = 0; ; ++i) { try { canvas.width = w; canvas.height = h; var context = canvas.getContext("2d"); context.drawWindow(win, 0, 0, w, h, "rgb(255, 255, 255)"); var url = canvas.toDataURL("image/png"); if(i && canNext()) { if(h > w && h < wh && dh >= 2) h += (dh /= 2); else if(w < ww) w += (dw /= 2); continue; } if(i) { var cw = Math.ceil(ww/w); var ch = Math.ceil(wh/h); setTimeout(function() { message( "Warning", "Can't save entire page: " + ww + " x " + wh + " => " + Math.round(w) + " x " + Math.round(h) + "\nParts: " + cw + " x " + ch + " = " + cw*ch + "\n\nLast error:\n" + lastErr ); }, 0); } var fileName = win.document.title .replace(/[\\\/:*?"<>|\s]+/g, "_"); var saveImageURL = "saveImageURL" in window ? window.saveImageURL // See chrome://global/content/contentAreaUtils.js : Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator) .getMostRecentWindow("navigator:browser") .saveImageURL; saveImageURL(url, getFileName(1, 1)); if(i) { // Try save page parts... for(var ih = 1; ih <= ch; ++ih) { for(var iw = 1; iw <= cw; ++iw) { var x = w*(iw - 1); var y = h*(ih - 1); if(!x && !y) // This is initial part, already saved continue; var _w = iw < cw ? w : ww - x; var _h = ih < ch ? h : wh - y; setTimeout(function(x, y, w, h, iw, ih) { canvas.width = w; canvas.height = h; context = canvas.getContext("2d"); context.drawWindow(win, x, y, w, h, "rgb(255, 255, 255)"); url = canvas.toDataURL("image/png"); saveImageURL(url, getFileName(iw, ih)); }, 0, x, y, _w, _h, iw, ih); } } } return true; } catch(e) { lastErr = e; if(!canNext()) { Components.utils.reportError(e); message("Error", "Iteration: " + i + "\nError:\n" + e); break; } if(h > w && dh >= 2) h -= (dh /= 2); else w -= (dw /= 2); } } return false; }
Будет сохранять частями в отдельные файлы.
Только saveImageURL() не позволяет обработать отмену.
И можно получить NS_ERROR_OUT_OF_MEMORY для только что сработавшего размера.
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Только saveImageURL() не позволяет обработать отмену.
И можно получить NS_ERROR_OUT_OF_MEMORY для только что сработавшего размера.
Попробовал, грузит браузер не по детски. И saveImageURL() пока не сохранит все не останавливается. Эх.
Отсутствует
bunda1, а если для сохранения тяжёлых страниц внешний скриншотер припахать?
Отсутствует
bunda1, а если для сохранения тяжёлых страниц внешний скриншотер припахать?
Да это возможно, запустить скриншотер с какими то параметрами. Я что то такое выдел в сборке Oперы страница сохранялась скриншотером SiteShoter специальной кнопкой на подобие CB. Но не все скриншотеры это поддерживают и я не знаю как это сделать.
Отсутствует
bunda1, Для K-Meleon есть CapturePlus , правда это расширение , но может можно сам принцип реализации посмотреть ? Там PicPick используется.
Отсутствует
2 сделать такой вариант - смотрим размеры и если они слишком большие то предупреждаем пользователя что страница будет обрезана и сохраняем обрезанный вариант без всякого гимора.
Никто не гарантирует, что добавление ограничения уберет ошибки.
И уже есть: http://forum.mozilla-russia.org/viewtop … 25#p571425
Еще можно добавить начальное предположение, тогда, пока там ничего не починят/поломают, подбор наибольшего допустимого размера будет быстрее:
saveScreenshot(content || window); function saveScreenshot(win) { var ww = win.innerWidth + win.scrollMaxX; var wh = win.innerHeight + win.scrollMaxY; var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); var maxIterations = 200; var stopTime = Date.now() + 12000; var okSize = 32000; var w = ww; var h = wh; var dw = ww; var dh = wh; function canNext() { return i < maxIterations && Date.now() < stopTime && (dw >= 2 || dh >= 2); } function message(title, s) { Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService) .alert(window, "Save Screenshot :: " + title, s); } var lastErr; for(var i = 0; ; ++i) { try { canvas.width = w; canvas.height = h; var context = canvas.getContext("2d"); context.drawWindow(win, 0, 0, w, h, "rgb(255, 255, 255)"); var url = canvas.toDataURL("image/png"); if(i && canNext()) { if(h > w && h < wh && dh >= 2) h += (dh /= 2); else if(w < ww) w += (dw /= 2); continue; } i && setTimeout(function() { message( "Warning", "Can't save entire page: " + ww + " x " + wh + " => " + Math.round(w) + " x " + Math.round(h) + "\nLast error:\n" + lastErr ); }, 0); var fileName = win.document.title .replace(/[\\\/:*?"<>|\s]+/g, "_"); if("saveImageURL" in window) saveImageURL(url, fileName + ".png"); else { Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator) .getMostRecentWindow("navigator:browser") .saveImageURL(url, fileName + ".png"); } return true; } catch(e) { lastErr = e; if(!i) { w = dw = Math.min(w, okSize); h = dh = Math.min(h, okSize); continue; } if(!canNext()) { Components.utils.reportError(e); message("Error", "Iteration: " + i + "\nError:\n" + e); break; } if(h > w && dh >= 2) h -= (dh /= 2); else w -= (dw /= 2); } } return false; }
хочу воткнуть на таб еще одну кнопку но чтоб отдельным расширением
Расширение, переопределяющее binding для tab'а может быть только одно.
Правда, можно сделать расширяющий binding с наследованием, только для поддержки каждого расширения нужен будет отдельный binding.
Но можно попытаться генерировать нужный binding «на лету», только вот по протоколу file: подключить нельзя из-за ограничений безопасности, неизвестно, можно ли использовать resource:, а chrome: нельзя настраивать программно.
Так что или одно расширение, или при каждом открытии вкладки добавлять на нее кнопки вручную.
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Скажите, пожалуйста, почему при переинициализации всех кнопок (она происходит каждый раз, когда закрывается палитра инструментов при настройке панелей инструментов) обработчики событий, заданные в коде инициализации, дублируются? Однако при редактировании кнопки такого не происходит.
Здесь, например, написано:
If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, and since the duplicates are discarded, they do not need to be removed manually with the removeEventListener method.
Однако для такой тестовой кнопки:
this.clickBtn = function(event) {
if (event.button == 0) {
event.preventDefault();
alert("cb click " + Date.now());
}
}
this.addEventListener("click", this.clickBtn, true);
каждая переинициализация после закрытия палитры инструментов добавляет по одному alert при нажатии (их на одно нажатие будет столько, сколько раз за сессию вызывалась настройка панелей инструментов). Однако если отредактировать саму кнопку, инициализация после редактирования обнулит все обработчики и alert опять будет один.
Есть ли способ избежать таких наслоений одинаковых обработчиков?
Отредактировано homo_nudus (10-07-2012 17:50:31)
Отсутствует
okkamas_knife
Какой именно код некорректный и в чём?
Удаление не помогает, этот код ведёт себя точно так же:
this.clickBtn = function(event) {
if (event.button == 0) {
event.preventDefault();
alert("cb click " + Date.now());
}
}
this.removeEventListener("click", this.clickBtn, true);
this.addEventListener("click", this.clickBtn, true);
В упомянутой цитате сказано, что при добавлении такого же обработчика с теми же параметрами удалять не нужно, дубликаты отбрасываются. Можно предположить, что при переинициализации this.clickBtn — уже другая функция (даже если её код одинаков), поэтому происходит дублирование и поэтому удаление бесполезно. Но почему же при редактировании кнопки такого эффекта нет, хотя и тогда происходит повторная инициализация?
Отредактировано homo_nudus (10-07-2012 18:02:46)
Отсутствует
okkamas_knife
Проверил на 13.0.1. Та же самая проблема, только при инициализации после закрытия палитры в консоли появляется сообщение об ошибке:
Ошибка: uncaught exception: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIObserverService.removeObserver]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: chrome://browser/content/search/search.xml :: :: line 90" data: no]
Однако оно относится не к расширению, а к панели поиска (если его удалить в палитру, при последующих закрытиях палитры этой ошибки не возникает, но обработчики событий всё равно наслаиваются). Так что у меня и на 13.0.1 та же проблема. А вы проверяли на 13.0?
Отсутствует
homo_nudus
Скорее всего, кнопка при сохранении из редактора пересоздается.
Вот так двоится и при сохранении:
window.addEventListener("click", function(e) { if(e.button == 1) alert("cb: middle-click"); }, true);
Так что надо или реализовать this.onDestroy() для зачистки, или использовать
из \chrome\custombuttons.jar\content\custombuttons\contextBuilder.js (chrome://custombuttons/content/contextBuilder.js)
Добавлено 10-07-2012 18:58:43
Да, а функции там каждый раз новые создаются через new Function() для кода, поэтому проще подчищать из того же кода, который «наследил».
Ну, или экспортировать что-нибудь в window, например.
Отредактировано Infocatcher (10-07-2012 18:58:43)
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Скажите, пожалуйста, почему при переинициализации всех кнопок (она происходит каждый раз, когда закрывается палитра инструментов при настройке панелей инструментов) обработчики событий, заданные в коде инициализации, дублируются?
Это баг Custom Buttons, появился на FF4.
Однако для такой тестовой кнопки:
Используй код с которым проблем нет:
this.onclick = function(event) { if(event.button == 0) { // Действие при клике ЛКМ } else if(event.button == 1) { // Действие при клике СКМ } else if(event.button == 2 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) { // Действие при клике ПКМ без модификаторов } }; this.oncontextmenu = function(event) { if(event.button == 2 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) { // Блокируем контекстное меню при клике ПКМ без модификаторов event.preventDefault(); event.stopPropagation(); } };
Однако если отредактировать саму кнопку, инициализация после редактирования обнулит все обработчики и alert опять будет один.
Если отредактировать кнопку обработчики событий тоже дублируются, это проверено. Но похоже что бывает исключения.
Отредактировано bunda1 (10-07-2012 19:08:58)
Отсутствует
Infocatcher
Ваш код двоится при пересохранении, потому что анонимная функция не может восприниматься как один и тот же обработчик, она всегда создаётся заново (см., например. этот раздел по поводу анонимный функций).
Попробую сейчас помудрить с onDestroy. Тут есть рецепт с window, но он меня немного пугает. Да и неправильное ведь всё равно поведение получается с этими обработчиками.
bunda1
Попробую и так, спасибо.
Может, они дублируются, только если функция анонимна или если она объявлена, но не привязана как свойство к кнопке?
Отредактировано homo_nudus (10-07-2012 19:11:51)
Отсутствует
Есть ли способ избежать таких наслоений одинаковых обработчиков?
Я это решаю по простому. Не самый лучший метод - для редактирования нужен рестарт и могут быть проблемы с глобальными переменными:
//Стоп, при открытии настройки панелей.................................................... if (window.qwertyRun == 'stop') return; this.clickBtn = function(event) { if (event.button == 0) { event.preventDefault(); alert("cb click " + Date.now()); } } this.addEventListener("click", this.clickBtn, true); window.qwertyRun = 'stop';
Или так, но такой вариант по неизвестным мне причинам не всегда работает:
// удаление обработчиков для адресной строки, при открытии настройки панелей this.onDestroy = function() { document.getElementById("urlbar").removeEventListener("dblclick", mclick, false); document.getElementById("urlbar").removeEventListener("mousedown", function(e){if(!gURLBar.focused) goDoCommand("cmd_copy");}, false) }; // добавляем обработчики для адресной строки........ document.getElementById("urlbar").addEventListener("dblclick", mclick, false); //копировать выделенный текст на странице document.getElementById("urlbar").addEventListener("mousedown", function(e){if(!gURLBar.focused) goDoCommand("cmd_copy");}, false);
И может это будет полезно:
Using onDestroy Method
/*Initialization code*/ // constructor example - change button type property // destructor example - close window // update example - edit button // delete example - delete button LOG("test 2"); this.onDestroy = function(reason) { LOG("test 1"); if (reason == "constructor") LOG("constructor"); if (reason == "destructor") LOG("destructor"); if (reason == "update") LOG("update"); if (reason == "delete") LOG("delete"); }
Отредактировано bunda1 (10-07-2012 19:35:39)
Отсутствует
Ваш код двоится при пересохранении, потому что анонимная функция не может восприниматься как один и тот же обработчик, она всегда создаётся заново
Да все они заново создаются:
function f0(e) { if(e.button == 1) alert("cb: middle-click - 0"); } window.addEventListener("click", f0, true); var f1 = function _f1(e) { if(e.button == 1) alert("cb: middle-click - 1"); }; window.addEventListener("click", f1, true); this.f2 = function(e) { if(e.button == 1) alert("cb: middle-click - 2"); }; window.addEventListener("click", this.f2, true);
Добавлено 10-07-2012 19:35:02
Или так, но такой вариант по неизвестным мне причинам не всегда работает:
removeEventListener() удалит только ту же функцию, что была добавлена через addEventListener().
А
создает новую функцию и никуда не сохраняет ссылку на нее.
Отредактировано Infocatcher (10-07-2012 19:35:02)
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует
Infocatcher, bunda1
Да, любой из этих кодов работает:
-----------------------------------------------------------------
this.clickBtn = function(event) {
if (event.button == 0) {
event.preventDefault();
alert("cb click " + Date.now());
}
}
this.addEventListener("click", this.clickBtn, true);
this.onDestroy = function() {
this.removeEventListener("click", this.clickBtn, true);
}
-----------------------------------------------------------------------------
this.clickBtn = function(event) {
if (event.button == 0) {
event.preventDefault();
alert("cb click " + Date.now());
}
}
this.onclick = this.clickBtn;
---------------------------------------------
Жаль только, что оба не очень красивы (добавления свойств window и подавно хотелось бы избегать). Onclick обычно советуют заменять на addEventListener (гибкий и стандартизированный метод), а вся эта суматоха с onDestroy выглядит костылями.
Большое спасибо всем за помощь.
Отредактировано homo_nudus (10-07-2012 19:37:40)
Отсутствует
А вот так работает:
function f(e) { if(e.button == 1) alert("cb: middle-click"); } window.addEventListener("click", f, true); this.onDestroy = function() { window.removeEventListener("click", f, true); };
И вот так:
function f(e) { if(e.button == 1) alert("cb: middle-click"); } addEventListener("click", f, true); // Функция addEventListener переопределена, и removeEventListener() вызовется автоматически при пересоздании кнопки
Добавлено 10-07-2012 19:39:34
Onclick обычно советуют заменять на addEventListener
Отделение разметки от кода ради отделения разметки от кода?
Отредактировано Infocatcher (10-07-2012 19:39:34)
Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела
Отсутствует