Продолжаем расширять функционал браузера Vivaldi

от автора

Вот уже полгода прошло с появления на свет самой первой версии браузера Вивальди.
За этот период группа разработчиков многое успела сделать и добавить, радуя пользователей еженедельными билдами. Прогресс виден на лицо. А совсем скоро подтянется и Technical Preview 4.

Но многим пользователям до сих пор не хватает каких-то фич. И пока разработчики браузера заняты совсем другим, мы попытаемся кое-что реализовать сами.

image

Эта статья является неким сборником некоторых функций, расширяющих возможности UI. Что-то подсмотрено на официальном форуме Vivaldi, что-то изменено, а что-то написано собственноручно. В статье мы попробуем реализовать фичи из других браузеров и вернём пару привычных вещей, которых некоторым так не хватает.

А под катом мы начнём с самого вкусного.

Сворачивать щелчком по вкладке

Именно так называлась галочка в настройках вкладок Opera Presto. Она позволяла при повторном нажатии на активную вкладку открывать предыдущую. Для некоторых это была весьма полезная вещь, которая со временем, к сожалению, пропала.
Так давайте же теперь вернём её в Вивальди.
Вот как выглядела она в Опере:

Иллюстрация:

image

Как и в прошлой статье здесь работаем также по старой схеме — только уже создаём не css, а js файл с каким-нибудь названием, например, «last-tab.js». И вставляем туда код:

last-tab.js

var browser = document.body.querySelector('#browser'); var list = []; function listTabs() { 	var tabs = browser.querySelectorAll('#tabs>.tab'); 	list=[]; 	for(var i = 0;i < tabs.length;i++){ 	    list.push(tabs[i]); 	}  	list.sort(function(a,b) { return recent(b) - recent(a); }); }  function recent(tab){ 	var page = document.querySelector('.webpageview webview[tab_id="'+tab.dataset.tabId+'"]'); 	if(page) { 	    page = page.parentNode.parentNode.parentNode.parentNode; 	    return parseInt(page.style.zIndex); 	} 	return 0; };  var dispatchMouseEvent = function(target, var_args) { 	var e = document.createEvent("MouseEvents"); 	e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1)); 	target.dispatchEvent(e); };  browser.addEventListener('mousedown', function(e){     for (var i = 0; i < e.path.length; i++) {         if (e.path[i].className.indexOf('active') > -1) {             var active = browser.querySelector('.tab.active');              listTabs();             dispatchMouseEvent(list[1], 'mousedown', true, true);             break;         }     } }); 

А в browser.html после

    <script src="bundle.js"></script> 

вставляем строчку:

    <script src="last-tab.js"></script> 

Теперь при повторном нажатии на активную вкладку будет открываться предыдущая.

Переход в начало страницы щелчком по вкладке

У Яндекса же есть свой альтернативный взгляд на то, как можно использовать щелчок по активной вкладке.
За эти полгода я часто слышал в комментариях и на форумах просьбы пользователей сделать эту фичу. Сам я Яндекс.Браузером никогда не пользовался, но по описанию всё, в принципе, кристально ясно что требуется.

tab-to-top.js

// Click on active tab to scroll top var browser=document.body.querySelector('#browser'); browser.addEventListener('click', function(e){ 	for (var i = 0; i < e.path.length; i++) { 		if (e.path[i].className.indexOf('active') > -1) { 			var active = browser.querySelector('.tab.active'); 			var webview = document.querySelector('#webview-container webview[tab_id="'+active.dataset.tabId+'"]'); 			webview.executeScript({ code: "document.body.scrollTop=0" }); 			return; 		} 	} }); 

В browser.html соответственно:

    <script src="tab-to-top.js"></script> 

Запускаем, проверяем. Вроде работает.

Иллюстрация (1 Mb):

image

Т.к. эти две функции исключают друг друга, настоятельно не рекомендуется совмещать их.

Вставить и перейти по клику

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

Создаём «click-and-go.js» и вставляем код:

click-and-go.js

// Right click on plus-button to paste and go var browser=document.body.querySelector('#browser'); var isItMouse = false; // Exclude responses from keyboard  //Tweak for paste in this input-field var hiddenInput = document.createElement("input"); hiddenInput.type = "text"; browser.appendChild(hiddenInput); hiddenInput.style.width = "0px"; hiddenInput.style.height = "0px"; hiddenInput.style.display = "none";  var dispatchMouseEvent = function(target, var_args) {     var e = document.createEvent("MouseEvents");     e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1));     target.dispatchEvent(e); };  browser.addEventListener('contextmenu', function(e) {     //Area near square     if (e.target.className.toString().indexOf('newtab') > -1) {         isItMouse = true;         document.execCommand('paste');         return;     }     //Plus-symbol     if (e.target.parentNode.parentNode.className.indexOf('newtab') > -1) {         initPaste();         return;     }     //Square     if (e.target.getTotalLength() > 0) { // 104 — length of new tab Button SVG         initPaste();         return;     } });  function initPaste() {     isItMouse = true;     hiddenInput.style.display = "block";     hiddenInput.focus();     document.execCommand('paste'); }  document.addEventListener('paste',function(e) {     if (isItMouse) {         isItMouse = false;         var url = e.clipboardData.getData('text/plain');         hiddenInput.style.display = "none"; //hide input-field for pasting          var re = new RegExp('\\r\\n', 'g'); // Delete newline characters         url = url.replace(re, '');         // Search engines     	var searchEngine = 'https://google.com/webhp?hl=ru#hl=ru&q=';      //	var searchEngine = 'http://yandex.ru/search/?text=';     //  var searchEngine = 'https://duckduckgo.com/?q=';         var active = browser.querySelector('.tab.active');         var webview = document.querySelector('#webview-container webview[tab_id="'+active.dataset.tabId+'"]');                  if (url.length > 0) {             if (checkUrl(url)) {                 webview.executeScript({ code: "window.open('"+url+"','_blank')" });             } else if (checkUrlWithoutProtocol(url)) {                 webview.executeScript({ code: "window.open('http://"+url+"','_blank')" });             } else {                 webview.executeScript({ code: "window.open('"+searchEngine+url+"','_blank')" });             }         }                  console.log(url)}     } ); //Check url var patternUrl = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?/#]\S*)?$/i; var patternUrlWithout = /^(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,3})).?)(?::\d{2,5})?(?:[/?/#]\S*)?$/i; function checkUrl(str) {     return patternUrl.test(str); } //url without protocol function checkUrlWithoutProtocol(str) {         return patternUrlWithout.test(str);     }  

Соответственно в browser.html добавляем:

    <script src="click-and-go.js"></script> 

Функция сделана по такому принципу: нажатие правой кнопки мыши по плюсику создаёт новую вкладку, и происходит переход по ссылке из буфера обмена, если же там находится не ссылка, то идёт автоматический поиск по строке в поисковой системе.
Но у решения есть пара минусов.
Во-первых, регулярное выражение, которое ищет ссылку в строке без протокола, может ошибаться. То есть, например, «test.test» воспримется как ссылка ровно как и «ya.ru». Но в целом на практике это не должно мешать.
А во-вторых, заданная поисковая система не связана с поисковой системой, что поставлена в браузере как основная. В данном случае поиск будет происходить через Google. Но я специально добавил ещё строчки для DuckDuckGo и Yandex, если кого-то не устроит Google. Для других поисковых систем также вполне несложно написать нужную ссылку.

Иллюстрация (1 Mb):

image

Избавляемся от строки состояния

Убрать строку состояния (status bar) можно было в настройках с самой первой версии. Но проблема в том, что именно там отображаются ссылки при наведении на них. И тем, кому status bar не нужен, либо приходилось уживаться с ним, либо же не видеть ссылок при наведении. Сейчас мы попробуем это исправить с помощью css.

status-bar.css

/** Избавляемся от status bar **/  #footer.disabled{ 	display:block !important; 	position:static !important; 	padding:0 !important; 	height:0 !important; 	width:0 !important; }  #footer.disabled > *{ 	display:none !important; } #footer.disabled #status_info{ 	display:block !important; }  #footer.disabled #status_info span{ 	position:fixed !important; 	bottom:0 !important; 	left:0 !important; 	margin:0 !important; 	color:#333 !important; 	background-color:#FEFEFE !important; 	padding:2px 5px !important; 	border:#9E9E9E solid 0 !important; 	border-width:1px 1px 0 0 !important; 	max-width:75% !important; 	overflow: hidden !important; 	white-space: nowrap !important; 	text-overflow: ellipsis !important; 	z-index:50 !important; }  #footer.disabled #status_info span:empty{ 	display:none !important; }  /******/ 

Соответственно после

    <link rel="stylesheet" href="style/common.css" /> 

вставляем строчку

    <link rel="stylesheet" href="status-bar.css" /> 

Принцип здесь простой: мы просто убираем отображение строки состояния и рисуем прямоугольник для status_info в углу.
image

Но у данного решения есть некоторые минусы: ссылка отображается всегда в углу поверх всех элементов пользовательского интерфейса. Поэтому для пользователей с вкладками снизу это решение не подойдёт, и нужно будет блок приподнимать через bottom.

Убираем адресную строку в заголовок окна

Данное дизайнерское решение может показаться интересным для пользователей, у которых вкладки расположены не сверху, а по бокам или снизу. Потому что именно при таком расположении вкладок сверху появляется заголовок окна, который отъедает лишнее место по вертикали, что может быть критично для некоторых.
Так будет выглядеть окно со совмещением:
image

header.css

/** Совмещаем заголовок вместе с адресбар **/ #header { 	min-height: 2px !important; 	height: 2px !important; 	z-index: auto !important; }  .win .vivaldi { 	color: #fff; 	position: absolute; 	top: 5px; 	left: 98px; }  .vivaldi+#tabs-container.top { 	border-bottom: 1px solid; 	position: absolute; 	top: 62px; 	width: 100%; 	z-index: 1 !important; }  #tabs-container.bottom #tabs, #tabs-container.top #tabs { 	max-height: 30px !important; }  .toolbar.toolbar-addressbar { 	padding-right: 100px; }  .addressfield {	margin-left: 40px !important; }  .button-toolbar { 	position: relative !important; 	left: 30px !important; }  .bookmark-bar { margin-bottom: 37px; }  .vivaldi { z-index: 3; }  .window-buttongroup { z-index: 2; }  .home,.rewind,.next,#pagetitle{display:none} /********************/ 

Это вариант для тех, кто пользуется Vivaldi-кнопкой.
Но есть и пользователи, которые используют меню в его классическом представлении. В таком случае адресной строке придётся ужаться и уступить место кнопкам меню. Причём для разных языков ширина меню будет разная.

Варианты для английского и русского языков

image image
#header { min-height: 2px !important; z-index: auto !important; }  .win .topmenu { color: #fff; position: absolute; top: 5px; left: 0px; }  .topmenu+#tabs-container.top { border-bottom: 1px solid; position: absolute; top: 62px; width: 100%; z-index: 1 !important; }  #tabs-container.bottom #tabs, #tabs-container.top #tabs { height: 30px !important; }  .toolbar.toolbar-addressbar { padding-right: 100px; }  .button-toolbar.back{ margin-left: 350px }  .home,.rewind,.next,#pagetitle{display:none}  .addressfield { margin-left: 3px !important; }  .bookmark-bar { margin-bottom:0px; }  .window-buttongroup { z-index: 2; } 

#header { min-height: 2px !important; z-index: auto !important; }  .win .topmenu { color: #fff; position: absolute; top: 5px; left: 0px; }  .topmenu+#tabs-container.top { border-bottom: 1px solid; position: absolute; top: 62px; width: 100%; z-index: 1 !important; }  #tabs-container.bottom #tabs, #tabs-container.top #tabs { height: 30px !important; }  .toolbar.toolbar-addressbar { padding-right: 100px; }  .button-toolbar.back{margin-left: 270px}  .home,.rewind,.next,#pagetitle{display:none}  .addressfield { margin-left: 3px !important; }  .bookmark-bar { margin-bottom:0px; }  .window-buttongroup { z-index: 2; } 

Несколько строк вкладок

Наверно многие уже забыли, но Opera Presto умела отображать вкладки в несколько строчек. Сейчас такое разве что в FF можно встретить. Пришло время и Вивальди научить этому.

tab-lines.css

#tabs-container.top #tabs, #tabs-container.bottom #tabs {   height: auto !important;   display: block !important; } #tabs-container.bottom #tabs .tab, #tabs-container.top #tabs .tab {   max-width: 150px !important;   min-width: 150px;   display: inline-block !important;   float: left; } #tabs .tab .tab-thumb { display: none; } #tabs .newtab { margin-top: -9px; } #tabs .trash {   margin-top: -10px;    display: inline-block !important;   float: right; } 

Так будет выглядеть полученный результат:
image
При открытии новых вкладок верхняя панель будет увеличиваться в высоту соответственно.

Ну и на последок пара мелочей:

  • Отключение отображения кнопки с плюсом в Экспресс-Панели (может вскоре станет неактуальным):
    .dial.add {display: none !important;}

  • Отключение отображения крестика с вкладок:
    #tabs .tab .tab-header .close {display: none !important;}

Если вы захотите использовать какие-то функции одновременно, то можно вполне безболезненно скопировать несколько файлов в один какой-нибудь custom.js файл, чтобы не плодить лишних файлов.
Тоже самое и с css.

Ещё хотелось бы поделиться гитхабом одного пользователя Вивальди с форума, который сделал вполне неплохие вещи и даже реализовал собственную прокрутку вкладок через ПКМ+скролл с превью. Хотя конкретно это более неактуально, т.к. в браузере уже есть такая функция, пусть и в самом зачаточном виде.

А на этом пожалуй всё. Надеюсь что-то из этого для вас было полезно. Конечно, эти решения не идеальны, и могут требовать индивидуальной доработки, т.к. от части некоторые вещи я создавал под себя.
Если же у вас есть мысли по поводу более лаконичного решения в js-функциях или предложения, что можно ещё сделать, то буду рад послушать.

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

Пара готовых вариантов от меня:
last-tab + status-bar + click&go + hideplus + tab-lines
(Вкладки должны быть заранее перемещены из заголовка) tab-top + status-bar + click&go + hideplus + header

Vivaldi Forum
Github.

ссылка на оригинал статьи http://habrahabr.ru/post/261543/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *