Mask for the address bar



  • What?

    • Initially I wanted to make vivaldi's address bar the same as other browsers, the page address can highlight the domain name by blurring other parts. But then I want more customization for color and structure.
    • Finally I decided to create a mod that can change any element in the site address with CSS on the elements created with JS, a layer mask covers the address field.

    Demo

    • theme-1
      0_1558601057398_theme-1.png

    • theme-2
      0_1558601104528_theme-2.png

    • theme-3
      0_1558601113372_theme-3.png

    Installation

    • You can learn how to install here
    • Mod supports 3 themes: theme-1, theme-2, theme-3 and you can customize your own themes with CSS
    • To change between themes, change the line const theme = 'theme-1'; in code javascript into the theme you want. Example you want to use theme-2, change the code to const theme = 'theme-2';

    Javascript:

    /*
     * Mask for the address bar
     * Written by Tam710562
     * Thanks to sjudenim and LonM for bug fixes and new ideas 
     */
    
    window.gnoh = Object.assign(window.gnoh || {}, {
      encode: {
        html: function (rawStr) {
          return !rawStr ? rawStr : rawStr.replace(/[\u00A0-\u9999<>\&"'%]/gi, function (i) {
            return '&#' + i.charCodeAt(0) + ';';
          });
        }
      },
      createElement: function (element, attribute, parent, inner) {
        if (typeof element === 'undefined') {
          return false;
        }
        var el = document.createElement(element);
        if (!!attribute && typeof attribute === 'object') {
          Object.assign(el, attribute);
          if (typeof attribute.text !== 'undefined') {
            el.textContent = attribute.text;
          }
          if (typeof attribute.html !== 'undefined') {
            el.innerHTML = attribute.html;
          }
          if (typeof attribute.style === 'object') {
            for (var css in attribute.style) {
              el.style[css] = attribute.style[css];
            }
          }
          if (typeof attribute.events === 'object') {
            for (let key in attribute.events) {
              if (typeof attribute.events[key] === 'function') {
                el.addEventListener(key, attribute.events[key]);
              }
            }
          }
          for (var key in attribute) {
            if (key !== 'style' && key !== 'events' && key !== 'text' && key !== 'html') {
              if (typeof attribute[key] === 'object') {
                attribute[key] = JSON.stringify(attribute[key]);
              }
              el.setAttribute(key, attribute[key]);
            }
          }
        }
        if (!!inner) {
          if (!Array.isArray(inner)) {
            inner = [inner];
          }
          for (var k = 0; k < inner.length; k++) {
            if (inner[k].nodeName) {
              el.append(inner[k]);
            } else {
              el.append(this.createElementFromHTML(inner[k]));
            }
          }
        }
        if (typeof parent === 'string') {
          parent = document.querySelector(parent);
        }
        if (!!parent) {
          parent.append(el);
        }
        return el;
      },
      observeDOM: function (obj, callback, config) {
        const obs = new MutationObserver(function (mutations, observer) {
          if (config) {
            callback(mutations, observer);
          } else {
            if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
              callback(mutations, observer);
            }
          }
        });
        obs.observe(obj, config || {
          childList: true,
          subtree: true
        });
      },
      timeOut: function (callback, conditon, timeout) {
        setTimeout(function wait() {
          var result;
          if (!conditon) {
            result = document.getElementById('browser');
          } else if (typeof conditon === 'string') {
            result = document.querySelector(conditon);
          } else if (typeof conditon === 'function') {
            result = conditon();
          } else {
            return;
          }
          if (result) {
            callback(result);
          } else {
            setTimeout(wait, timeout || 300);
          }
        }, timeout || 300);
      },
      override: function (obj, functionName, callback, conditon) {
        obj[functionName] = (function (_super) {
          return function () {
            var result;
            if (typeof conditon === 'function' && conditon.apply(this, arguments) || conditon === undefined || conditon === true) {
              result = _super.apply(this, arguments);
            }
            callback.apply(this, arguments);
            return result;
          };
        })(obj[functionName]);
      },
      getReactEventHandlersKey: function (element) {
        if (!this.reactEventHandlersKey) {
          if (!element) {
            element = document.getElementById('browser');
          } else if (typeof element === 'string') {
            element = document.querySelector(element);
          }
          if (!element) {
            return;
          }
          this.reactEventHandlersKey = Object.keys(element).find(function (key) {
            return key.startsWith('__reactEventHandlers');
          });
        }
        return this.reactEventHandlersKey;
      }
    });
    
    (function () {
      const theme = 'theme-2';
      let enableDecodeURL = false;
      let isPrivate = false;
      let searchEngines = {
        default: undefined,
        defaultPrivate: undefined,
        engines: {}
      };
      let extensions = {};
      const themeSettings = {
        'theme-1': {
          decodeURL: false
        },
        'theme-2': {
          decodeURL: true
        },
        'theme-3': {
          decodeURL: false
        },
      };
      const pattern = {
        url: {
          full: /(([a-z-]+):(?!\/\/))?(([^\/]+):\/\/)?(([^\/?#:]+)(:([^\/?#]*))?)?(\/[^?#]*)?(\?[^#]*)?(#(.*))?/i,
          path: /\/([^/]*)/gi,
          search: /[?&]([^=&]+)?(=([^&]*))?/gi,
          host: {
            hostSub: {
              topLevel1: /((.*)\.)?([^.]+\.[a-z]{2,4})$/i,
              topLevel2: /((.*)\.)?([^.]+\.[a-z]{2,3}\.[a-z]{2})$/i,
            },
            ipv4: /^(?=\d+\.\d+\.\d+\.\d+$)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.?){4}$/i,
            extensions: undefined
          }
        },
        searchEngines: undefined
      };
    
      function setSettings(theme, addressfieldMaskEl, addressfieldEl) {
        if (theme && typeof theme === 'string') {
          if (themeSettings[theme]) {
            enableDecodeURL = themeSettings[theme].decodeURL;
          }
          addressfieldMaskEl.classList.add(theme);
          addressfieldEl.classList.add(theme);
        }
      }
    
      function urlConvertEncodeHTML(urlConvert) {
        Object.keys(urlConvert).forEach(function (key) {
          urlConvert[key + 'HTML'] = gnoh.encode.html(urlConvert[key]);
        });
        return urlConvert;
      }
    
      function changeValue(addressfieldMaskEl, addressfieldEl, isChange) {
        if (addressfieldMaskEl.dataset.value !== addressfieldEl.value || isChange === true) {
          addressfieldMaskEl.dataset.value = addressfieldEl.value;
          addressfieldMaskEl.innerHTML = getURLColorEl(addressfieldEl.value);
        }
      }
    
      function createPatternSearchEngines(searchEngineCollection) {
        searchEngines = {
          default: undefined,
          defaultPrivate: undefined,
          engines: {}
        };
        pattern.searchEngines = undefined;
        const engines = searchEngineCollection.engines.filter(e => e.removed !== true);
        if (engines.length > 0) {
          const regKeywords = [];
          engines.forEach(function (engine) {
            searchEngines.engines[engine.keyword] = engine;
            searchEngines.engines[engine.keyword].keywordHTML = gnoh.encode.html(engine.keyword);
            searchEngines.engines[engine.keyword].nameHTML = gnoh.encode.html(engine.name);
            regKeywords.push(engine.keyword.replace(/[-/\\^$*+?.()|[]{}]/g, '\\$&'));
    
            if (engine.id === searchEngineCollection.default) {
              searchEngines.default = searchEngines.engines[engine.keyword];
            }
            if (engine.id === searchEngineCollection.defaultPrivate) {
              searchEngines.defaultPrivate = searchEngines.engines[engine.keyword];
            }
          });
    
          pattern.searchEngines = new RegExp('^(' + regKeywords.join('|') + ')\\s(.*)', 'i');
        }
      }
    
      function createPatternExtensions(extensionCollection, callback) {
        extensions = {};
        pattern.url.host.extensions = undefined;
        extensionCollection = extensionCollection.filter(e => e.enabled === true);
        if (extensionCollection.length > 0) {
          const regKeywords = [];
          extensionCollection.forEach(function (extension) {
            extensions[extension.id] = extension;
            extensions[extension.id].nameHTML = gnoh.encode.html(extension.name);
            regKeywords.push(extension.id);
          });
    
          pattern.url.host.extensions = new RegExp('^(?=[a-z]{32})(?:(' + regKeywords.join('|') + '))$', 'i');
        }
        if (typeof callback === 'function') {
          callback();
        }
      }
    
      function updatePatternExtensions(callback) {
        chrome.management.getAll(function (extensionCollection) {
          createPatternExtensions(extensionCollection, callback);
        });
      }
    
      chrome.storage.local.get({
        'SEARCH_ENGINE_COLLECTION': {
          engines: []
        }
      }, function (res) {
        createPatternSearchEngines(res.SEARCH_ENGINE_COLLECTION);
      });
    
      updatePatternExtensions();
    
      function createMask(addressfieldEl, addressfieldParentEl) {
        addressfieldParentEl = addressfieldParentEl || addressfieldEl.parentElement;
        const addressfieldMaskEl = gnoh.createElement('div', {
          class: addressfieldEl.className,
          placeholder: addressfieldEl.placeholder
        }, addressfieldParentEl);
        addressfieldMaskEl.classList.add('addressfield-mask');
    
        setSettings(theme, addressfieldMaskEl, addressfieldEl);
        changeValue(addressfieldMaskEl, addressfieldEl);
    
        chrome.storage.local.onChanged.addListener(function (changes, namespace) {
          if (changes.SEARCH_ENGINE_COLLECTION) {
            createPatternSearchEngines(changes.SEARCH_ENGINE_COLLECTION.newValue);
            changeValue(addressfieldMaskEl, addressfieldEl, true);
          }
        });
    
        ['onEnabled', 'onDisabled', 'onInstalled', 'onUninstalled'].forEach(function (event) {
          chrome.management[event].addListener(function () {
            updatePatternExtensions(function () {
              changeValue(addressfieldMaskEl, addressfieldEl, true);
            });
          });
        });
    
        gnoh.observeDOM(addressfieldEl, function (mutations, observer) {
          if (mutations[0].attributeName === 'value') {
            changeValue(addressfieldMaskEl, mutations[0].target);
          }
        }, { attributes: true });
      }
    
      function getURLColorEl(url) {
        const arr = pattern.url.full.exec(url);
        if (arr) {
          const urlConvert = urlConvertEncodeHTML({
            protocolSubFull: arr[1],
            protocolSub: arr[2],
            protocolFull: arr[3],
            protocol: arr[4],
            hostFull: arr[5],
            host: arr[6],
            postFull: arr[7],
            post: arr[8],
            path: arr[9],
            search: arr[10],
            hashFull: arr[11],
            hash: arr[12],
          });
          return [
            typeof urlConvert.protocolSub !== 'undefined' ? '<div class="protocol-sub" data-protocol-sub="' + urlConvert.protocolSubHTML + '">' + urlConvert.protocolSubHTML + '</div>' : '',
            typeof urlConvert.protocol !== 'undefined' ? '<div class="protocol" data-protocol="' + urlConvert.protocolHTML + '">' + urlConvert.protocolHTML + '</div>' : '',
            typeof urlConvert.hostFull !== 'undefined' ? [
              '<div class="host-full" data-host-full="' + urlConvert.hostFullHTML + '">',
              typeof urlConvert.host !== 'undefined' ? getURLHostEl(urlConvert.host, urlConvert) : '',
              typeof urlConvert.postFull !== 'undefined' ? '<div class="post" data-post="' + urlConvert.postHTML + '">' + urlConvert.postHTML + '</div>' : '',
              '</div>'
            ].join('') : '',
            (typeof urlConvert.path !== 'undefined' || typeof urlConvert.search !== 'undefined' || typeof urlConvert.hashFull !== 'undefined') ? [
              '<div class="path-full">',
              urlConvert.path === '/' ? '<div class="path" data-path="/"></div>' : typeof urlConvert.path !== 'undefined' ? '<div class="path" data-path="' + urlConvert.pathHTML + '">' + getURLPathEl(urlConvert.path) + '</div>' : '',
              urlConvert.search === '?' ? '<div class="search" data-search="?"></div>' : typeof urlConvert.search !== 'undefined' ? '<div class="search" data-search="' + urlConvert.searchHTML + '">' + getURLSearchEl(urlConvert.search) + '</div>' : '',
              typeof urlConvert.hashFull !== 'undefined' ? '<div class="hash" data-hash="' + urlConvert.hashFullHTML + '">' + (enableDecodeURL === true ? decodeURIComponent(urlConvert.hashHTML) : urlConvert.hashHTML) + '</div>' : '',
              '</div>'
            ].join('') : '',
          ].join('');
        } else {
          return url || '';
        }
      }
    
      function getURLHostEl(host, urlConvert) {
        if (host.match(pattern.url.host.hostSub.topLevel2)) {
          let hostSubHTML, hostMainHTML;
          return host.replace(pattern.url.host.hostSub.topLevel2, function (match, hostSubFull, hostSub, hostMain) {
            hostSubHTML = gnoh.encode.html(hostSub);
            hostMainHTML = gnoh.encode.html(hostMain);
            return [
              '<div class="host with-sub" data-host="' + urlConvert.hostHTML + '">',
              typeof hostSub !== 'undefined' ? '<div class="host-sub" data-host-sub="' + hostSubHTML + '">' + hostSubHTML + '</div>' : '',
              typeof hostMain !== 'undefined' ? '<div class="host-main" data-host-main="' + hostMainHTML + '">' + hostMainHTML + '</div>' : '',
              '</div>'
            ].join('');
          });
        } else if (host.match(pattern.url.host.hostSub.topLevel1)) {
          let hostSubHTML, hostMainHTML;
          return host.replace(pattern.url.host.hostSub.topLevel1, function (match, hostSubFull, hostSub, hostMain) {
            hostSubHTML = gnoh.encode.html(hostSub);
            hostMainHTML = gnoh.encode.html(hostMain);
            return [
              '<div class="host with-sub" data-host="' + urlConvert.hostHTML + '">',
              typeof hostSub !== 'undefined' ? '<div class="host-sub" data-host-sub="' + hostSubHTML + '">' + hostSubHTML + '</div>' : '',
              typeof hostMain !== 'undefined' ? '<div class="host-main" data-host-main="' + hostMainHTML + '">' + hostMainHTML + '</div>' : '',
              '</div>'
            ].join('');
          });
        } else if (pattern.searchEngines && host.match(pattern.searchEngines)) {
          let searchQueryHTML;
          return host.replace(pattern.searchEngines, function (match, searchNickname, searchQuery) {
            searchQueryHTML = gnoh.encode.html(searchQuery);
            return [
              '<div class="search-engine with-nickname">',
              typeof searchNickname !== 'undefined' ? '<div class="search-nickname" data-search-nickname="' + searchEngines.engines[searchNickname].keywordHTML + '" data-search-name="' + searchEngines.engines[searchNickname].nameHTML + '">' + searchEngines.engines[searchNickname].keywordHTML + '</div>' : '',
              typeof searchQuery !== 'undefined' ? '<div class="search-query" data-search-query="' + searchQueryHTML + '">' + (enableDecodeURL === true ? decodeURIComponent(searchQueryHTML) : searchQueryHTML) + '</div>' : '',
              '</div>'
            ].join('');
          });
        } else if (typeof urlConvert.protocol !== 'chrome-extension' && pattern.url.host.extensions && host.match(pattern.url.host.extensions)) {
          return '<div class="host extension" data-host="' + urlConvert.hostHTML + '"><div class="host-extension" data-host-extension="' + urlConvert.hostHTML + '" data-host-extension-name="' + extensions[host].nameHTML + '">' + urlConvert.hostHTML + '</div></div>';
        } else if (host.match(pattern.url.host.ipv4)) {
          return '<div class="host ipv4" data-host="' + urlConvert.hostHTML + '"><div class="host-main" data-host-main="' + urlConvert.hostHTML + '">' + urlConvert.hostHTML + '</div></div>';
        } else if (typeof urlConvert.protocolSub !== 'undefined' || typeof urlConvert.protocol !== 'undefined') {
          return '<div class="host other" data-host="' + urlConvert.hostHTML + '"><div class="host-other" data-host-other="' + urlConvert.hostHTML + '">' + urlConvert.hostHTML + '</div></div>';
        } else {
          const searchDefault = isPrivate ? searchEngines.defaultPrivate : searchEngines.default;
          return '<div class="search-engine default" data-search-nickname-default="' + searchDefault.keywordHTML + '" data-search-name-default="' + searchDefault.nameHTML + '"><div class="search-query" data-search-query="' + urlConvert.hostHTML + '">' + urlConvert.hostHTML + '</div></div>';
        }
      }
    
      function getURLPathEl(path) {
        let pathItemHTML;
        return path.replace(pattern.url.path, function (match, pathItem) {
          pathItemHTML = gnoh.encode.html(pathItem);
          return (typeof match !== 'undefined' ? '<div class="path-item" data-path-item="' + pathItemHTML + '">' + (enableDecodeURL === true ? decodeURIComponent(pathItemHTML) : pathItemHTML) + '</div>' : '');
        });
      }
    
      function getURLSearchEl(search) {
        let keyHTML, valueHTML;
        return search.replace(pattern.url.search, function (match, key, valueFull, value) {
          keyHTML = gnoh.encode.html(key);
          valueHTML = gnoh.encode.html(value);
          return [
            '<div class="search-item">',
            typeof key !== 'undefined' ? '<div class="search-key" data-search-key="' + keyHTML + '">' + (enableDecodeURL === true ? decodeURIComponent(keyHTML) : keyHTML) + '</div>' : '',
            typeof valueFull !== 'undefined' ? '<div class="search-value" data-search-value="' + valueHTML + '">' + (enableDecodeURL === true ? decodeURIComponent(valueHTML) : valueHTML) + '</div>' : '',
            '</div>'
          ].join('');
        });
      }
    
      gnoh.timeOut(function (addressfieldEl) {
        isPrivate = document.getElementById('browser').classList.contains('private');
        createMask(addressfieldEl);
        gnoh.override(HTMLElement.prototype, 'appendChild', function (element) {
          var key = gnoh.getReactEventHandlersKey(this);
          if (this[key] && this[key].className === 'UrlField' && element[key] && element[key].className.indexOf('url vivaldi-addressfield') > -1) {
            createMask(element, this);
          }
        });
      }, 'input.url.vivaldi-addressfield');
    })();
    

    CSS:

    /*
     * Mask for the address bar
     * Written by Tam710562
     * Thanks to sjudenim and LonM for bug fixes and new ideas
     */
    
    .addressfield-mask {
      cursor: text;
      padding: 0;
      padding-left: 6px;
      width: 100%;
      height: 22px;
      line-height: normal;
      background-color: transparent;
      border: 0;
      box-shadow: none;
      position: absolute;
      top: 0px;
      left: 0px;
      right: 0px;
      bottom: 0px;
      display: flex;
      align-items: center;
      overflow: hidden;
      z-index: -1;
    }
    
    .addressfield-mask:empty:before {
      content: attr(placeholder);
      opacity: 0.45;
    }
    
    .addressfield-mask div,
    .addressfield-mask div:after,
    .addressfield-mask div:before {
      display: inline-flex;
      position: relative;
      white-space: pre;
      height: 100%;
      align-items: center;
    }
    
    input.vivaldi-addressfield {
      opacity: 0;
    }
    
    .addressfield .UrlField:not(:focus-within) {
      position: relative;
    }
    
    #browser:not(.isblurred) .addressfield > .UrlBar-UrlFieldWrapper:hover .addressfield-mask,
    #browser:not(.isblurred) .addressfield > .UrlBar-UrlFieldWrapper input.vivaldi-addressfield:focus + .addressfield-mask,
    #browser:not(.isblurred) .addressfield > .UrlBar-UrlFieldWrapper input.vivaldi-addressfield:first-child:nth-last-child(3) + .addressfield-mask {
      display: none;
    }
    
    #browser:not(.isblurred) .addressfield > .UrlBar-UrlFieldWrapper:hover input.vivaldi-addressfield,
    #browser:not(.isblurred) .addressfield > .UrlBar-UrlFieldWrapper input.vivaldi-addressfield:focus,
    #browser:not(.isblurred) .addressfield > .UrlBar-UrlFieldWrapper input.vivaldi-addressfield:first-child:nth-last-child(3) {
      opacity: 1;
    }
    
    /* Theme 1 */
    .theme-1.addressfield-mask .protocol-sub,
    .theme-1.addressfield-mask .protocol,
    .theme-1.addressfield-mask .protocol:after,
    .theme-1.addressfield-mask .host .host-sub,
    .theme-1.addressfield-mask .post,
    .theme-1.addressfield-mask .path-full {
      /* color: var(--colorFgFadedMore); */
      /* color: graytext; */
      color: var(--colorFg);
      opacity: 0.7;
    }
    
    .theme-1.addressfield-mask .host {
      color: var(--colorFg);
    }
    
    .addressfield > .secure + .UrlBar-UrlFieldWrapper .theme-1.addressfield-mask .protocol,
    .addressfield > .certified + .UrlBar-UrlFieldWrapper .theme-1.addressfield-mask .protocol {
      color: #46c235;
      opacity: 1;
    }
    
    .theme-1.addressfield-mask .protocol[data-protocol="vivaldi"] {
      color: var(--colorHighlightBg);
      opacity: 1;
    }
    
    .theme-1.addressfield-mask .protocol-sub:after {
      content: ':';
    }
    
    .theme-1.addressfield-mask .protocol:after {
      content: '://';
    }
    
    .theme-1.addressfield-mask .host .host-sub:after {
      content: '.';
    }
    
    .theme-1.addressfield-mask .search-engine .search-nickname:after {
      content: ' ';
    }
    
    .theme-1.addressfield-mask .post:before {
      content: ':';
    }
    
    .theme-1.addressfield-mask .path:before,
    .theme-1.addressfield-mask .path .path-item:not(:first-child):before {
      content: '/';
    }
    
    .theme-1.addressfield-mask .search:before {
      content: '?';
    }
    
    .theme-1.addressfield-mask .search .search-item:not(:first-child):before {
      content: '&';
    }
    
    .theme-1.addressfield-mask .search .search-item .search-value:before {
      content: '=';
    }
    
    .theme-1.addressfield-mask .hash:before {
      content: '#';
    }
    
    .private .theme-1.addressfield-mask .protocol-sub,
    .private .theme-1.addressfield-mask .protocol,
    .private .theme-1.addressfield-mask .protocol:after,
    .private .theme-1.addressfield-mask .host .host-sub,
    .private .theme-1.addressfield-mask .post,
    .private .theme-1.addressfield-mask .path-full,
    .private .theme-1.addressfield-mask .host {
      color: var(--colorBgIntense);
    }
    
    .private .theme-1.addressfield-mask .protocol[data-protocol="vivaldi"] {
      color: var(--colorHighlightBg);
    }
    
    /* Theme 2 */
    .theme-2.addressfield-mask .path-full > div:not(:empty):before {
      content: '';
      height: 12px;
      position: absolute;
      left: -6px;
      top: 50%;
      margin-top: -6px;
      border-left: 1px solid var(--colorFg);
    }
    
    .theme-2.addressfield-mask .path-full > div:not(:empty) {
      margin-left: 6px;
    }
    
    .theme-2.addressfield-mask .protocol-sub,
    .theme-2.addressfield-mask .protocol,
    .theme-2.addressfield-mask .host,
    .theme-2.addressfield-mask .search-engine .search-nickname,
    .theme-2.addressfield-mask .search-engine .search-query:not(:empty),
    .theme-2.addressfield-mask .search-engine.default:before,
    .theme-2.addressfield-mask .post:not(:empty),
    .theme-2.addressfield-mask .path-item:not(:empty),
    .theme-2.addressfield-mask .hash {
      background-color: var(--colorFg);
      color: var(--colorBgIntense);
      margin-right: 5px;
      padding-left: 3px;
      padding-right: 3px;
      border-radius: var(--radiusRoundedLess);
    }
    
    .theme-2.addressfield-mask .search .search-item {
      margin-right: 5px;
    }
    
    .addressfield > .secure + .UrlBar-UrlFieldWrapper .theme-2.addressfield-mask .protocol,
    .addressfield > .certified + .UrlBar-UrlFieldWrapper .theme-2.addressfield-mask .protocol {
      color: #46c235;
      background-color: rgba(85, 204, 68, 0.2);
    }
    
    .theme-2.addressfield-mask .host,
    .theme-2.addressfield-mask .search-engine .search-nickname,
    .theme-2.addressfield-mask .search-engine.default:before {
      background-color: var(--colorAccentBg);
      color: var(--colorAccentFg);
      font-weight: 700;
    }
    
    .theme-2.addressfield-mask .host .host-sub {
      opacity: 0.7;
    }
    
    .theme-2.addressfield-mask .host .host-sub:after {
      content: '.';
    }
    
    .theme-2.addressfield-mask .host .host-extension,
    .theme-2.addressfield-mask .search-engine .search-nickname {
      text-indent: -9999px; 
    }
    
    .theme-2.addressfield-mask .host .host-extension:after {
      text-indent: 0;
      content: attr(data-host-extension-name);
    }
    
    .theme-2.addressfield-mask .search-engine .search-nickname:after {
      text-indent: 0;
      content: attr(data-search-name);
    }
    
    .theme-2.addressfield-mask .search-engine.default:before {
      content: attr(data-search-name-default);
    }
    
    .theme-2.addressfield-mask .search .search-item .search-key {
      background-color: var(--colorAccentBgDarker);
      color: var(--colorAccentFg);
      padding-left: 3px;
      padding-right: 3px;
      border-top-left-radius: var(--radiusRoundedLess);
      border-bottom-left-radius: var(--radiusRoundedLess);
    }
    
    .theme-2.addressfield-mask .search .search-item .search-key:last-child {
      border-top-right-radius: var(--radiusRoundedLess);
      border-bottom-right-radius: var(--radiusRoundedLess);
    }
    
    .theme-2.addressfield-mask .search .search-item .search-value {
      background-color: var(--colorFg);
      color: var(--colorBgIntense);
      padding-left: 3px;
      padding-right: 3px;
      border-top-right-radius: var(--radiusRoundedLess);
      border-bottom-right-radius: var(--radiusRoundedLess);
    }
    
    .theme-2.addressfield-mask .search .search-item .search-value:first-child {
      border-top-left-radius: var(--radiusRoundedLess);
      border-bottom-left-radius: var(--radiusRoundedLess);
    }
    
    .private .theme-2.addressfield-mask .path-full > div:not(:empty):before {
      background-color: var(--colorBgIntense);
    }
    
    .private .theme-2.addressfield-mask .protocol-sub,
    .private .theme-2.addressfield-mask .protocol,
    .private .theme-2.addressfield-mask .search-engine .search-nickname,
    .private .theme-2.addressfield-mask .search-engine .search-query:not(:empty),
    .private .theme-2.addressfield-mask .post:not(:empty),
    .private .theme-2.addressfield-mask .path-item:not(:empty),
    .private .theme-2.addressfield-mask .hash,
    .private .theme-2.addressfield-mask .search .search-item .search-value {
      background-color: var(--colorBgIntense);
      color: var(--colorFgIntense);
    }
    
    /* Theme 3 */
    .theme-3.addressfield-mask {
      justify-content: center;
    }
    
    .theme-3.addressfield-mask .protocol-sub,
    .theme-3.addressfield-mask .protocol,
    .theme-3.addressfield-mask .host .host-sub,
    .theme-3.addressfield-mask .search-engine .search-nickname,
    .theme-3.addressfield-mask .post {
      opacity: 0.7;
    }
    
    .theme-3.addressfield-mask .protocol:not([data-protocol="file"]):not([data-protocol="vivaldi"]):not([data-protocol="chrome"]):not([data-protocol="chrome-extension"]),
    .theme-3.addressfield-mask .path-full {
      display: none;
    }
    
    .theme-3.addressfield-mask .host .host-extension,
    .theme-3.addressfield-mask .search-engine .search-nickname {
      text-indent: -9999px;
      
    }
    
    .theme-3.addressfield-mask .host .host-extension:after {
      text-indent: 0;
      content: attr(data-host-extension-name);
    }
    
    .theme-3.addressfield-mask .search-engine .search-nickname:after {
      text-indent: 0;
      content: attr(data-search-name);
      margin-right: 5px;
    }
    
    .theme-3.addressfield-mask .protocol-sub:after {
      content: ':';
    }
    
    .theme-3.addressfield-mask .protocol:not([data-protocol="file"]):after {
      content: '://';
    }
    
    .theme-3.addressfield-mask .host .host-sub:after {
      content: '.';
    }
    
    .theme-3.addressfield-mask .post:before {
      content: ':';
    }
    
    .theme-3.addressfield-mask .path:before,
    .theme-3.addressfield-mask .path .path-item:not(:first-child):before {
      content: '/';
    }
    
    .theme-3.addressfield-mask .search:before {
      content: '?';
    }
    
    .theme-3.addressfield-mask .search .search-item:not(:first-child):before {
      content: '&';
    }
    
    .theme-3.addressfield-mask .search .search-item .search-value:before {
      content: '=';
    }
    
    .theme-3.addressfield-mask .hash:before {
      content: '#';
    }
    
    input.theme-3.url {
      text-align: center;
    }
    

    Diagram of render classes:

    .addressfield-mask
    ├── .protocol-sub[data-protocol-sub]
    ├── .protocol[data-protocol]
    ├── .host-full[data-host-full]
    │   ├── .host[data-host]┌── .with-sub
    │   │                   │   ├── .host-sub[data-host-sub]
    │   │                   │   └── .host-main[data-host-main]
    │   │                   ├── .extension
    │   │                   │   └── .host-extension[data-host-extension][data-host-extension-name]
    │   │                   ├── .ipv4
    │   │                   │   └── .host-main[data-host-main]
    │   │                   └── .other
    │   │                       └── .host-other[data-host-other]
    │   ├── .post[data-post]
    │   └── .search-engine  ┌── .with-nickname
    │                       │   ├── .search-nickname[data-search-nickname][data-search-name]
    │                       │   └── .search-query[data-search-query]
    │                       └── .default[data-search-nickname-default][data-search-name-default]
    │                           └── .search-query[data-search-query]
    └── .path-full
        ├── .path[data-path]
        │   └── .path-item[data-path-item]
        ├── .search[data-search]
        │   └── .search-item
        │       ├── .search-key[data-search-key]
        │       └── .search-value[data-search-value]
        └── .hash[data-hash]
    

    Changelog

    23/05/2019

    • Create the first version.

    21/07/2019

    • Fix the error for Vivaldi Snapshot 2.7.1609.4
    • Add theme class to addressfield input to align with theme
    • Add extension name for url of chrome-extension

    13/08/2019

    • Fix the error for Vivaldi Snapshot 2.7.1628.12

    02/09/2019

    • Fix the error for Vivaldi Snapshot 2.8.1650.3

    05/09/2019

    • Fix crashed browser in some cases when the address bar contains % character

    Thanks to @sjudenim and @LonM for bug fixes and new ideas



  • Thanks for sharing.

    Theme-3 is inconsistent though, the url left justifies when the field is selected.

    I haven't tested it in this mod, but I've been using this

    .addressfield form input.url {text-align: center}


  • This is amanzing, though I wish I could combine theme 1 and 3. Also as @sjudenim said, hovering over the url makes it align to the left.

    In fact, hovering over the url anytime disables any of the themes completely. I think that should only happen once you click on the url.

    Also a few other things that I noticed:

    • Theme 3 moves the url from left to the center as the page loads (could be due to these elements, but I'm not sure).
    • Text and font in theme 1 is altered when I hover over the url, everything moves slightly down (see here).
    • Theme 3 ignores show full address bar setting (I'm assuming this might be intentional).
    • Focus to the address field is lost for new tabs.


  • I remember the addon LocationBar2 on Firefox:

    0_1558627783319_59030301-49e7-4977-8743-6d65b8570746-image.png

    How I could bold "strong":
    1.- the domain "vivaldi.net"
    2.- all between // and .net

    Thank for your work


  • Moderator

    This is a really cool address bar mod. Much much better than the one I attempted to make.

    What might be a good integration would be if theme 2 worked with ctrl+click selection to navigate "up a level" to other parts on the URL.

    Update: There seems to be some interference with this mod and focusing the address bar


  • Moderator

    I've found a fix for the bug where the address bar doesn't get the focus on creation of a new tab, or pressing "F8". These lines:

    input.vivaldi-addressfield {
        display: none;
      }
    ...
      #browser:not(.isblurred) .addressfield > form:hover input.vivaldi-addressfield,
      #browser:not(.isblurred) .addressfield > form input.vivaldi-addressfield:focus,
      #browser:not(.isblurred) .addressfield > form input.vivaldi-addressfield:first-child:nth-last-child(3) {
        display: inline-block;
      }
    

    Need to be changed to use opacity: 0 to hide, and opacity: 1 to make it visible:

      input.vivaldi-addressfield {
        opacity: 0;
      }
    ...
      #browser:not(.isblurred) .addressfield > form:hover input.vivaldi-addressfield,
      #browser:not(.isblurred) .addressfield > form input.vivaldi-addressfield:focus,
      #browser:not(.isblurred) .addressfield > form input.vivaldi-addressfield:first-child:nth-last-child(3) {
        opacity: 1;
      }
    

    The browser optimises elements with display: none to completely remove interaction with them, which makes it impossible to programatically focus an element not visible.



  • @AltCode said in Mask for the address bar:

    This is amanzing, though I wish I could combine theme 1 and 3.

    Do you mean that you want the full address like in theme 1 but centred as in theme 3?

    .theme-1.addressfield-mask {
      justify-content: center;
    }
    


  • @barbudo2005 said in Mask for the address bar:

    How I could bold "strong":
    1.- the domain "vivaldi.net"
    2.- all between // and .net

    You didn't specify for which theme so I'll demonstrate on the first one

    .theme-1.addressfield-mask .protocol-sub,
    .theme-1.addressfield-mask .protocol,
    .theme-1.addressfield-mask .protocol:after,
    .theme-1.addressfield-mask .host .host-sub,
    .theme-1.addressfield-mask .post,
    .theme-1.addressfield-mask .path-full {
      color: var(--colorFg);
      opacity: .7;
      font-weight: initial
    }
    
    .theme-1.addressfield-mask .host {
      color: var(--colorFg);
      font-weight: bold
    }
    

    You can replace bold with bolder or fine tune it more with 500 600 700 ,etc.


  • Moderator

    The highlighting of when you've entered a search term is nice. It is possible to achieve something similar for chrome-extension URLs. E.g. from this:

    0_1558950190821_ac9f4ab8-2602-44c0-b07c-e8f8f46b141a-image.png

    To This

    0_1558950224300_d2a62f9c-af4d-414f-b5fc-ccaed484d45d-image.png

    Using the chrome extension management API



  • @sjudenim said in Mask for the address bar:

    Theme-3 is inconsistent though, the url left justifies when the field is selected.

    I haven't tested it in this mod, but I've been using this

    .addressfield form input.url {text-align: center}
    

    You may be right, the field should be centered in theme-3 when selected

    @AltCode said in Mask for the address bar:

    In fact, hovering over the url anytime disables any of the themes completely. I think that should only happen once you click on the url.

    This is because I have not found a better way without depending on javascript. But when I looked at @LonM's solution to focus on the new tab, I thought I found a solution

    • Theme 3 moves the url from left to the center as the page loads (could be due to these elements, but I'm not sure).

    That's exactly what caused the error.

    • Text and font in theme 1 is altered when I hover over the url, everything moves slightly down (see here).

    I don't see this in my vivaldi, probably because of different operating systems. I am using windows

    • Theme 3 ignores show full address bar setting (I'm assuming this might be intentional).

    Are you talking about http, https?

    @LonM said in Mask for the address bar:

    The highlighting of when you've entered a search term is nice. It is possible to achieve something similar for chrome-extension URLs. E.g. from this:

    0_1558950190821_ac9f4ab8-2602-44c0-b07c-e8f8f46b141a-image.png

    To This

    0_1558950224300_d2a62f9c-af4d-414f-b5fc-ccaed484d45d-image.png

    Using the chrome extension management API

    A good idea, I'll try it 🙂



  • @tam710562 said in Mask for the address bar:

    • Text and font in theme 1 is altered when I hover over the url, everything moves slightly down (see here).

    I don't see this in my vivaldi, probably because of different operating systems. I am using windows

    I am using macOS. Luckily I was able to find a partial solution. For it to display to not move up and down on macOS, the line:

      line-height: 22px;
    

    Needs to be changed to:

      line-height: 20px;
    

    I am not sure what needs to be changed to prevent the shrinking of the url width every time I hover over the address bar.

    • Theme 3 ignores show full address bar setting (I'm assuming this might be intentional).

    Are you talking about http, https?

    I'm talking about this setting
    0_1558984341426_Screenshot 2019-05-27 at 21.11.52.png

    It does more than just display http and https. In some websites, such as youtube, it displays everything else after the domain that is normally hidden away.

    @sjudenim said in Mask for the address bar:

    Do you mean that you want the full address like in theme 1 but centred as in theme 3?

    No, I meant the colored parts in the address. These are absent from theme 3, but what you offered here is great too.


  • Moderator

    I decided to hide the protocol for times when it's not needed:

    .protocol[data-protocol=https],
    .protocol[data-protocol=vivaldi],
    .protocol[data-protocol=chrome-extension],
    .protocol[data-protocol=file] {
        display: none;
    }
    

    The only protocol that will show is http as that's one I want to be warned about.



  • @tam710562

    Could you update the code in the opening post to work with latest Vivaldi snapshot 2.7.1609.4?
    Thanks



  • This post is deleted!


  • Thank you very much for so great Mod 😉 ! !

    Unfortunately, it doesn't work anymore 😟

    Any solution? Some help?

    Thanks to all who can collaborate with the solution

    🤗



  • Updated a version to fix the error for Vivaldi Snapshot 2.7.1628.12



  • Thanks 😉

    I'll test it

    🤓



  • Perfect 😁

    It's working 😉

    I love this mod 😍

    Thanks again ! !



  • This was one of the few things that i was missing since moving to Vivaldi just recently.

    Nice work!



  • Oops, copied the wrong one. The Update code wasn't working but the top most post is working



Looks like your connection to Vivaldi Forum was lost, please wait while we try to reconnect.