Browse Source

Update advanced option page + improve content detection

simov 2 years ago
parent
commit
ad41fd6316

+ 10 - 10
background/detect.js

@@ -33,7 +33,7 @@ md.detect = ({storage: {state}, inject}) => {
           return
           return
         }
         }
 
 
-        if (header(win.header) || match(win.url)) {
+        if (detect(win.header, win.url)) {
           if (onwakeup && chrome.webRequest) {
           if (onwakeup && chrome.webRequest) {
             onwakeup = false
             onwakeup = false
             chrome.tabs.reload(id)
             chrome.tabs.reload(id)
@@ -46,11 +46,7 @@ md.detect = ({storage: {state}, inject}) => {
     }
     }
   }
   }
 
 
-  var header = (value) => {
-    return state.header && value && /text\/(?:x-)?markdown/i.test(value)
-  }
-
-  var match = (url) => {
+  var detect = (content, url) => {
     var location = new URL(url)
     var location = new URL(url)
 
 
     var origin =
     var origin =
@@ -60,10 +56,14 @@ md.detect = ({storage: {state}, inject}) => {
       state.origins['*://' + location.hostname] ||
       state.origins['*://' + location.hostname] ||
       state.origins['*://*']
       state.origins['*://*']
 
 
-    if (origin && origin.match && new RegExp(origin.match).test(location.href)) {
-      return origin
-    }
+    return (
+      (origin && origin.header && origin.path && origin.match && /\btext\/(?:(?:(?:x-)?markdown)|plain)\b/i.test(content) && new RegExp(origin.match).test(location.href)) ||
+      (origin && origin.header && !origin.path && /\btext\/(?:(?:(?:x-)?markdown)|plain)\b/i.test(content)) ||
+      (origin && origin.path && origin.match && !origin.header && new RegExp(origin.match).test(location.href))
+        ? origin
+        : undefined
+    )
   }
   }
 
 
-  return {tab, header, match}
+  return {tab}
 }
 }

+ 17 - 22
background/messages.js

@@ -86,37 +86,19 @@ md.messages = ({storage: {defaults, state, set}, compilers, mathjax, xhr, webreq
       sendResponse()
       sendResponse()
     }
     }
 
 
-    // options
+    // origins view
     else if (req.message === 'options.origins') {
     else if (req.message === 'options.origins') {
       sendResponse({
       sendResponse({
         origins: state.origins,
         origins: state.origins,
-        header: state.header,
         match: state.match,
         match: state.match,
       })
       })
     }
     }
-    else if (req.message === 'options.header') {
-      set({header: req.header})
-      sendResponse()
-    }
-
-    // settings
-    else if (req.message === 'options.settings') {
-      sendResponse({
-        icon: state.icon,
-      })
-    }
-    else if (req.message === 'options.icon') {
-      set({icon: req.icon})
-      icon()
-      sendResponse()
-    }
-
-    // origins
+    // origins options
     else if (req.message === 'origin.add') {
     else if (req.message === 'origin.add') {
       state.origins[req.origin] = {
       state.origins[req.origin] = {
+        header: true,
+        path: true,
         match: defaults.match,
         match: defaults.match,
-        csp: false,
-        encoding: '',
       }
       }
       set({origins: state.origins})
       set({origins: state.origins})
       sendResponse()
       sendResponse()
@@ -134,6 +116,19 @@ md.messages = ({storage: {defaults, state, set}, compilers, mathjax, xhr, webreq
       sendResponse()
       sendResponse()
     }
     }
 
 
+    // settings view
+    else if (req.message === 'options.settings') {
+      sendResponse({
+        icon: state.icon,
+      })
+    }
+    // settings options
+    else if (req.message === 'options.icon') {
+      set({icon: req.icon})
+      icon()
+      sendResponse()
+    }
+
     return true
     return true
   }
   }
 
 

+ 12 - 3
background/storage.js

@@ -42,7 +42,6 @@ md.storage.defaults = (compilers) => {
     theme: 'github',
     theme: 'github',
     compiler: 'marked',
     compiler: 'marked',
     raw: false,
     raw: false,
-    header: true,
     match,
     match,
     themes: {
     themes: {
       width: 'auto',
       width: 'auto',
@@ -58,9 +57,9 @@ md.storage.defaults = (compilers) => {
     },
     },
     origins: {
     origins: {
       'file://': {
       'file://': {
+        header: true,
+        path: true,
         match,
         match,
-        csp: false,
-        encoding: '',
       }
       }
     },
     },
     icon: false,
     icon: false,
@@ -140,4 +139,14 @@ md.storage.migrations = (state) => {
   if (state.remark.footnotes !== undefined) {
   if (state.remark.footnotes !== undefined) {
     delete state.remark.footnotes
     delete state.remark.footnotes
   }
   }
+  // v5.0 -> v5.1
+  if (state.header !== null) {
+    Object.keys(state.origins).forEach((origin) => {
+      state.origins[origin].header = true
+      state.origins[origin].path = true
+      delete state.origins[origin].csp
+      delete state.origins[origin].encoding
+    })
+    state.header = null
+  }
 }
 }

+ 1 - 0
build/README.md

@@ -28,6 +28,7 @@ sh build/package.sh
 | @material/switch    | ^0.36.1
 | @material/switch    | ^0.36.1
 | @material/tabs      | ^0.37.1
 | @material/tabs      | ^0.37.1
 | @material/textfield | ^0.37.1
 | @material/textfield | ^0.37.1
+| bootstrap           |  5.2.3
 | cleanrmd            |  0.1.0
 | cleanrmd            |  0.1.0
 | emojione            |  2.2.7
 | emojione            |  2.2.7
 | github-markdown-css |  5.1.0
 | github-markdown-css |  5.1.0

+ 6 - 0
build/bootstrap/build.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# set current working directory to directory of the shell script
+cd "$(dirname "$0")"
+
+curl https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/css/bootstrap.min.css --output ../../vendor/bootstrap.min.js

+ 0 - 52
build/fontello/fontello.json

@@ -1,52 +0,0 @@
-{
-  "name": "",
-  "css_prefix_text": "icon-",
-  "css_use_suffix": false,
-  "hinting": true,
-  "units_per_em": 1000,
-  "ascent": 850,
-  "glyphs": [
-    {
-      "uid": "0f6a2573a7b6df911ed199bb63717e27",
-      "css": "github",
-      "code": 61595,
-      "src": "fontawesome"
-    },
-    {
-      "uid": "bd7fd67bed189448225cad0fe4ef3d7c",
-      "css": "chrome",
-      "code": 62056,
-      "src": "fontawesome"
-    },
-    {
-      "uid": "d5fabfa46384953ae055fceacb2229a7",
-      "css": "refresh",
-      "code": 59393,
-      "src": "elusive"
-    },
-    {
-      "uid": "8da3ac534210aae9c0f0e13804c1df97",
-      "css": "remove",
-      "code": 59394,
-      "src": "websymbols"
-    },
-    {
-      "uid": "62c089cb34e74b3a1200bc7f5314eb4e",
-      "css": "firefox",
-      "code": 59456,
-      "src": "fontelico"
-    },
-    {
-      "uid": "d9be617b7f2fe7843118ca2d3a1b8cca",
-      "css": "arrow-down",
-      "code": 61444,
-      "src": "mfglabs"
-    },
-    {
-      "uid": "440e148d0e21100118eae7036bcd2067",
-      "css": "arrow-up",
-      "code": 61445,
-      "src": "mfglabs"
-    }
-  ]
-}

+ 1 - 0
build/package.sh

@@ -24,6 +24,7 @@ mkdir -p ../themes
 mkdir -p ../vendor
 mkdir -p ../vendor
 
 
 # build deps
 # build deps
+sh bootstrap/build.sh
 sh marked/build.sh
 sh marked/build.sh
 sh mathjax/build.sh
 sh mathjax/build.sh
 sh mdc/build.sh
 sh mdc/build.sh

+ 0 - 59
options/icons.css

@@ -1,59 +0,0 @@
-@font-face {
-  font-family: 'fontello';
-  src: url('icons.ttf') format('truetype');
-  font-weight: normal;
-  font-style: normal;
-}
-/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
-/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
-/*
-@media screen and (-webkit-min-device-pixel-ratio:0) {
-  @font-face {
-    font-family: 'fontello';
-    src: url('../font/fontello.svg?68292491#fontello') format('svg');
-  }
-}
-*/
- 
- [class^="icon-"]:before, [class*=" icon-"]:before {
-  font-family: "fontello";
-  font-style: normal;
-  font-weight: normal;
-  speak: none;
- 
-  display: inline-block;
-  text-decoration: inherit;
-  width: 1em;
-  margin-right: .2em;
-  text-align: center;
-  /* opacity: .8; */
- 
-  /* For safety - reset parent styles, that can break glyph codes*/
-  font-variant: normal;
-  text-transform: none;
- 
-  /* fix buttons height, for twitter bootstrap */
-  line-height: 1em;
- 
-  /* Animation center compensation - margins should be symmetric */
-  /* remove if not needed */
-  margin-left: .2em;
- 
-  /* you can be more comfortable with increased icons size */
-  /* font-size: 120%; */
- 
-  /* Font smoothing. That was taken from TWBS */
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
- 
-  /* Uncomment for 3D effect */
-  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
-}
- 
-.icon-refresh:before { content: '\e801'; } /* '' */
-.icon-remove:before { content: '\e802'; } /* '' */
-.icon-firefox:before { content: '\e840'; } /* '' */
-.icon-arrow-down:before { content: '\f004'; } /* '' */
-.icon-arrow-up:before { content: '\f005'; } /* '' */
-.icon-github:before { content: '\f09b'; } /* '' */
-.icon-chrome:before { content: '\f268'; } /* '' */

BIN
options/icons.ttf


+ 83 - 281
options/index.css

@@ -1,87 +1,66 @@
 
 
-/*sticky footer*/
-html, body {
-  height: 100%;
-  padding: 0;
-  margin: 0;
-}
-#wrapper {
-  min-height: 100%;
-  height: auto !important;
-  height: 100%;
-  margin: 0 auto -40px;
-}
-footer, #footer-push {
-  height: 40px;
-  text-align: center;
-}
-
-
-/*center content on large screens*/
-main {
-  max-width: 1200px;
-  margin: 0 auto;
-}
+/*---------------------------------------------------------------------------*/
+/*global*/
 
 
-/*font family*/
 body,
 body,
 body label,
 body label,
 body input {
 body input {
   font-family: 'Monospace', monospace !important;
   font-family: 'Monospace', monospace !important;
 }
 }
-body select,
-body button,
-.m-name {
+body button {
   font-family: sans-serif !important;
   font-family: sans-serif !important;
 }
 }
 
 
-
 /*content*/
 /*content*/
 main {
 main {
-  padding: 90px 0 30px 0;
+  padding-top: 120px;
 }
 }
-a { text-decoration: none; }
-a:hover { text-decoration: none; }
 
 
-
-/*global*/
+/*misc*/
 .hidden {
 .hidden {
   display: none;
   display: none;
 }
 }
+.overflow {
+  white-space: nowrap;
+  overflow: hidden;
+  min-height: 52px;
+}
 
 
-/*header*/
-#header {
-  background: #607d8b;
-  position: fixed;
-  z-index: 100;
-  width: 100%;
-  height: 60px;
-  font-size: 20px;
-  line-height: 60px;
-  color: #fff;
+/*---------------------------------------------------------------------------*/
+/*sticky footer*/
+
+html, body {
+  height: 100%;
+  padding: 0;
+  margin: 0;
 }
 }
-#header .holder {
-  width: 100%;
-  max-width: 1200px;
-  margin: 0 auto;
-  display: flex;
-  justify-content: space-between;
+#wrapper {
+  min-height: 100%;
+  height: auto !important;
+  height: 100%;
+  margin: 0 auto -40px;
+}
+footer, #footer-push {
+  height: 40px;
+  text-align: center;
 }
 }
 
 
-
+/*---------------------------------------------------------------------------*/
 /*header menu*/
 /*header menu*/
+
 #menu {
 #menu {
   position: relative;
   position: relative;
   color: #fff;
   color: #fff;
 }
 }
 #menu span {
 #menu span {
+  font-size: 20px;
   display: inline-block;
   display: inline-block;
   line-height: 60px;
   line-height: 60px;
   padding: 0 20px;
   padding: 0 20px;
 }
 }
 #menu div {
 #menu div {
   position: absolute;
   position: absolute;
-  top: 60px;
+  top: 68px;
   right: 0;
   right: 0;
   z-index: 10;
   z-index: 10;
   width: 200px;
   width: 200px;
@@ -92,7 +71,8 @@ a:hover { text-decoration: none; }
 }
 }
 #menu em {
 #menu em {
   display: block;
   display: block;
-  font-size: 16px;
+  font-size: 20px;
+  line-height: 50px;
   font-style: normal;
   font-style: normal;
   color: #333;
   color: #333;
   cursor: pointer;
   cursor: pointer;
@@ -109,34 +89,9 @@ a:hover { text-decoration: none; }
   background: #ececec;
   background: #ececec;
 }
 }
 
 
+/*---------------------------------------------------------------------------*/
+/*scrollbar*/
 
 
-/*footer*/
-footer {
-  font-size: 14px;
-  line-height: 40px;
-  color: #9e9e9e;
-  text-align: center;
-  background: #424242;
-}
-footer a {
-  color: #9e9e9e;
-  text-decoration: none;
-}
-footer .icon-chrome { margin-right: 10px; }
-footer .icon-chrome:before { font-size: 17px; }
-footer .icon-firefox { margin-right: 10px; }
-footer .icon-firefox:before {
-  font-size: 18px; position: relative; top: 1px;
-}
-footer .icon-github:before {
-  font-size: 20px; position: relative; top: 1px;
-}
-footer .icon-hidden {
-  display: none;
-}
-
-
-/*custom scrollbars in WebKit*/
 ::-webkit-scrollbar,
 ::-webkit-scrollbar,
 ::-webkit-scrollbar-corner {
 ::-webkit-scrollbar-corner {
   height: 10px;
   height: 10px;
@@ -154,31 +109,21 @@ footer .icon-hidden {
   background-color: #607d8b;
   background-color: #607d8b;
 }
 }
 
 
-
+/*---------------------------------------------------------------------------*/
 /*bootstrap callout*/
 /*bootstrap callout*/
+
 .bs-callout {
 .bs-callout {
   border: 1px solid #eee;
   border: 1px solid #eee;
   border-left-width: 5px;
   border-left-width: 5px;
   border-left-color: #607d8b;
   border-left-color: #607d8b;
   border-radius: 3px;
   border-radius: 3px;
   background: #fcfcfc;
   background: #fcfcfc;
-  padding: 20px;
+  padding: 20px 20px 10px 20px;
   margin: 0 0 30px 0;
   margin: 0 0 30px 0;
 }
 }
-.bs-callout h4 {
-  font-size: 24px;
-  line-height: 36px;
-  font-weight: normal;
-  margin: 0 !important;
-}
-
-.mdc-elevation--z2 {
-  box-shadow:
-    0 3px 1px -2px rgba(0,0,0,.2),
-    0 2px 2px 0 rgba(0,0,0,.14),
-    0 1px 5px 0 rgba(0,0,0,.12);
-}
 
 
+/*---------------------------------------------------------------------------*/
+/*mdc controls*/
 
 
 /*button*/
 /*button*/
 .m-button {
 .m-button {
@@ -192,234 +137,91 @@ footer .icon-hidden {
   background-color: rgba(96, 125, 139, 0.56) !important;
   background-color: rgba(96, 125, 139, 0.56) !important;
 }
 }
 
 
-
 /*switch*/
 /*switch*/
 .m-switch {
 .m-switch {
   cursor: pointer;
   cursor: pointer;
-  display: table;
-  margin: 7px 0;
+  /*display: table;*/
+  margin: 14px 0;
 }
 }
 .m-switch .mdc-switch__background {
 .m-switch .mdc-switch__background {
   display: inline-block;
   display: inline-block;
-  bottom: 5px;
+  bottom: 0px;
   left: 15px;
   left: 15px;
 }
 }
 .m-switch .mdc-switch-label {
 .m-switch .mdc-switch-label {
   font-size: 1rem;
   font-size: 1rem;
   line-height: 1.5rem;
   line-height: 1.5rem;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  display: inline-block;
   padding: 0 0 0 30px;
   padding: 0 0 0 30px;
 }
 }
-.m-switch .mdc-switch-label code {
-  font-size: 16px;
-}
-
-
-/*select*/
-.m-select {
-  font-size: 14px;
-  line-height: 17px;
-  color: #000;
-  text-transform: uppercase;
-  background-color: #ececec;
-  border: none;
-  border-radius: 2px;
-  cursor: pointer;
-  padding: 9px 12px;
-}
-
 
 
 /*textfield*/
 /*textfield*/
 .m-textfield {
 .m-textfield {
   font-size: 1rem;
   font-size: 1rem;
   line-height: 1.5rem;
   line-height: 1.5rem;
-  height: auto;
-  margin: 0;
-}
-
-
-/*add origin*/
-
-.m-add-origin {}
-.m-add-origin:after { content: ''; display: block; clear: both; }
-.m-add-origin h4 {
-  float: left;
-  padding: 0 100px 0 0;
-}
-.m-add-origin .m-select {
-  width: 110px;
-  position: relative;
-  top: -1px;
-}
-.m-add-origin .m-textfield {
-  width: 400px;
-  height: auto !important;
-  padding: 0 !important;
-  margin: 0 10px !important;
+  width: 100%;
+  height: 26px !important;
+  margin-left: 10px;
 }
 }
-.m-add-origin .m-textfield input {
+.m-textfield input {
+  border-bottom: 1px solid #ececec !important;
   padding-top: 3px;
   padding-top: 3px;
 }
 }
-.m-add-origin button:nth-of-type(1) {
-  position: relative;
-  top: -3px;
-}
-.m-add-origin button:nth-of-type(2) {
-  float: right;
-}
 
 
+/*---------------------------------------------------------------------------*/
+/*misc*/
 
 
-/*global*/
-.m-global {
-  margin: 20px 0 0 0;
-}
-.m-global:after { content: ''; display: block; clear: both; }
-.m-global .m-switch {
-  float: left;
-}
-.m-global button {
-  float: right;
+.navbar-brand {
+  font-size: 1.5rem;
 }
 }
 
 
-
-/*list*/
-
-.m-list {
-  list-style: none;
-  padding: 0;
-  margin: 20px 0 0 0;
+h4 {
+  margin-bottom: 1.5rem;
 }
 }
 
 
-.m-list li {
-  background: #fff;
-  transition-duration: .28s;
-  transition-timing-function: cubic-bezier(.4,0,.2,1);
-  transition-property: background-color box-shadow;
-  border-bottom: 1px solid #ececec;
+.m-box-add {
+  border-left-color: #f1b100;
 }
 }
-.m-list li:first-child {
 
 
-}
-.m-list li:last-child {
-  margin-bottom: 0 !important;
-}
-.m-list li:hover:not(.m-expanded) { background: #ececec; }
-.m-list li:after { content: ''; display: block; clear: both; }
-.m-list li.m-expanded {
-  border: 0;
-  margin: 20px 0;
+.m-box-refresh {
+  border-left-color: #d9534f;
 }
 }
 
 
-/*list summary*/
-
-.m-list .m-summary {
-  display: block;
-  height: 36px;
-  padding: 10px 20px 0 20px;
-  cursor: pointer;
-  position: relative;
+.m-origin {
+  font-size: 1.3rem;
+  padding-left: 10px;
 }
 }
-.m-list .m-summary:after { content: ''; display: block; clear: both; }
-.m-list .m-summary .m-title {
-  float: left;
-  font-size: 16px;
-  line-height: 28px;
-}
-.m-list .m-summary .m-options {
+
+.m-btn-file {
   float: right;
   float: right;
-  padding: 6px 25px 0 0;
-}
-.m-list .m-summary .m-options span {
-  background: #ececec;
-  font-size: 12px;
-  line-height: 15px;
-  padding: 2px 5px;
-  border-radius: 3px;
-  margin: 0 5px 0 0;
+  margin-bottom: 12px;
 }
 }
-.m-list .m-summary i {
-  position: absolute;
-  top: 17px;
-  right: 17px;
-}
-
-/*list content*/
 
 
-.m-list .m-content {
-  display: none;
-  background: #fff;
-  padding: 0 20px 12px 20px;
-  position: relative;
-}
-.m-list .m-expanded .m-summary {
-  background: #ececec;
-}
-.m-list .m-expanded .m-content {
-  display: block;
+.m-btn-all {
+  float: right;
+  margin-bottom: 12px;
 }
 }
 
 
-/*list option*/
-
-.m-list .m-content .m-option {
-  min-height: 50px;
-}
-.m-list .m-content .m-option:after { content: ''; display: block; clear: both; }
-.m-list .m-content .m-option .m-name {
-  float: left;
-  width: 10%;
-  font-size: 14px;
-  line-height: 50px;
-  text-align: right;
-}
-.m-list .m-content .m-option .m-name span {
-  font-size: 12px;
-  line-height: 15px;
-  text-transform: uppercase;
-}
-.m-list .m-content .m-option .m-control {
-  float: left;
-  width: 90%;
-}
-.m-list .m-content .m-option .m-control .m-textfield {
-  height: 43px;
-  margin: 0 0 7px 10px;
-}
-.m-list .m-content .m-option .m-control .m-textfield input {
-  border-bottom: 1px solid #ececec !important;
-  padding-top: 3px;
+.m-btn-add {
+  float: right;
 }
 }
 
 
-
-/*list options - origin*/
-
-.m-list .m-content .m-option.m-match .m-control {
-  width: 80%;
-  margin: 0 0 0 15px;
+.m-btn-remove {
+  float: right;
 }
 }
-.m-list .m-content .m-option.m-match .m-textfield {
-  width: 100%;
+
+.m-btn-refresh {
+  float: right;
+  margin-right: 20px;
 }
 }
-.m-list .m-content .m-option.m-csp label {
-  margin: 12px 0 0 10px;
+
+footer nav {
+  font-size: .8rem;
+  color: #212529;
 }
 }
-.m-list .m-content .m-option.m-encoding select {
-  width: 200px;
-  margin: 6px 0 0 25px;
+footer nav a {
+  text-decoration: none;
+  color: #212529;
 }
 }
-
-
-/*list footer*/
-
-.m-list .m-footer {
-  text-align: right;
-  margin: 10px 0 8px 0;
-  /*position: absolute;
-  bottom: 20px;
-  right: 20px;*/
-}
-.m-list .m-footer .m-button:last-child {
-  margin: 0 0 0 20px;
+footer nav a:hover {
+  text-decoration: underline;
 }
 }

+ 13 - 11
options/index.html

@@ -4,36 +4,38 @@
   <meta charset="utf-8" />
   <meta charset="utf-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1" />
   <meta name="viewport" content="width=device-width, initial-scale=1" />
   <title>Markdown Viewer</title>
   <title>Markdown Viewer</title>
+  <link href="/vendor/bootstrap.min.css" rel="stylesheet" type="text/css" media="all" />
   <link href="/vendor/mdc.min.css" rel="stylesheet" type="text/css" media="all" />
   <link href="/vendor/mdc.min.css" rel="stylesheet" type="text/css" media="all" />
-  <link href="/options/icons.css" rel="stylesheet" type="text/css" media="all" />
   <link href="/options/index.css" rel="stylesheet" type="text/css" media="all" />
   <link href="/options/index.css" rel="stylesheet" type="text/css" media="all" />
   <script src="/vendor/mdc.min.js" type="text/javascript" charset="utf-8"></script>
   <script src="/vendor/mdc.min.js" type="text/javascript" charset="utf-8"></script>
   <script src="/vendor/mithril.min.js" type="text/javascript" charset="utf-8"></script>
   <script src="/vendor/mithril.min.js" type="text/javascript" charset="utf-8"></script>
 </head>
 </head>
-<body class="mdc-typography">
+<body>
   <div id="wrapper">
   <div id="wrapper">
-    <div id="header" class="mdc-elevation--z2">
-      <div class="holder">
-        <span>Markdown Viewer</span>
+    <nav class="navbar navbar-dark bg-dark fixed-top">
+      <div class="container">
+        <a href="https://github.com/simov/markdown-viewer" class="navbar-brand">Markdown Viewer</a>
         <a href="#" id="menu">
         <a href="#" id="menu">
           <span>☰</span>
           <span>☰</span>
           <div class="hidden">
           <div class="hidden">
-            <em class="active">Manage Origins</em>
+            <em class="active">Origins</em>
             <em>Settings</em>
             <em>Settings</em>
             <em>Help</em>
             <em>Help</em>
           </div>
           </div>
         </a>
         </a>
       </div>
       </div>
+    </nav>
+    <div class="container">
+      <main></main>
     </div>
     </div>
-    <main></main>
     <div id="footer-push">&nbsp;</div>
     <div id="footer-push">&nbsp;</div>
   </div>
   </div>
   <footer>
   <footer>
     <nav>
     <nav>
-      <a href="https://chrome.google.com/webstore/detail/markdown-viewer/ckkdlimhmcjmikdlpkmbgfkaikojcbjk" class="icon-chrome icon-hidden">Chrome Store</a>
-      <a href="https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/" class="icon-firefox icon-hidden">Firefox Store</a>
-      <a href="https://microsoftedge.microsoft.com/addons/detail/markdown-viewer/cgfmehpekedojlmjepoimbfcafopimdg" class="icon-edge icon-hidden">Edge</a>
-      <a href="https://github.com/simov/markdown-viewer" class="icon-github">GitHub</a>
+      <a href="https://github.com/simov/markdown-viewer">GitHub</a> &bullet;
+      <a href="https://chrome.google.com/webstore/detail/markdown-viewer/ckkdlimhmcjmikdlpkmbgfkaikojcbjk">Chrome</a> &bullet;
+      <a href="https://microsoftedge.microsoft.com/addons/detail/markdown-viewer/cgfmehpekedojlmjepoimbfcafopimdg">Edge</a> &bullet;
+      <a href="https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/">Firefox</a>
     </nav>
     </nav>
   </footer>
   </footer>
 </body>
 </body>

+ 1 - 8
options/index.js

@@ -18,7 +18,7 @@ document.querySelector('#menu div').addEventListener('click', (e) => {
   Array.from(document.querySelectorAll('#menu em')).forEach((link) => {
   Array.from(document.querySelectorAll('#menu em')).forEach((link) => {
     link.classList.remove('active')
     link.classList.remove('active')
   })
   })
-  if (e.target.innerText === 'Manage Origins') {
+  if (e.target.innerText === 'Origins') {
     document.querySelector('.m-origins').classList.remove('hidden')
     document.querySelector('.m-origins').classList.remove('hidden')
     document.querySelector('.m-settings').classList.add('hidden')
     document.querySelector('.m-settings').classList.add('hidden')
     e.target.classList.add('active')
     e.target.classList.add('active')
@@ -33,10 +33,3 @@ document.querySelector('#menu div').addEventListener('click', (e) => {
   }
   }
   document.querySelector('#menu div').classList.add('hidden')
   document.querySelector('#menu div').classList.add('hidden')
 })
 })
-
-// ff: set appropriate footer icon
-document.querySelector('.icon-' + (
-  /Firefox/.test(navigator.userAgent) ? 'firefox' :
-  /Edg/.test(navigator.userAgent) ? 'edge' :
-  'chrome'
-)).classList.remove('icon-hidden')

+ 222 - 241
options/origins.js

@@ -3,36 +3,11 @@ var Origins = () => {
   var defaults = {
   var defaults = {
     // storage
     // storage
     origins: {},
     origins: {},
-    header: false,
     match: '',
     match: '',
     // UI
     // UI
-    scheme: 'https',
     host: '',
     host: '',
     timeout: null,
     timeout: null,
     file: true,
     file: true,
-    // static
-    schemes: ['https', 'http', '*'],
-    // encodings: {
-    //   'Unicode': ['UTF-8', 'UTF-16LE'],
-    //   'Arabic': ['ISO-8859-6', 'Windows-1256'],
-    //   'Baltic': ['ISO-8859-4', 'ISO-8859-13', 'Windows-1257'],
-    //   'Celtic': ['ISO-8859-14'],
-    //   'Central European': ['ISO-8859-2', 'Windows-1250'],
-    //   'Chinese Simplified': ['GB18030', 'GBK'],
-    //   'Chinese Traditional': ['BIG5'],
-    //   'Cyrillic': ['ISO-8859-5', 'IBM866', 'KOI8-R', 'KOI8-U', 'Windows-1251'],
-    //   'Greek': ['ISO-8859-7', 'Windows-1253'],
-    //   'Hebrew': ['Windows-1255', 'ISO-8859-8', 'ISO-8859-8-I'],
-    //   'Japanese': ['EUC-JP', 'ISO-2022-JP', 'Shift_JIS'],
-    //   'Korean': ['EUC-KR'],
-    //   'Nordic': ['ISO-8859-10'],
-    //   'Romanian': ['ISO-8859-16'],
-    //   'South European': ['ISO-8859-3'],
-    //   'Thai': ['Windows-874'],
-    //   'Turkish': ['Windows-1254'],
-    //   'Vietnamese': ['Windows-1258'],
-    //   'Western': ['ISO-8859-15', 'Windows-1252', 'Macintosh'],
-    // },
     // chrome
     // chrome
     permissions: {},
     permissions: {},
   }
   }
@@ -60,25 +35,14 @@ var Origins = () => {
       chrome.tabs.create({url: `chrome://extensions/?id=${chrome.runtime.id}`})
       chrome.tabs.create({url: `chrome://extensions/?id=${chrome.runtime.id}`})
     },
     },
 
 
-    header: (e) => {
-      state.header = !state.header
-      chrome.runtime.sendMessage({
-        message: 'options.header',
-        header: state.header,
-      })
-    },
-
     origin: {
     origin: {
-      scheme: (e) => {
-        state.scheme = state.schemes[e.target.selectedIndex]
-      },
-
       host: (e) => {
       host: (e) => {
+        state.scheme = e.target.value.replace(/(.*):\/\/.*/i, '$1')
         state.host = e.target.value.replace(/.*:\/\/([^/]+).*/i, '$1')
         state.host = e.target.value.replace(/.*:\/\/([^/]+).*/i, '$1')
       },
       },
 
 
       add: (all) => () => {
       add: (all) => () => {
-        if (!all && !state.host) {
+        if (!all && !state.host && !['https', 'http', '*'].includes(state.scheme)) {
           return
           return
         }
         }
         var origin = all ? '*://*' : `${state.scheme}://${state.host}`
         var origin = all ? '*://*' : `${state.scheme}://${state.host}`
@@ -86,9 +50,9 @@ var Origins = () => {
           if (granted) {
           if (granted) {
             chrome.runtime.sendMessage({message: 'origin.add', origin})
             chrome.runtime.sendMessage({message: 'origin.add', origin})
             state.origins[origin] = {
             state.origins[origin] = {
+              header: true,
+              path: true,
               match: state.match,
               match: state.match,
-              csp: false,
-              encoding: '',
             }
             }
             state.host = ''
             state.host = ''
             state.permissions[origin] = true
             state.permissions[origin] = true
@@ -117,38 +81,38 @@ var Origins = () => {
         })
         })
       },
       },
 
 
-      match: (origin) => (e) => {
-        state.origins[origin].match = e.target.value
-        clearTimeout(state.timeout)
-        state.timeout = setTimeout(() => {
-          var {match, csp, encoding} = state.origins[origin]
-          chrome.runtime.sendMessage({
-            message: 'origin.update',
-            origin,
-            options: {match, csp, encoding},
-          })
-        }, 750)
-      },
-
-      csp: (origin) => () => {
-        state.origins[origin].csp = !state.origins[origin].csp
-        var {match, csp, encoding} = state.origins[origin]
+      header: (origin) => () => {
+        state.origins[origin].header = !state.origins[origin].header
+        var {header, path, match} = state.origins[origin]
         chrome.runtime.sendMessage({
         chrome.runtime.sendMessage({
           message: 'origin.update',
           message: 'origin.update',
           origin,
           origin,
-          options: {match, csp, encoding},
+          options: {header, path, match},
         })
         })
       },
       },
 
 
-      encoding: (origin) => (e) => {
-        state.origins[origin].encoding = e.target.value
-        var {match, csp, encoding} = state.origins[origin]
+      path: (origin) => () => {
+        state.origins[origin].path = !state.origins[origin].path
+        var {header, path, match} = state.origins[origin]
         chrome.runtime.sendMessage({
         chrome.runtime.sendMessage({
           message: 'origin.update',
           message: 'origin.update',
           origin,
           origin,
-          options: {match, csp, encoding},
+          options: {header, path, match},
         })
         })
       },
       },
+
+      match: (origin) => (e) => {
+        state.origins[origin].match = e.target.value
+        clearTimeout(state.timeout)
+        state.timeout = setTimeout(() => {
+          var {header, path, match} = state.origins[origin]
+          chrome.runtime.sendMessage({
+            message: 'origin.update',
+            origin,
+            options: {header, path, match},
+          })
+        }, 750)
+      },
     },
     },
   }
   }
 
 
@@ -162,211 +126,228 @@ var Origins = () => {
   }
   }
 
 
   var onupdate = {
   var onupdate = {
-    header: (vnode) => {
-      if (vnode.dom.classList.contains('is-checked') !== state.header) {
+    header: (origin) => (vnode) => {
+      if (vnode.dom.classList.contains('is-checked') !== state.origins[origin].header) {
         vnode.dom.classList.toggle('is-checked')
         vnode.dom.classList.toggle('is-checked')
       }
       }
     },
     },
-    csp: (origin) => (vnode) => {
-      if (vnode.dom.classList.contains('is-checked') !== state.origins[origin].csp) {
+    path: (origin) => (vnode) => {
+      if (vnode.dom.classList.contains('is-checked') !== state.origins[origin].path) {
         vnode.dom.classList.toggle('is-checked')
         vnode.dom.classList.toggle('is-checked')
       }
       }
     }
     }
   }
   }
 
 
   var render = () =>
   var render = () =>
-    m('.bs-callout m-origins',
+    m('.m-origins',
 
 
-      // add origin
-      m('.m-add-origin',
-        m('h4.mdc-typography--headline5', 'Allowed Origins'),
-        m('select.mdc-elevation--z2 m-select', {
-          onchange: events.origin.scheme
-          },
-          state.schemes.map((scheme) =>
-          m('option', {
-            value: scheme,
-            selected: scheme === state.scheme
+      // file access
+      m('.row',
+        m('.col-xxl-10.col-xl-10.col-lg-9.col-md-8.col-sm-12',
+          m('h3', 'File Access'),
+        ),
+        m('.col-xxl-2.col-xl-2.col-lg-3.col-md-4.col-sm-12',
+          // file access is disabled
+          (!state.file || null) &&
+          m('button.mdc-button mdc-button--raised m-button m-btn-file', {
+            oncreate: oncreate.ripple,
+            onclick: events.file
             },
             },
-            scheme + '://'
+            'Allow Access'
           )
           )
-        )),
-        m('.mdc-text-field m-textfield', {
-          oncreate: oncreate.textfield,
-          },
-          m('input.mdc-text-field__input', {
-            type: 'text',
-            value: state.host,
-            onchange: events.origin.host,
-            placeholder: 'raw.githubusercontent.com'
-          }),
-          m('.mdc-line-ripple')
         ),
         ),
-        m('button.mdc-button mdc-button--raised m-button', {
-          oncreate: oncreate.ripple,
-          onclick: events.origin.add()
-          },
-          'Add'
+      ),
+      state.file &&
+      Object.keys(state.origins).filter((origin) => origin === 'file://').map((origin) =>
+        m('.bs-callout',
+          // origin
+          m('.row',
+            m('.col-xxl-8.col-xl-8.col-lg-8.col-md-8.col-sm-12', m('span.m-origin', origin)),
+            m('.col-xxl-4.col-xl-4.col-lg-4.col-md-4.col-sm-12')
+          ),
+          // header detection
+          m('.row',
+            m('.col-sm-12',
+              m('.overflow',
+                m('label.mdc-switch m-switch', {
+                  onupdate: onupdate.header,
+                  title: 'Toggle Header Detection'
+                  },
+                  m('input.mdc-switch__native-control', {
+                    type: 'checkbox',
+                    checked: state.origins[origin].header,
+                    onchange: events.origin.header(origin)
+                  }),
+                  m('.mdc-switch__background', m('.mdc-switch__knob')),
+                  m('span.mdc-switch-label',
+                    'Content Type Detection: ',
+                    m('span', 'text/markdown'),
+                    ', ',
+                    m('span', 'text/x-markdown'),
+                    ', ',
+                    m('span', 'text/plain'),
+                  )
+                ),
+              )
+            )
+          ),
+          // path matching regexp
+          m('.row',
+            m('.col-sm-12',
+              m('.overflow',
+                m('label.mdc-switch m-switch', {
+                  onupdate: onupdate.path,
+                  title: 'Toggle Path Detection'
+                  },
+                  m('input.mdc-switch__native-control', {
+                    type: 'checkbox',
+                    checked: state.origins[origin].path,
+                    onchange: events.origin.path(origin)
+                  }),
+                  m('.mdc-switch__background', m('.mdc-switch__knob')),
+                  m('span.mdc-switch-label',
+                    'Path Matching RegExp: '
+                  )
+                ),
+                m('.mdc-text-field m-textfield', {
+                  oncreate: oncreate.textfield
+                  },
+                  m('input.mdc-text-field__input', {
+                    type: 'text',
+                    onkeyup: events.origin.match(origin),
+                    value: state.origins[origin].match,
+                  }),
+                  m('.mdc-line-ripple')
+                )
+              )
+            )
+          )
         ),
         ),
-        m('button.mdc-button mdc-button--raised m-button', {
-          oncreate: oncreate.ripple,
-          onclick: events.origin.add(true)
-          },
-          'Allow All'
-        )
       ),
       ),
 
 
-      // global options
-      m('.m-global',
-        (
-          (
-            // header detection - ff: disabled
-            !/Firefox/.test(navigator.userAgent) && (
-              Object.keys(state.origins).length > 1 ||
-              Object.keys(state.origins).length === 1 && state.file)
-          )
-          || null
-        ) &&
-        m('label.mdc-switch m-switch', {
-          onupdate: onupdate.header,
-          title: 'Toggle header detection'
-          },
-          m('input.mdc-switch__native-control', {
-            type: 'checkbox',
-            checked: state.header,
-            onchange: events.header
-          }),
-          m('.mdc-switch__background', m('.mdc-switch__knob')),
-          m('span.mdc-switch-label',
-            'Detect ',
-            m('code', 'text/markdown'),
-            ' and ',
-            m('code', 'text/x-markdown'),
-            ' content type'
-          )
+      // site access
+      m('.row',
+        m('.col-xxl-10.col-xl-10.col-lg-10.col-md-9.col-sm-8',
+          m('h3', 'Site Access'),
+        ),
+        (!Object.keys(state.origins).includes('*://*') || null) &&
+        m('.col-xxl-2.col-xl-2.col-lg-2.col-md-3.col-sm-4',
+          m('button.mdc-button mdc-button--raised m-button m-btn-all', {
+            oncreate: oncreate.ripple,
+            onclick: events.origin.add(true)
+            },
+            'Allow All'
+          ),
         ),
         ),
+      ),
 
 
-        // file access is disabled
-        (!state.file || null) &&
-        m('button.mdc-button mdc-button--raised m-button', {
-          oncreate: oncreate.ripple,
-          onclick: events.file
-          },
-          'Allow Access to file:// URLs'
+      // add origin
+      m('.bs-callout m-box-add',
+        m('.row',
+          m('.col-xxl-11.col-xl-11.col-lg-10.col-md-10.col-sm-12',
+            m('.mdc-text-field m-textfield', {
+              oncreate: oncreate.textfield,
+              },
+              m('input.mdc-text-field__input', {
+                type: 'text',
+                value: state.host,
+                onchange: events.origin.host,
+                placeholder: 'Copy URL address and paste it here'
+              }),
+              m('.mdc-line-ripple')
+            ),
+          ),
+          m('.col-xxl-1.col-xl-1.col-lg-2.col-md-2.col-sm-12',
+            m('button.mdc-button mdc-button--raised m-button m-btn-add', {
+              oncreate: oncreate.ripple,
+              onclick: events.origin.add()
+              },
+              'Add'
+            ),
+          )
         )
         )
       ),
       ),
 
 
       // allowed origins
       // allowed origins
-      (state.file || Object.keys(state.origins).length > 1 || null) &&
-      m('ul.m-list',
-        Object.keys(state.origins).sort((a, b) => a < b ? 1 : a > b ? -1 : 0).map((origin) =>
-          (
-            (
-              state.file && origin === 'file://' &&
-              // ff: access to file:// URLs is not allowed
-              !/Firefox/.test(navigator.userAgent)
-            )
-            || origin !== 'file://' || null
-          ) &&
-          m('li.mdc-elevation--z2', {
-            class: state.origins[origin].expanded ? 'm-expanded' : null,
-            },
-            m('.m-summary', {
-              onclick: (e) => state.origins[origin].expanded = !state.origins[origin].expanded
-              },
-              m('.m-title', origin),
-              m('.m-options',
-                !state.permissions[origin] ? m('span', m('strong', 'refresh')) : null,
-                state.origins[origin].match !== state.match ? m('span', 'match') : null,
-                state.origins[origin].csp ? m('span', 'csp') : null,
-                state.origins[origin].encoding ? m('span', 'encoding') : null
+      Object.keys(state.origins)
+        .sort((a, b) => a < b ? 1 : a > b ? -1 : 0)
+        .filter((origin) => origin !== 'file://')
+        .map((origin) =>
+        m('.bs-callout', {class: !state.permissions[origin] ? 'm-box-refresh' : undefined},
+          // origin
+          m('.row',
+            m('.col-xxl-8.col-xl-8.col-lg-8.col-md-7.col-sm-12', m('span.m-origin', origin)),
+            m('.col-xxl-4.col-xl-4.col-lg-4.col-md-5.col-sm-12',
+              // remove
+              m('button.mdc-button mdc-button--raised m-button m-btn-remove', {
+                oncreate: oncreate.ripple,
+                onclick: events.origin.remove(origin)
+                },
+                'Remove'
               ),
               ),
-              m('i.material-icons', {
-                class: state.origins[origin].expanded ? 'icon-arrow-up' : 'icon-arrow-down'
-              })
-            ),
-            m('.m-content',
-              // match
-              m('.m-option m-match',
-                m('.m-name', m('span', 'match')),
-                m('.m-control',
-                  m('.mdc-text-field m-textfield', {
-                    oncreate: oncreate.textfield
-                    },
-                    m('input.mdc-text-field__input', {
-                      type: 'text',
-                      onkeyup: events.origin.match(origin),
-                      value: state.origins[origin].match,
-                    }),
-                    m('.mdc-line-ripple')
+              // refresh
+              (!state.permissions[origin] || null) &&
+              m('button.mdc-button mdc-button--raised m-button m-btn-refresh', {
+                oncreate: oncreate.ripple,
+                onclick: events.origin.refresh(origin)
+                },
+                'Refresh'
+              )
+            )
+          ),
+          // header detection
+          m('.row',
+            m('.col-sm-12',
+              m('.overflow',
+                m('label.mdc-switch m-switch', {
+                  onupdate: onupdate.header,
+                  title: 'Toggle Header Detection'
+                  },
+                  m('input.mdc-switch__native-control', {
+                    type: 'checkbox',
+                    checked: state.origins[origin].header,
+                    onchange: events.origin.header(origin)
+                  }),
+                  m('.mdc-switch__background', m('.mdc-switch__knob')),
+                  m('span.mdc-switch-label',
+                    'Content Type Detection: ',
+                    m('span', 'text/markdown'),
+                    ', ',
+                    m('span', 'text/x-markdown'),
+                    ', ',
+                    m('span', 'text/plain'),
                   )
                   )
-                )
-              ),
-              // csp
-              // (origin !== 'file://' || null) &&
-              // m('.m-option m-csp',
-              //   m('.m-name', m('span', 'csp')),
-              //   m('.m-control',
-              //     m('label.mdc-switch m-switch', {
-              //       onupdate: onupdate.csp(origin),
-              //       },
-              //       m('input.mdc-switch__native-control', {
-              //         type: 'checkbox',
-              //         checked: state.origins[origin].csp,
-              //         onchange: events.origin.csp(origin)
-              //       }),
-              //       m('.mdc-switch__background', m('.mdc-switch__knob')),
-              //       m('span.mdc-switch-label',
-              //         'Disable ',
-              //         m('code', 'Content Security Policy')
-              //       )
-              //     )
-              //   )
-              // ),
-              // encoding
-              // (origin !== 'file://' || null) &&
-              // m('.m-option m-encoding',
-              //   m('.m-name', m('span', 'encoding')),
-              //   m('.m-control',
-              //     m('select.mdc-elevation--z2 m-select', {
-              //       onchange: events.origin.encoding(origin),
-              //       },
-              //       m('option', {
-              //         value: '',
-              //         selected: state.origins[origin].encoding === ''
-              //         },
-              //         'auto'
-              //       ),
-              //       Object.keys(state.encodings).map((label) =>
-              //         m('optgroup', {label}, state.encodings[label].map((encoding) =>
-              //           m('option', {
-              //             value: encoding,
-              //             selected: state.origins[origin].encoding === encoding
-              //             },
-              //             encoding
-              //           )
-              //         ))
-              //       )
-              //     )
-              //   )
-              // ),
-              // refresh/remove
-              (origin !== 'file://' || null) &&
-              m('.m-footer',
-                m('span',
-                  (!state.permissions[origin] || null) &&
-                  m('button.mdc-button mdc-button--raised m-button', {
-                    oncreate: oncreate.ripple,
-                    onclick: events.origin.refresh(origin)
-                    },
-                    'Refresh'
-                  ),
-                  m('button.mdc-button mdc-button--raised m-button', {
-                    oncreate: oncreate.ripple,
-                    onclick: events.origin.remove(origin)
-                    },
-                    'Remove'
+                ),
+              )
+            )
+          ),
+          // path matching regexp
+          m('.row',
+            m('.col-sm-12',
+              m('.overflow',
+                m('label.mdc-switch m-switch', {
+                  onupdate: onupdate.path,
+                  title: 'Toggle Path Detection'
+                  },
+                  m('input.mdc-switch__native-control', {
+                    type: 'checkbox',
+                    checked: state.origins[origin].path,
+                    onchange: events.origin.path(origin)
+                  }),
+                  m('.mdc-switch__background', m('.mdc-switch__knob')),
+                  m('span.mdc-switch-label',
+                    'Path Matching RegExp: '
                   )
                   )
+                ),
+                m('.mdc-text-field m-textfield', {
+                  oncreate: oncreate.textfield
+                  },
+                  m('input.mdc-text-field__input', {
+                    type: 'text',
+                    onkeyup: events.origin.match(origin),
+                    value: state.origins[origin].match,
+                  }),
+                  m('.mdc-line-ripple')
                 )
                 )
               )
               )
             )
             )

+ 21 - 15
options/settings.js

@@ -36,21 +36,27 @@ var Settings = () => {
   }
   }
 
 
   var render = () =>
   var render = () =>
-    m('.bs-callout m-settings hidden',
-      m('h4.mdc-typography--headline5', 'Settings'),
-      m('.m-option m-icon',
-        m('.m-control',
-          m('label.mdc-switch m-switch', {
-            onupdate: onupdate.icon(),
-            },
-            m('input.mdc-switch__native-control', {
-              type: 'checkbox',
-              checked: state.icon,
-              onchange: events.icon()
-            }),
-            m('.mdc-switch__background', m('.mdc-switch__knob')),
-            m('span.mdc-switch-label',
-              m('code', 'Light Extension Icon for Dark Browser Theme')
+    m('.m-settings hidden',
+      m('.row',
+        m('h3', 'Settings')
+      ),
+      m('.bs-callout',
+        m('.row',
+          m('.col-sm-12',
+            m('.overflow',
+              m('label.mdc-switch m-switch', {
+                onupdate: onupdate.icon(),
+                },
+                m('input.mdc-switch__native-control', {
+                  type: 'checkbox',
+                  checked: state.icon,
+                  onchange: events.icon()
+                }),
+                m('.mdc-switch__background', m('.mdc-switch__knob')),
+                m('span.mdc-switch-label',
+                  'Light Extension Icon for Dark Browser Theme'
+                )
+              )
             )
             )
           )
           )
         )
         )