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 || {}, {
      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) {
          this.reactEventHandlersKey =  Object.keys(element).find(function (key) {
            return key.startsWith('__reactEventHandlers');
          });
        }
        return this.reactEventHandlersKey;
      },
      timeOut: function (callback, conditon, timeout) {
        setTimeout(function wait() {
          var result;
          if (typeof conditon === 'string') {
            result = document.querySelector(conditon);
          } else {
            result = conditon();
          }
          if (result) {
            callback(result);
          } else {
            setTimeout(wait, timeout || 300);
          }
        }, timeout || 300);
      },
      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
        });
      }
    });
    
    (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 encodeHTML(rawStr) {
        return !rawStr ? rawStr : rawStr.replace(/[\u00A0-\u9999<>\&"']/gi, function(i) {
           return '&#'+i.charCodeAt(0)+';';
        });
      }
      
      function urlConvertEncodeHTML(urlConvert) {
        Object.keys(urlConvert).forEach(function(key) {
          urlConvert[key+'HTML'] = encodeHTML(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 = encodeHTML(engine.keyword);
            searchEngines.engines[engine.keyword].nameHTML = encodeHTML(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 = encodeHTML(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 = document.createElement('div');
        addressfieldMaskEl.className = addressfieldEl.className;
        addressfieldMaskEl.classList.add('addressfield-mask');
        addressfieldMaskEl.setAttribute('placeholder', addressfieldEl.placeholder);
        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});
    
        addressfieldParentEl.append(addressfieldMaskEl);
      }
    
      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 = encodeHTML(hostSub);
            hostMainHTML = encodeHTML(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 = encodeHTML(hostSub);
            hostMainHTML = encodeHTML(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 = encodeHTML(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 = encodeHTML(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 = encodeHTML(key);
          valueHTML = encodeHTML(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 === 'url vivaldi-addressfield') {
            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

    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



  • Update for Vivaldi Snapshot 2.7.1609.4 and some new features.
    Note: Only used for Snapshot version 2.7.1609.4, not compatible with older versions.

    Javascript:

    /*
     * Mask for the address bar
     * Written by Tam710562
     */
    
    (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 encodeHTML(rawStr) {
        return !rawStr ? rawStr : rawStr.replace(/[\u00A0-\u9999<>\&"']/gi, function(i) {
           return '&#'+i.charCodeAt(0)+';';
        });
      }
      
      function urlConvertEncodeHTML(urlConvert) {
        Object.keys(urlConvert).forEach(function(key) {
          urlConvert[key+'HTML'] = encodeHTML(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 = encodeHTML(engine.keyword);
            searchEngines.engines[engine.keyword].nameHTML = encodeHTML(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 = encodeHTML(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) {
        const addressfieldParentEl = addressfieldEl.parentElement;
        const addressfieldMaskEl = document.createElement('div');
        addressfieldMaskEl.className = addressfieldEl.className;
        addressfieldMaskEl.classList.add('addressfield-mask');
        addressfieldMaskEl.setAttribute('placeholder', addressfieldEl.placeholder);
        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);
            });
          });
        });
    
        const observer = new MutationObserver(function (mutationsList) {
          if (mutationsList[0].attributeName === 'value') {
            changeValue(addressfieldMaskEl, mutationsList[0].target);
          }
        });
        observer.observe(addressfieldEl, {attributes: true});
        
        addressfieldParentEl.appendChild(addressfieldMaskEl);
      }
    
      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 = encodeHTML(hostSub);
            hostMainHTML = encodeHTML(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 = encodeHTML(hostSub);
            hostMainHTML = encodeHTML(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 = encodeHTML(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 = encodeHTML(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 = encodeHTML(key);
          valueHTML = encodeHTML(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('');
        });
      }
    
      setTimeout(function wait() {
        const addressfieldEl = document.querySelector('input.url.vivaldi-addressfield');
        if (addressfieldEl) {
          isPrivate = document.getElementById('browser').classList.contains('private');
          createMask(addressfieldEl);
        } else {
          setTimeout(wait, 300);
        }
      }, 300);
    }());
    

    CSS:

    /*
     * Mask for the address bar
     * Written by Tam710562
     */
    
    .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;
    }
    


  • 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

    🤓



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