JavaScript

индекс
246,46

Сохранение по Ctrl+S в браузере

Могу ошибаться, но решения данной проблемы на Хабре еще не приводилось, так что позвольте поделиться с вами полезным куском кода. Задача: по нажатию Ctrl+S заблокировать браузерный диалог о сохранении страницы и запустить пользовательскую функцию.

Проблема

При редактировании данных в формах вместо прилагающейся кнопки "Сохранить" иногда так и хочется нажать привычное Ctrl+S. Это неизменно приводит к появлению стандартного браузерного диалога, который предложит вам сохранить текущую html-страницу.

С помощью JavaScript попытаемся:
* заблокировать появление диалога о сохранении;
* отловить нажатие клавиш и запустить клиентскую функцию, которая, к примеру, может запустить ajax-submit ваших данных;

Для блокирования стандартной обработки событий в браузере используются:
* Метод preventDefault() объекта event. Поддерживается в Gecko и Opera.
* Свойство returnValue объекта event, поддерживаемое в IE.

Обработчики вешаем с помощью специальной функции addHandler, чтобы не менять лишний раз HTML-код.В зависисмости от браузера блокирование производится для события keydown или keypress. После того, как диалог о сохранении будет убит, можно вызвать угодную нам функцию.

Код


// Функция для добавления обработчиков событий
function addHandler(object, event, handler, useCapture) {
if (object.addEventListener) {
object.addEventListener(event, handler, useCapture ? useCapture : false);
} else if (object.attachEvent) {
object.attachEvent('on' + event, handler);
} else alert("Add handler is not supported");
}

// Определяем браузеры
var ua = navigator.userAgent.toLowerCase();
var isIE = (ua.indexOf("msie") != -1 && ua.indexOf("opera") == -1);
var isGecko = (ua.indexOf("gecko") != -1);


// Добавляем обработчики
if (isIE) addHandler (document, "keydown", hotSave);
else addHandler (document, "keypress", hotSave);

function hotSave(evt) {
// Получаем объект event
evt = evt || window.event;
var key = evt.keyCode || evt.which;
// Определяем нажатие Ctrl+S
key = String.fromCharCode(key).toLowerCase() == "s";
if (evt.ctrlKey && key) {
// Блокируем появление диалога о сохранении
if(evt.preventDefault) evt.preventDefault();
evt.returnValue = false;
// Запускаем любую функцию, по желанию
clientFunction();
// Возвращаем фокус в окно
window.focus();
return false;
}
}
function clientFunction() {
// И тут что-то происходит...
}


Плагин для jQuery, размещенный на Google Code

Использование

Работоспособность проверена в:
* WIN: IE6, IE7;
* WIN: FF 1.5, NN 7.1, NN 8.0, Mozilla 1.7;
* WIN: Opera 7.1, 7.5, 8.0, 9.01, 9.2;
* MAC: Пишут, что по Mac OS X + FF3b5 работает (но имеено Ctrl+S, а не Command+S);

Не работает:
* в Лисе под Linux и Mac OS X при сохранении по Ctrl+Ы. Для фикса нужен патч браузера.

Приведенный выше скрипт успешно протестирован в системе редактирования баз данных Flede. Привычное нажатие Ctrl+S, и база на вашем хосте получила новые данные, а вы остались на нужной странице и пишите дальше :-)

Если скрипт не работатет в других браузерах или платформах, пишите в комментах!

Кросспост Сохранение по Ctrl+S в браузере c webew.ru
+34
16 мая 2008, 12:44
78
bur

комментарии (91)

+1
rgbeast #
В системе Flede это сейчас работает в версии 0.73rc, которая доступна с svn. Есть одно пожелание - в firefox под линукс нажатие Ctrl-Ы не срабатывает как Ctrl-S. Это бага firefox, но можно ли пофиксить средствами JS?
0
bur #
Это особенность Лисы именно под Линукс, под вин — всё ОК.
Да, надо потестить. Как только доберусь до Линукса — обязательно починю :-)
+2
soider #
Это бага именно фаера именно под линукс, лечится вот этим https://addons.mozilla.org/ru/firefox/addon/3529 =)
0
Mastyf #
Это бага линукса и именно хоткеев. В Мозиллу костыли вставить можно, а вот в остальные приложения - проблемно.

Решения вменяемого я так и не нашел. Может поделится кто?
0
soider #
мне кажется, это баг только gtk, разве нет ? и вроде бы где то я видел решение на эту тему) но может я ошибаюсь, скорей всего так и есть =)
0
eschava #
линукса - это вы уж слишком )
скорее GTK, в QT приложениях такого не наблюдается
+1
Davidov #
Это _не_ баг GTK. Если не обрабатывать сырое событие "key-press-event", а делать акселераторы, то никаких проблем нет. Сам исправлял подобный баг в gajim.
Большая часть GTK приложений прекрасно понимают шорткаты в любой раскладке.

И, кстати, в Firefox3 баг был исправлен. Но, к сожалению, костылём, который, впрочем, работает лучше, чем вышеупомянутое расширение.
0
diamant #
Don't try it with other languages/layouts, the result will be unpredictable.

я пользуюсь раскладкой typewriter, у меня этот плагин не будет работать?
0
rakot #
Огромное спасибо, оч долго мучался с хоткеями
0
UrbanRider #
Поп поводу этого бага в блоге "огненый лис" был топик, где сказано что проблема решена...

Можете почтитаь топик про решение проблемы.
+1
monsterzz #
Эта проблема решена в ff3. А вот 1 и 2 версии останутся без этого фикса :(
Так что, на мой взгляд, при создании хоткеев надо учитывать и это.
0
UrbanRider #
извините что дабл пост, но я не нашел как отредактировать сообщение =(

я тут новый...

Вот ссылка на решение проблемы с Лисом в Линуксе:

http://habrahabr.ru/blog/firefox/28589.html
0
XaocCPS #
+1
Хороший пост, пишите еще.
+1
majesty #
осталось внедрить на хабр (а лучше - повсеместно, где есть формы) :)
большое спасибо за статью! буду адаптировать код под jQuery и юзать в проектах :)
0
bur #
Как сделаете решение для jQuery, если Вас не затруднит, отпишите его мне или в комментах. С удовольствием добавлю его в статью.
+1
majesty #
Прошу простить, не тестировал совсем :) Просто переложил (с некоторыми неточностями, т.к. jQuery, судя по примерам из документации, не знает gecko, но знает msie, opera, safari & firefox). В общем, предлагаю уважаемому сообществу принять участие в разработке :)

var e = "keypress";
if($.browser.msie || $.browser.opera) e = "keydown";
$(document).bind(e, function(evt){
var evt = evt || window.event;
var key = evt.keyCode || evt.which;

var isIE = $.browser.msie || $.browser.opera;
var isGecko = !isIE;
key = !isGecko ? (key == 83 ? 1 : 0) : (key == 115 ? 1 : 0);
if (evt.ctrlKey && key) {
if(evt.preventDefault) evt.preventDefault();
evt.returnValue = false;
clientFunction();
window.focus();
return false;
})

ЗЫ: ногами не бить, с jQuery знаком второй день :)
+1
rold #
0
majesty #
:) за ссылку спасибо, пошёл искать ритуальную стену для самоубийств.
0
bur #
Спасибо!
0
bur #
Работает, только у Вас одной фигурной скобки не хватает закрывающей для ифа в конце.
Статья обновлена, спасибо!
+1
majesty #
Лучше положить в статью ссылку rold. Моё решение кривое (у меня оно под IE7 не заработало, а под FF заработало со второго нажатия).
0
bur #
Да, ссылка на гугл будет актуальнее.
А у Вас всё работает, видимость неработоспособности из-за того, что дебажите алертом. Лучше обновите какую-нибудь ноду на страницу, сразу всё станет на свои места ;-)
0
majesty #
Во всём есть плюсы и минусы :) В ИЕ у меня не заработало так: http://www.href.kz/save
А решение по ссылке исполняет код параллельно с вызовом сохранительного окошка (по крайней мере в опере) :)
Нет в жизни счастья :)
0
bur #
Но, попытаться стоило )
0
reaferon #
Немного не в тему: встречал однажды интересную реализацию отлова CTRL+S на сайте. При нажатии на данную комбинацию открывался DIV, визуально копирующий окно сохранения файла в MSIE. При нажатии кнопки Save страница якобы сохранялась в MyDocuments и div-чик закрывался.
Разумеется позже, когда пользователь хотел посмотреть сохранённую страницу и искал её в папке с документами, он там её не обнаруживал.
0
bur #
На локальную машину без использования хаков или activeX яваскрипт никого не пустить. А вот сделать такую вещь с привлечением сервера никто не мешает.
Например, Вы жмете Ctrl+S, открывается тот самый ДИВ, похожий на браузерный диалог и предлагает выбрать папку на хосте, для сохранения HTML-документа (при участии БД или еще как, не суть). Вы выбираете и сохраняете.
Или в почте — выбрать папку куда положить черновик письма.
Возможностей для реализации можно придумать много.
0
reaferon #
Вы не совсем меня поняли. Данный функционал явно сделан был чтобы ввести пользователя в заблуждение. Пользователь считал, что страница сохранена, чего по сути не происходило. Видимо, таким образом пытались защитить авторский контент. Хотя не уверен: не было защиты от selection, да и "File -> Save As" работало прекрасно. Имхо - просто разработчику не фиг делать было, вот он и реализовал такую "фичу".
К сожалению не могу дать ссылку, видел это несколько лет назад и сейчас уже адрес ресурса не помню.
0
bur #
Я всё прекрасно понял, и предложил вместо бестолкового решения вариант полезного (более-менее) применения :-)
0
reaferon #
Ну, собственно, в таком случае, простите, Вы изобрели велосипед :)
Схожий функционал реализован у некоторых служб Google (например, GoogleDocs)
0
bur #
В таком случае я изобрел 2 велосипеда, сама статья тоже неактуальна в виду того, что Ctrl+S уже реализован у Гугла :-)
0
reaferon #
Боюсь расстроить: http://jshotkeys.googlepages.com/test-st… :)
Другое дело, далеко не всегда желательно подключать большие либы в проекте.
0
bur #
Видел уже. Да и когда гмэйлом пользуешься такая реализация сохранения выделяется своим удобством. А вот отдельный скрипт для сохранения нигде не встречал, вот и результат в виде статьи :-)
0
zvirusz #
блин... опять эта страница... люблю я её... какое-то неповторимое ощущение зарождается, когда по нажатию Ctrl+W - ничего не происходит :)
0
rold #
В Опере очень даже происходит :)
+1
majesty #
именно поэтому я пока использую решение из статьи, за неимением лучшего :)
–3
m007 #
Подкинули бы кармы мне, пост хочу по javascript написать. А то у меня 0 - зарегился неделю назад :)
+1
reaferon #
Совет: не просите карму. Её нужно заслужить, а после таких просьб у кармы имеется тенденция уменьшаться :)
+1
m007 #
Ну ваше дело :) Если никому неинтересно про то как красиво вписать понятия процесса и потоков и как следствие динамическую подгрузку модулей на javascript.

//
// Dynamic script example.
//

// Load script.
var pLib = new HDynamicScript("Lib\\MapAppTest.js", "Map" ]);
var Map = pLib.GetExport("Map");

var pMap = new Map;

alert(pMap.PrivateData());

Хотел реально полезную штуку осветить, походу тут это не нужно...
0
reaferon #
Почему же не нужно?
Считаете полезным другим - пишите, в этом ограничений нет. А если то, что напишите будет действительно полезным, то проблема кармы и переноса из персонального блога в коллективный очень быстро решится :)
Хинт: для записи в персональный блог карма должна быть >= 0
0
bur #
Тут Вы ошибаетесь. В персональный блог нельзя писать с нулевой кармой, только комменты.
0
reaferon #
"опубликовать новый хабратопик в персональный блог — карма >0"
http://habrahabr.ru/info/help/karma/
+1
zvirusz #
именно это и сказал bur :)
0
reaferon #
Согласен, мой косяк в операторе.
Но суть осталась: m007 вполне иеет возможность писать в блог.
0
bur #
Нет, не осталось.
При регистрации карма = 0.
А писать можно при карме > 0.
Вывод?
0
reaferon #
при добавлении коммента карма уже была положительная. А сейчас даже увеличилась. Так что утверждение "m007 вполне иеет возможность писать в блог" верно :)
0
bur #
При добавлении комментария карма была нулевая (я сам лично это видел), а потом её плюсанули. Поверьте, я сам только пару недель на Хабре. Пока не плюсанут в карму - живешь полностью в комментах.
0
reaferon #
Я тоже посмотрел практически сразу. Карма была меньше единицы, но больше нуля.
0
reaferon #
Кстати, считаю верным тот момент, что с нулевой кармой писать блог нельзя. Хорошо, если чловек некоторое время будет только читателем. Блоггин на Хабре довольно специфичен :)
0
bur #
карма >0
а вы утверждаете, что карма >= 0
;-)
0
darkside #
пиши в личный блог. там тебе скажут что надо было писать в блог о яваскриптах, скажешь что кармы не хватает и будет тебе кармы) перенесёшь пост в нужный блог.
+2
unclegluk #
Классная штука, мне понравилось. Mac OS X + FF3b5 работает, но в макосях вместо Ctrl+S принято нажимать Command+S, посему диалог появляется, но с Ctrl все работает. На виндовой клаве у меня оно равняется клавише Win.
0
bur #
Спасибо! Допишу в топик.
+1
unclegluk #
Дополнение про Mac OS X: Ctrl+Ы на Маке не работает.
0
bur #
Спасибо, учёл в статье.
+1
rold #
Решение для jQuery от Google
Не совсем корректная фраза, скорее «Плагин для jQuery, размещенный на Google Code» :)
0
bur #
Спасибо, изменил.
0
flash3r #
Наверняка, многие попробовали нажать ctrl + S после прочтения заголовка :D
+1
romy4 #
чисто ради интереса, зачем блокировать горячие клавиши?
0
bur #
Если вам нужен интерфейс для сохранения ваших данных, а не HTML-кода страницы, то логично воспользоваться уже существующими хоткеями.
И их никто не блокирует, их переопределяют для сохранения других данных.
0
romy4 #
ничего не понял из вашего ответа :(
если я нажимаю ctrl+s то должна сохраниться страница. для каких целей блокировать это?
+1
bur #
Объясню проще.
Ctrl+S — это горячая клавиша для сохранения.
А что сохранять, HTML-страницу или введенные пользователем данные решает уже конкретное приложение.
Есть такой почтовик - Gmail. Так вот, когда я пишу письмо, мне очень удобно по нажатию Ctrl+S сохранять письмо, а не видеть диалог о сохранении страницы.
Здесь речь идет не просто о блокировании Ctrl+S, а о возможности привязать к этому хоткею другое событие.
0
romy4 #
в таком случае, следует предупреждать большими буквами, что ctrl+s сохраняет письмо, а не страницу. иначе такая юзабильность будет только со знаком "−". В том же GMail'e я вовсе не ожидаю сохранения письма по ctrl+s, хоть это и логично было бы.
Извините за придирство, но это всё равно что взять чью-либо машину и перекрасить в другой цвет.
А за скрипт респектище!
+1
art_linux #
s/Gekko/Gecko
0
bur #
fixed
0
darkside #
спасибо, интересно. но лично я считаю, что функция сохранения документа должна лежать на браузере. а для сайта следует определить уровень доступности, что-то вроде предупреждения перед сохранением и служебной информацией для браузера как, что и в каком варианте сохранять. так, думаю, будет грамотней и логичней.

может подкинуть как идейку W3C?:)
0
bur #
Что и куда сохранять должно определяться приложением исходя из удобства пользователей. Иначе мы получим враждебный по отношению к юзеру интерфейс. Здесь речь идет исключительно о перехвате хоткея. Никакая служебная информация никуда не уходит, а сохранять можно не только документ.
0
darkside #
перехватка хоткея по своей идее вещь не правильная. я говорю о том, что сайт дне должен определять функцию сохранения, в лучшем случае должен указывать браузеру что и как сохранять. отсюда будет и удобство для пользователя и стандарт для сайтостроителя, а для браузера это новая встроенная функция и отсутствие избыточной загрузки яваскрипт кодом.
0
bur #
1) Под сохранения в данном случае подразумевается отправка HTTP-запросов на хост. Это для юзера выглядит сохранением, а для браузера - ничем не примечательный запрос с данными формы.
2) В мозгу пользователя хоткей привязан к событию, а не конкретному действию, и это правильно. Неправильно на Ctrl+S привязывать выделение всего документа или закрытие страницы. А сохранение данных, если есть что сохранять и оно часто требуется - очень правильно повесить на этот хоткей.
0
darkside #
1) я рассуждал о том как можно было бы реализовать эту функцию в будущем;)
2) я согласен с тем, что в голове у пользователя на хоткей Ctrl+S записана одна постоянная функция, не правильным я считаю сокрытие от него факта переделки этой функции и невозможность перенастройки этого хоткея. у браузера есть свой вариант выполнения функции, у авторов сайта свой - получается насильственный запрет функции браузера. а если браузерная функция мне была удобней?
0
bur #
1) Зачем? Нет, действительно, чем запрос отправленный по хоткею отличается своего обычного собрата?
2) Ответственность за такие случаи ложится на разработчика приложения. Если разработчик перехватил хоткей там, где все пользуются браузерным — значит он мудак и юзеры быстро забьют на эту страницу.
0
pxx #
Как по мне, неудачная идея переопределять стандартное поведение программы. Один сайт будет реагировать на Ctrl-S стандартно, другой иначе, третий вообще непредсказуемо. Будет каша в головах юзеров и разрыв привычных шаблонов.
0
bur #
Предполагаю, что Вы не работали с web-приложениями где это реализовано и не представляете насколько это удобно и естественно :-)
К тому же не стоит втыкать перехват хоткеев по поводу и без повода.

И еще информация для размышления. Часто ли Вы на страницах ежедневно используемых сайтов (почта, поиск) жмете Ctrl+S для сохранения html-кода? :-)
–1
rwz #
Я, например, работал с приложениями, где это реализовано. И отлично представляю, насколько это неудобно.
Я привык что броузер по ctrl+s/cmd+s сохраняет страничку, а не делает какую-то там другую фигню. Мне не нужную тем более.

Моментально проникаюсь отвращением к сайтам, которые пытаются переназначить хоткеи моего браузера.
+1
chEbba #
Фича очень полезная, знаю по себе, отработана уже привычка если пишешь "долго" некий текст автоматом жмешь ктрл+Ы, от этого зачастую получаю диалог сохранения страницы =) Так что когда в свое время увидел подобную фишку в редакторе tinymce принял на вооружение и использую в некоторых местах.

Полностью согласен, что подобную функциональность веб приложение в праве изменять.
Будем надеяться что данный топик сподвигнет народ использовать подобную функциональность.

ЗЫ и вообще стандартные хоткеев много ) главное не переборщить.
0
bur #
Винградовцам, привет! :-)
Ловите плюс.
0
AKS #

key = !isGecko ? (key == 83 ? 1 : 0) : (key == 115 ? 1 : 0);
???
0
bur #
По кейпрессу разные кейкоды в Гекко и Опере.
0
AKS #
:)
Я думал, что достаточно будет обратить внимание программиста на строку...
Что ж, еще раз (конкретнее): key == 83 ? 1 : 0
0
bur #
key == 83 ? 1 : 0
Если на клавиатуре нажата клавиша с виртуальным кодом 83 ("S"), то присваиваем флагу истинное значение, если нет - ложное.
:-)
Кстати, есть более элегантное решение для всей строки:
key = String.fromCharCode(key).toLowerCase() == "s" ? 1 : 0;
+1
AKS #
key = key == 83;
То же самое и для "более элегантного решения", т.к. булева значения, которое возвращает оператор сравнения, вполне достаточно, чтобы не "городить огород".
0
bur #
+1
Глаз замылен, не увидел (
0
Quessir #
Те, кто используют PrototypeJS, могут поставить просто evt.stop(). Он сам определяет, что использовать: evt.preventDefault() или evt.stopPropogation().

Если надо делать в iframe, то для IE строчка определения event выглядеть будет так:
evt = iframe.contentWindow.document.parentWindow.event;
0
pento #
Имхо, пытаться изменить действие браузера по умолчанию - моветон.
0
Quessir #
А что, если вы хотите сделать какой-нибудь тул типа wysiwyg-редактора?
–1
pento #
Стараться не использовать "браузерные" комбинации. Я привык к тому, что Ctrl+S сохраняет страницу и если кому-то вздумается, что на его сайте будет по-другому, то я больше никогда этот сайт не посещу.
0
Quessir #
Согласен с вами... но не полностью. Обычно такие вещи делаются там, где нужен именно функционал (привычный для большинства пользователей), а не там, где располагается контент.
0
Snowman #
Сколько людей - столько мнений. Лично я привык сабмитить данные по Ctrl-Enter, Ctrl-S - сохранение страницы на диск. Веб-приложение ни под каким предлогом не вправе переназначать пользовательские хоткеи, до тех пора пока это явно не указано юзером в настройках.
0
pento #
Вот и я о том же!
–1
twirpx #
Согласен на все 100% с людьми, критикующими переопределение шорткатов.

Любое отклонение поведения приложения от интуитивно ожидаемого - есть зло.

Я уверен, что после прочтения данного топика в инете появится десяток форм вида:
очень-полезный-текст-который-надо-сохранить + форма комментариев.
А обычные пользователи этих форм будут очень удивляться, почему у них нет возможности просто и быстро сохранить понравившийся текст.

И речь даже не о Ctrl-S, а о любых шоркатах.
Вот вам нравятся всевозможные блокираторы контекстных меню, приемы "анти-копирования", бегающий текст в статустной строке?
Не нравятся? Но делать по сути тоже самое, но более изящно, в своих проектах, считаете допустимым.

Недавно "порадовала" подобная "возможность" на ArtLebedev.
Очень хотел бы посмотреть в глаза тому умнику, который повесил на Ctrl-Home переход на главную страницу.
Вместо того, чтобы быстро перепрыгнуть к топу страницы приходится юзать scrollbar (аггрррр...).

Не надо решать за пользователя, что и как ему делать.
Не надо придавать стандартным функциям "новое видение".
Используйте стандартные выразительные средства, предоставленные вам целевой платформой.
0
deex #
"который повесил на Ctrl-Home переход на главную страницу"
а почему просто не нажать home, чтобы попасть наверх страницы?
0
tarutin #
Привык на маке сохранять cmd+s. почему бы и тут не сделать такой обработчик?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.