Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

80 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Fancy Settings 1.2

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Rationale

The goal of this project is to provide a simple way to generate native-chrome-like settings pages for use in projects like chrome extensions. Settings are defined entirely using a javascript object, the "manifest," and event binding can be easily customized via javascript.

Ideally, this framework contains enough variety of setting types that one need only to edit the "Manifest" (/source/manifest.js) and the settings initialization script (/source/settings.js) to populate the settings page with the right controls.

How It Works

Project Structure

├── css ─────────────────────────├─( framework css; if you're extending the framework you should add to these )
│ ├── main.css ────────────────├─( main layout )
│ └── setting.css ─────────────├─( styles for each "setting" [ListBox, Button, etc.] )
├── custom.css ──────────────────├─( your css should go here, probably overriding default styles )
├── i18n.js ─────────────────────├─( your internationalization data )
├── icon.png ────────────────────├─( favicon shown on the settings tab in chrome )
├── index.html ──────────────────├─( index page; loads all javascript and establishes main layout )
├── js ──────────────────────────├─( framework javascript; if you're extending the framework you should add to these )
│ ├── classes ─────────────────├─( mootools-backed framework classes )
│ │ ├── fancy-settings.js ├─( main entry point; contains `FancySettings.initWithManifest` function, used to │ │ │ │ build all settings and add them to the DOM )
│ │ ├── search.js ───────────├─( provides management interface for the search index )
│ │ ├── setting.js ──────────├─( classes for all setting types (e.g. ListBox, Button, etc.) and the Setting class
│ │ │ │ itself; includes DOM creation and event logic )
│ │ └── tab.js ──────────────├─( class for `Tab`; includes DOM creation and tab switching )
│ └── i18n.js ─────────────────├─( internationalization interface; retrieves i18n values registered in `/source/i18n.js` )
├── lib ─────────────────────────├─( dependencies
│ ├── default.css ─────────────├─( base css for elements and utility classes )
│ ├── mootools-core.js ────────├─( mootools )
│ └── store.js ────────────────├─( localStorage interface )
├── manifest.js ─────────────────├─( your settings manifest; see [The "Manifest"](#the--manifest)
└── settings.js ─────────────────└─( your settings pre-initialization; `FancySettings.initWithManifest` is called here after any prerequisite async event (e.g. domready, retrieving values from `chrome.storage`, etc.); see [Settings Initialization](#settings-initialization) )

The "Manifest"

The "Manifest" (/source/manifest.js) is a simple javascript file which registers a global object: manifest. This object contains the following properties:

  • name: Name of the manifest

  • icon: Filename of the favicon to show for the options tab in chrome

  • alignment(optional): WIP - not sure how to explain this yet

  • settings:

    An array containing a "flattened" list of settings. Each element in this array describes one setting. All setting objects, regardless of type, have the following properties:

    • tab: The name (and text) of the tab where the setting will be shown; settings with the same tab value will be rendered on the same tab
    • name: The name of this setting; this name will be used to reference it later via javascript, usually as the key of an object
    • type: The type of setting, see setting types below
    • label(optional): The text of a <label> element which will be rendered before the setting element
    • group(optional): The name (and text) of the group (a section within a tab) where the setting will be shown; settings with the same group value will be rendered in the same group

Events

(WIP)

Setting Types

TypeDescriptionAdditional PropertiesEvents
descriptionrenders a <p> element containing a block of text
  • text: the text content of the <p> element
buttonrenders a <button> element
  • text: the text of the <button> element
  • action: fires on button click
textrenders an <input> element with a type attribute of either text (default) or password
  • text: the value of the placeholder attribute of the <input> element
  • masked: a boolean property; if true, sets the type attribute of the <input> element to password
textarearenders an <input type='textarea'> element
  • text: not sure what this does yet
  • value: not sure what this does yet
action: fires on textarea change & keyup
checkboxrenders an <input type='checkbox'> elementHINT: use label with this setting type
  • action: fires on checkbox change
sliderrenders an <input type='range'> element
  • min: sets the min attribute
  • max: sets the max attribute
  • step: sets the step attribute
  • display: a boolean property; if true (default), renders the current value of the slider beside it (unless modified by displayModifier)
  • displayModifier: a function which receives the value of the range and whose return value is rendered beside the range if display is true
  • action: fires on range change
popupButtona bit of a misnomer; render's a <select> element with <option> childred corresponding to the options array
  • options: an object with groups and values properties
    • groups: an array of strings; each renders an <optgroup> element whose label attribute is the value of the string
    • values: array of objects which correspond to the <option> elements to go inside the <optgroup>s; each object should have a text property which renders as the text node inside of the <option>, a value property which is the value of the value attribute on the <option> element, and a group property which detmines which <optgroup> a given <option> is placed
action: fires on select change
listboxrenders a <select> element in listBox mode with <option> elements corresponding to the options array
  • multiple: adds the multiple attribute, allowing for multiple options to be selected simultaneously
  • options: an array of objects which correspond to the <option> elements to go inside the <select>; each object should have a text property which renders as the text node inside of the <option> and a value property which is the value of the value attribute on the <option> element<\li><\ul>
  • action: fires on select change
radioButtonsrenders a set of <input type='radio'> elements corresponding to the options array
  • options: an array of objects which correspond to the <input type='radio'>; each object should have a text property which renders as the text node inside of the <input type='radio'> and a value property which is the value of the value attribute on the <input type='radio'> element
  • action: fires on select change
modalButtonrenders a button which, when clicked, opens a modal over the current settings tab, containing nested settings
  • text: the text of the <button> element
  • modal: an object with title and contents properties
    • title: the text which is rendered in an <h2> at the top of the modal
    • contents: an array of nested settings which will be rendered inside the modal
  • action: fires on button click
  • modal_done: fires on "done" button click (inside modal)
fileButtonWIP

Settings Initialization

(WIP)

Using Settings Values

All values in the settings page are automatically persisted via localStorage objects with the prefix of store.settings. (e.g. store.settings.myButton). You can retrieve the values via javascript, operate on them and ultimately store your chrome extension settings via chrome.storage for use in your extension.

In the sample code of this repo, this logic resides in the settings file as well but could just as easily be factored out.

How To Use (WIP)

  1. npm i --save or something...
  2. add things to your build process...
  3. customize manifest.js
  4. customize settings.js
  5. ...

About

Create fancy, chrome-look-alike settings for your Chrome or Safari extension in minutes!

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages