-
-
Save soundyogi/03df95505604c8351212 to your computer and use it in GitHub Desktop.
| void function() { "use strict" | |
| /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WIP DO NOT USE WIP !!!!!!!!!!!!!!!!!!!!! | |
| DO NOT USE THIS YET. | |
| USE THE 2016 VERSION BELOW PLEASE. | |
| WWWWWWWW WWWWWWWWIIIIIIIIIIPPPPPPPPPPPPPPPPP | |
| W::::::W W::::::WI::::::::IP::::::::::::::::P | |
| W::::::W W::::::WI::::::::IP::::::PPPPPP:::::P | |
| W::::::W W::::::WII::::::IIPP:::::P P:::::P | |
| W:::::W WWWWW W:::::W I::::I P::::P P:::::P | |
| W:::::W W:::::W W:::::W I::::I P::::P P:::::P | |
| W:::::W W:::::::W W:::::W I::::I P::::PPPPPP:::::P | |
| W:::::W W:::::::::W W:::::W I::::I P:::::::::::::PP | |
| W:::::W W:::::W:::::W W:::::W I::::I P::::PPPPPPPPP | |
| W:::::W W:::::W W:::::W W:::::W I::::I P::::P | |
| W:::::W:::::W W:::::W:::::W I::::I P::::P | |
| W:::::::::W W:::::::::W I::::I P::::P | |
| W:::::::W W:::::::W II::::::IIPP::::::PP | |
| W:::::W W:::::W I::::::::IP::::::::P | |
| W:::W W:::W I::::::::IP::::::::P | |
| WWW WWW IIIIIIIIIIPPPPPPPPPP | |
| * Manage and Import/Export Chrome Snippets (2018) | |
| * by: http://github.com/soundyogi | |
| * inspired by: https://github.com/bgrins/devtools-snippets/blob/master/import-export/chrome/devtools_import_export.js | |
| */ | |
| // - Templates | |
| // - Test Harness | |
| // - Diy Redux | |
| // - Main | |
| // - Util | |
| // - CSS | |
| // Templates | |
| // | |
| function Layout({getState}){ return ` | |
| <article> | |
| <header><h1>Chrome Export</h1></header> | |
| ${sideMenu({getState})} | |
| <main> | |
| <h2>Current snippets buffer / state / preview: </h2> | |
| ${getState().scriptSnippets.forEach((snippet) => { | |
| return ` | |
| <li>${snippet}</li> | |
| `})} | |
| </main> | |
| ${outMenu({getState})} | |
| <footer></footer> | |
| </article> | |
| `} | |
| function sideMenu({getState}) { return ` | |
| <aside> | |
| <nav> | |
| <h3>--> Input</h3> | |
| <ul> | |
| <li> | |
| <label> load chrome snippets: </label> | |
| <button id=${uuidv4()} onclick='dispatch(events.snippetsFetchRequested())'> (re)init </button> | |
| </li> | |
| <li> | |
| <label> on name conflicts: </label> | |
| <select onchange='( x => {console.log(x,event); dispatch(events.snippetsFetchRequested(event))} )()' id='rename'> | |
| <option value='true'>Rename Import Files</option> | |
| <option value="false">Overwrite Snippets</option> | |
| </select> | |
| </li> | |
| <li> | |
| <dropzone> | |
| <div>Click/Drop .js or .json</div> | |
| <input id="drop_files" type='file' multiple='true'/> | |
| </dropzone> | |
| <label>append files or replace everything? | |
| <select id='append'> | |
| <option value='true'>Append</option> | |
| <option value="false">Replace</option> | |
| </select> | |
| </label> | |
| </li> | |
| <li> | |
| import files from external sources: | |
| <button id="external_bgrins">load some scripts from bgrins/devtools-snippets repo</button> | |
| <button id="external_bahmutov">load some scripts from bahmutov/code-snippets repo</button> | |
| </li> | |
| </ul> | |
| </nav> | |
| </aside> | |
| `}; | |
| function outMenu({getState}){ return ` | |
| <out> | |
| <nav> | |
| <h3>Output --></h3> | |
| <ul> | |
| <li> | |
| <button id="export_snippets">export</button> | |
| <select id='format'> | |
| <option value="json">Single .json</option> | |
| <option value="js">Multiple .js</option> | |
| </select> | |
| </li> | |
| <li> | |
| <button id="save_snippets">Save to Chrome</button> | |
| </li> | |
| <li> | |
| <button id="reset_snippets">DELETE all on Chrome</button> | |
| </li> | |
| </ul> | |
| </nav> | |
| </out> | |
| `} | |
| // Test Harness | |
| // | |
| function log(...x) { | |
| return console.log(...x) | |
| } | |
| function test(suiteName, f) { | |
| log(`Test: ${suiteName}`) | |
| f({ok}) | |
| } | |
| function ok(expr, msg) { | |
| expr ? log(' %c!pass:' + msg, 'color:green') : log(' %c?fail:' + msg, 'color:red') | |
| } | |
| // INIT TEST | |
| test('selftest', function(t) { | |
| t.ok(true, ' I pass') | |
| t.ok(false, 'I fail') | |
| }) | |
| test("are we inspecting devtools?", ()=>{ | |
| if (location.origin !== "chrome-devtools://devtools") | |
| console.log("not in devtools of devtools / please inspect devtools again with: (ctrl+shift+i)") | |
| ok(location.origin === "chrome-devtools://devtools", 'we are in devtools of devtools, good to go') | |
| }) | |
| // Naive Redux | |
| // | |
| function createStore(rootReducer, initialState, storeEnhancer) { | |
| const createStore = storeEnhancer | |
| ? storeEnhancer(_createStore) | |
| : _createStore | |
| ; | |
| return createStore(); | |
| function _createStore() { | |
| if (!rootReducer) throw Error('rootReducer is missing') | |
| const _mapSubscribers = {} | |
| const _rootReducer = rootReducer | |
| const _store = { | |
| dispatch: baseDispatch, | |
| getState, | |
| subscribe | |
| } | |
| let _state = initialState | |
| return _store; | |
| function getState() { | |
| return _state | |
| } | |
| function subscribe(f) { | |
| _mapSubscribers[uuidv4()] = f | |
| } | |
| function baseDispatch(action) { | |
| if (!action || !action.type) throw Error("cant call dispatch without action. stupid."); | |
| _state = _rootReducer(_state, action) | |
| for (var subscriberKey in _mapSubscribers) | |
| _mapSubscribers[subscriberKey] ? _mapSubscribers[subscriberKey]() : null; | |
| return true; | |
| } | |
| } | |
| } | |
| function applyMiddleware(...middlewares) { | |
| return createStore => (...args) => { | |
| const store = createStore(...args) | |
| let chain = [] | |
| let dispatch | |
| const middlewareAPI = { | |
| getState: store.getState, | |
| dispatch: (...args) => dispatch(...args) | |
| } | |
| chain = middlewares.map(middleware => middleware(middlewareAPI)) | |
| dispatch = compose(...chain)(store.dispatch) | |
| return { | |
| ...store, | |
| dispatch | |
| } | |
| } | |
| } | |
| // Middleware | |
| // | |
| const logger = store => next => action => { | |
| if(!action.type && action instanceof Function) console.log('thunk: '+action.name) | |
| else { console.info('event: ', action) } | |
| let result = next(action) | |
| return result | |
| } | |
| const crashReporter = store => next => action => { | |
| try { | |
| return next(action) | |
| } catch (err) { | |
| console.error('Caught an exception!', err) | |
| throw err | |
| } | |
| } | |
| const vanillaPromise = store => next => action => { | |
| if (typeof action.then !== 'function') { | |
| return next(action) | |
| } | |
| return Promise.resolve(action).then(store.dispatch) | |
| } | |
| const thunk = store => next => action => | |
| typeof action === 'function' | |
| ? action(store.dispatch, store.getState) | |
| : next(action) | |
| /* | |
| function combineReducers(reducerObject:Object):function{} | |
| Combines Reducers by returning a Reducer Reducing Reducers | |
| */ | |
| function combineReducers(reducerObject){ | |
| function rootReducer(state, action){ | |
| const newState = {} | |
| Object.keys(reducerObject).reduce( (newState, currentKey) => { | |
| if(!state) state = {} | |
| // if(!state[currentKey]) state[currentKey] = undefined; | |
| newState[currentKey] = reducerObject[currentKey](state[currentKey], action) | |
| return newState | |
| }, newState) | |
| return newState | |
| } | |
| return rootReducer | |
| } | |
| // Snippets 'Duck' | |
| // | |
| // Actions | |
| // | |
| const SNIPPETS_FETCH_REQUESTED = 'SNIPPETS_FETCH_REQUESTED' | |
| const SNIPPETS_FETCHED = 'SNIPPETS_FETCHED' | |
| const SNIPPET_ADDED = 'SNIPPET_ADDED' | |
| const SNIPPET_REMOVED = 'SNIPPET_REMOVED' | |
| // Action Creators / Thunk Creators | |
| // | |
| function snippetsFetchRequested(){ | |
| return function snippetsFetchRequestedThunk(dispatch, getState){ | |
| dispatch({type: SNIPPETS_FETCH_REQUESTED}) | |
| InspectorFrontendHost.getPreferences(prefs=>{ | |
| const lastScriptSnippets = prefs.scriptSnippets | |
| const snippets = deserialize(lastScriptSnippets) | |
| const lastIdentifier = prefs.scriptSnippets_lastIdentifier | |
| dispatch(snippetsFetched({snippets, lastIdentifier})) | |
| }) | |
| } | |
| } | |
| function snippetsFetched(payload){ | |
| return {type: SNIPPETS_FETCHED, payload} | |
| } | |
| function snippetAdded(){} | |
| function snippetRemoved(){} | |
| const actionCreators = { | |
| snippetsFetchRequested, | |
| snippetsFetched, | |
| } | |
| function import_files(event){ | |
| if(!state.gui_switches.append) state.scriptSnippets = [] | |
| const files = event.target.files | |
| const stack = Object.keys(files) | |
| .forEach((key)=>{ | |
| const file = files[key] | |
| const reader = new FileReader() | |
| reader.fileName = file.name | |
| reader.onerror = (()=> {throw Error}) | |
| reader.onabort = (()=> {throw Error}) | |
| reader.onload = file_loaded | |
| reader.readAsText(file) | |
| }) | |
| function file_loaded(event){ | |
| const content_string = event.target.result | |
| const fileName = event.target.fileName | |
| const fileNameNoExt = /(.+?)(\.[^.]*$|$)/.exec(fileName)[1] | |
| const ext = /\.[0-9a-z]+$/.exec(fileName)[0] | |
| if(ext === ".json") return import_json(content_string) | |
| return add_snippet(fileNameNoExt, content_string) | |
| } | |
| } | |
| function import_json(content_string){ | |
| var json_data = deserialize(content_string) | |
| json_data.snippets.forEach(snippet => { | |
| add_snippet(snippet.name, snippet.content) | |
| }) | |
| } | |
| function set_pref(name, data_string){ | |
| InspectorFrontendHost.setPreference(name, data_string) | |
| } | |
| function save_snippets(){ | |
| set_pref( "scriptSnippets", serialize(state.scriptSnippets) ) | |
| set_pref( "scriptSnippets_lastIdentifier", state.lastIdentifier) | |
| prompt('restart chrome now!') | |
| } | |
| function reset_snippets(){ | |
| var choice = window.confirm("DELETE ALL SNIPPETS IN DEVTOOLS?") | |
| if(choice) clear_chrome_snippets() | |
| init() | |
| } | |
| function clear_chrome_snippets(){ | |
| set_pref("scriptSnippets", "[]") | |
| set_pref("scriptSnippets_lastIdentifier", "0") | |
| } | |
| function add_snippet(name, snippet_content_string){ | |
| if(is_duplicate(name, state.scriptSnippets)) { | |
| if(!state.gui_switches.rename) return state.scriptSnippets[name] = snippet_content_string | |
| return add_snippet(name+"copy", snippet_content_string) | |
| } | |
| const currentIdentifier = serialize(parseInt(state.lastIdentifier)+1) | |
| const new_snip = { | |
| content: snippet_content_string, | |
| id: currentIdentifier, | |
| name: name | |
| } | |
| state.scriptSnippets.push( new_snip ) | |
| state.lastIdentifier = currentIdentifier | |
| update() | |
| } | |
| function external_bgrins(){ | |
| const brings_snippets = [ | |
| 'allcolors', | |
| 'cachebuster', | |
| 'cssreload', | |
| 'cssprettifier', | |
| 'hashlink' | |
| ] | |
| brings_snippets.forEach((snippet)=>{ | |
| request('https://raw.githubusercontent.com/bgrins/devtools-snippets/master/snippets/'+snippet+'/'+snippet+'.js', function(request){ | |
| const snippet_content_string = request.target.response | |
| add_snippet(snippet, snippet_content_string) | |
| }) | |
| }) | |
| } | |
| function external_bahmutov(){ | |
| const bahmutov_snippets = [ | |
| 'timing', | |
| 'profile-method-call', | |
| 'time-method-call' | |
| ] | |
| bahmutov_snippets.forEach((snippet)=>{ | |
| request('https://raw.githubusercontent.com/bahmutov/code-snippets/master/'+snippet+'.js', function(request){ | |
| const snippet_content_string = request.target.response | |
| add_snippet(snippet, snippet_content_string) | |
| }) | |
| }) | |
| } | |
| function export_snippets(){ | |
| if(state.gui_switches.format === "json") return download_json() | |
| return download_js() | |
| } | |
| function download_js(){ | |
| state.scriptSnippets.forEach((snippet)=>{ | |
| download(snippet.name+'.js', snippet.content) | |
| }) | |
| } | |
| function download_json(){ | |
| console.log("json") | |
| const fileName = serialize(Date()) | |
| const json_data = serialize({'snippets': state.scriptSnippets}, ['snippets', 'name', 'content'], 2) | |
| download(fileName+".json", json_data) | |
| } | |
| // Reducer | |
| // | |
| const snippetsShape = { | |
| scriptSnippets: [], | |
| lastIdentifier: 0, | |
| //ui | |
| rename: true, | |
| format: 'json', | |
| review: false, | |
| append: true | |
| } | |
| function snippetsReducer(state = snippetsShape, {TYPE, PL}) { | |
| if(TYPE === SNIPPETS_FETCHED) return {...state, scriptSnippets: PL.snippets} | |
| return state | |
| } | |
| // Main logic | |
| // | |
| const app_window = createWindow("menubar=false, width=1024, height=768", "Chrome Snippets Import/Export/Manager") | |
| const store = createStore(snippetsReducer, undefined, applyMiddleware(logger,thunk,vanillaPromise,crashReporter)) | |
| app_window.dispatch = store.dispatch | |
| app_window.getState = store.getState | |
| app_window.events = actionCreators | |
| app_window.document.head.innerHTML = style(); | |
| store.subscribe(function(){ | |
| // console.log(JSON.stringify(store.getState())) | |
| render(app_window.document.body, Layout) | |
| }) | |
| store.dispatch({type: 'first', payload: Date.now()}) | |
| // UTIL | |
| // | |
| function render(mountNode, template){ | |
| mountNode.innerHTML = template({getState: store.getState}); | |
| } | |
| function compose(...funcs) { | |
| if (funcs.length === 0) { | |
| return arg => arg | |
| } | |
| if (funcs.length === 1) { | |
| return funcs[0] | |
| } | |
| return funcs.reduce((a, b) => (...args) => a(b(...args))) | |
| } | |
| function uuidv4() { | |
| // RFC4122 version 4 compliant | |
| return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { | |
| var r = Math.random() * 16 | 0 | |
| , v = c == 'x' ? r : (r & 0x3 | 0x8); | |
| return v.toString(16); | |
| }); | |
| } | |
| function request(url, success) { | |
| var xhr = new XMLHttpRequest(); | |
| xhr.open('GET', url); | |
| xhr.onload = success; | |
| xhr.send(); | |
| return xhr; | |
| } | |
| function serialize(object, ...rest) { | |
| if (!object) throw Error("serialize needs input") | |
| return JSON.stringify(object, ...rest) | |
| } | |
| function deserialize(string) { | |
| if (typeof string !== "string") throw Error("deserialize needs a string") | |
| if (string === "") throw Error("no snippets present") | |
| return JSON.parse(string) | |
| } | |
| function download(name, data) { | |
| const Blob = new window.Blob([data],{ 'type': 'text/utf-8' }) | |
| const a = app_window.document.createElement('a') | |
| a.href = URL.createObjectURL(Blob) | |
| a.download = name | |
| a.click() | |
| } | |
| function is_duplicate(name, snippets_arr) { | |
| const result = snippets_arr.filter(function(snippet) { | |
| return snippet.name === name | |
| }) | |
| if (result.length === 0) return false | |
| return true | |
| } | |
| function createWindow(options, title) { | |
| const w = window.open("", "", options) | |
| w.document.title = title | |
| return w | |
| } | |
| // CSS | |
| // | |
| function style() { return ` | |
| <style> | |
| body { | |
| font-family: 'Open Sans', sans-serif; | |
| } | |
| article { | |
| display: grid; | |
| grid-template-columns: auto minmax(min-content, 1fr); | |
| grid-template-rows: auto minmax(min-content, 1fr) auto; | |
| max-width: 800px; | |
| margin: 0 auto; | |
| } | |
| header { | |
| grid-column: 1 / span 3; | |
| grid-row: 1; | |
| } | |
| aside { | |
| grid-column: 1; | |
| grid-row: 2; | |
| background-color: #F0F0F2; | |
| padding: 5px 10px; | |
| } | |
| out { | |
| grid-column: 3; | |
| grid-row: 2; | |
| background-color: #F0F0F2; | |
| padding: 5px 10px; | |
| } | |
| main { | |
| grid-column: 2; | |
| grid-row: 2; | |
| align-self: start; | |
| margin-left: 18px; | |
| } | |
| footer { | |
| grid-column: 1 / span 2; | |
| grid-row: 3; | |
| background-color: #474F59; | |
| margin-top: 20px; | |
| padding: 5px 10px; | |
| color: white; | |
| margin-bottom: 20px; | |
| } | |
| #drop_files { | |
| opacity: 0; | |
| width: 100%; | |
| height: 20vh; | |
| } | |
| dropzone { | |
| cursor: pointer; | |
| border: 1px black dotted; | |
| font-weight: bold; | |
| font-size: 1em; | |
| text-align: center; | |
| } | |
| </style> | |
| ` | |
| } | |
| }("live long and prosper"); |
| void function(){ | |
| "use strict" | |
| /* | |
| 222222222222222 000000000 1111111 66666666 | |
| 2:::::::::::::::22 00:::::::::00 1::::::1 6::::::6 | |
| 2::::::222222:::::2 00:::::::::::::00 1:::::::1 6::::::6 | |
| 2222222 2:::::2 0:::::::000:::::::0111:::::1 6::::::6 | |
| 2:::::2 0::::::0 0::::::0 1::::1 6::::::6 | |
| 2:::::2 0:::::0 0:::::0 1::::1 6::::::6 | |
| 2222::::2 0:::::0 0:::::0 1::::1 6::::::6 | |
| 22222::::::22 0:::::0 000 0:::::0 1::::l 6::::::::66666 | |
| 22::::::::222 0:::::0 000 0:::::0 1::::l 6::::::::::::::66 | |
| 2:::::22222 0:::::0 0:::::0 1::::l 6::::::66666:::::6 | |
| 2:::::2 0:::::0 0:::::0 1::::l 6:::::6 6:::::6 | |
| 2:::::2 0::::::0 0::::::0 1::::l 6:::::6 6:::::6 | |
| 2:::::2 2222220:::::::000:::::::0111::::::1116::::::66666::::::6 | |
| 2::::::2222222:::::2 00:::::::::::::00 1::::::::::1 66:::::::::::::66 | |
| 2::::::::::::::::::2 00:::::::::00 1::::::::::1 66:::::::::66 | |
| 22222222222222222222 000000000 111111111111 666666666 | |
| * Manage and Import / Export snippets from chrome (2016) | |
| * hacked together by: http://github.com/soundyogi | |
| * inspired by: https://github.com/bgrins/devtools-snippets/blob/master/import-export/chrome/devtools_import_export.js | |
| * ALPHA / SILLY SIDE PROJECT | |
| */ | |
| let_us("execute some init tests", () => { | |
| if(location.origin !== "chrome-devtools://devtools") throw Error("not in devtools of devtools / please inspect devtools again (ctrl+shift+i)") | |
| ok(location.origin === "chrome-devtools://devtools", 'we are in devtools of devtools, good to go') | |
| }) | |
| const state = { | |
| scriptSnippets: [], | |
| } | |
| window.state = state | |
| const style = ` | |
| <style> | |
| body{ | |
| margin: 0; | |
| padding: 0; | |
| } | |
| grid { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| -webkit-flex-flow: column; | |
| } | |
| column { | |
| display: flex; | |
| -webkit-flex-flow: column; | |
| width: 30vw; | |
| } | |
| row { | |
| display: flex; | |
| -webkit-flex-flow: row; | |
| width: 90vw; | |
| margin-bottom: 2vh; | |
| } | |
| item { | |
| background: tomato; | |
| min-height: 13vh; | |
| color: white; | |
| font-weight: bold; | |
| font-size: 1.5em; | |
| text-align: center; | |
| padding: 20px; | |
| } | |
| #drop_files { | |
| opacity: 0; | |
| width: 100%; | |
| height: 20vh; | |
| } | |
| dropzone { | |
| cursor: pointer; | |
| border: 1px black dotted; | |
| font-weight: bold; | |
| font-size: 1em; | |
| text-align: center; | |
| } | |
| </style> | |
| ` | |
| const markup = ` | |
| <grid> | |
| <row> | |
| <column> | |
| <item> load chrome snippets: | |
| <button id="init">(re)init</button> | |
| </item> | |
| </column> | |
| <column> | |
| <item> | |
| <label>on name conflicts: | |
| <select id='rename'> | |
| <option value='true'>Rename Import Files</option> | |
| <option value="false">Overwrite Snippets</option> | |
| </select> | |
| </label> | |
| </item> | |
| </column> | |
| <column> | |
| <item> | |
| <button id="export_snippets">export</button> | |
| <select id='format'> | |
| <option value="json">Single .json</option> | |
| <option value="js">Multiple .js</option> | |
| </select> | |
| </item> | |
| </column> | |
| <column> | |
| <item> | |
| <button id="save_snippets">Save to Chrome</button> | |
| </item> | |
| </column> | |
| <column> | |
| <item> | |
| <button id="reset_snippets">DELETE all on Chrome</button> | |
| </item> | |
| </column> | |
| </row> | |
| <row> | |
| <column> | |
| <dropzone> | |
| <div>Click/Drop .js or .json</div> | |
| <input id="drop_files" type='file' multiple='true'/> | |
| </dropzone> | |
| <label>append files or replace everything? | |
| <select id='append'> | |
| <option value='true'>Append</option> | |
| <option value="false">Replace</option> | |
| </select> | |
| </label> | |
| </column> | |
| <column>===== snippets preview =====<ul id="state.scriptSnippets"></ul></column> | |
| <column>import files from external sources: | |
| <button id="external_bgrins">load some scripts from bgrins/devtools-snippets repo</button> | |
| <button id="external_bahmutov">load some scripts from bahmutov/code-snippets repo</button> | |
| </column> | |
| </row> | |
| </grid> | |
| ` | |
| /* Main logic | |
| */ | |
| const app_window = create_window("menubar=false, height=700, width=1000", "chrome snippets import/export - ALPHA USE AT OWN RISK") | |
| const document = app_window.document | |
| let_us("bootstrap the whole thing", () => { | |
| init() | |
| }) | |
| function init(){ | |
| setupGUI() | |
| state.scriptSnippets = [] | |
| state.lastIdentifier = 0 | |
| state.gui_switches = { | |
| rename: true, | |
| format: "json", | |
| review: false, | |
| append: true | |
| } | |
| InspectorFrontendHost.getPreferences( prefs => { | |
| const lastScriptSnippets = prefs.scriptSnippets | |
| state.scriptSnippets = deserialize(lastScriptSnippets) | |
| state.lastIdentifier = prefs.scriptSnippets_lastIdentifier | |
| update() | |
| }) | |
| } | |
| function setupGUI(){ | |
| app_window.document.body.innerHTML = style+markup | |
| getID("format").on("change", handle_gui_switches) | |
| getID("rename").on("change", handle_gui_switches) | |
| getID("append").on("change", handle_gui_switches) | |
| getID("drop_files").on("change", import_files) | |
| getID("export_snippets").on("click", export_snippets) | |
| getID("init").on("click", init) | |
| getID("save_snippets").on("click", save_snippets) | |
| getID("reset_snippets").on("click", reset_snippets) | |
| getID("external_bgrins").on("click", external_bgrins) | |
| getID("external_bahmutov").on("click", external_bahmutov) | |
| } | |
| function handle_gui_switches(ev){ | |
| const target = ev.target | |
| const opt = state.gui_switches | |
| if(target.id === 'format') { | |
| opt.format = target.value | |
| return update() | |
| } | |
| if(target.id === 'rename') { | |
| opt.rename = !target.value | |
| return update() | |
| } | |
| if(target.id === 'review') { | |
| opt.review = !opt.review | |
| return update() | |
| } | |
| if(target.id === 'append') { | |
| opt.append = !target.value | |
| return update() | |
| } | |
| } | |
| function update(){ | |
| render_list() | |
| console.log(state.gui_switches) | |
| } | |
| function render_list(){ | |
| const ul = app_window.document.getElementById("state.scriptSnippets") | |
| ul.innerHTML = '' | |
| state.scriptSnippets.forEach((snippet)=>{ | |
| const li = document.createElement('li') | |
| //const a = document.createElement('a') | |
| //a.href = snippet.name | |
| li.innerHTML = snippet.name | |
| //li.appendChild(a) | |
| ul.appendChild(li) | |
| }) | |
| } | |
| /* Helpers | |
| */ | |
| function import_files(event){ | |
| if(!state.gui_switches.append) state.scriptSnippets = [] | |
| const files = event.target.files | |
| const stack = Object.keys(files) | |
| .forEach((key)=>{ | |
| const file = files[key] | |
| const reader = new FileReader() | |
| reader.fileName = file.name | |
| reader.onerror = (()=> {throw Error}) | |
| reader.onabort = (()=> {throw Error}) | |
| reader.onload = file_loaded | |
| reader.readAsText(file) | |
| }) | |
| } | |
| function file_loaded(event){ | |
| const content_string = event.target.result | |
| const fileName = event.target.fileName | |
| const fileNameNoExt = /(.+?)(\.[^.]*$|$)/.exec(fileName)[1] | |
| const ext = /\.[0-9a-z]+$/.exec(fileName)[0] | |
| if(ext === ".json") return import_json(content_string) | |
| return add_snippet(fileNameNoExt, content_string) | |
| } | |
| function import_json(content_string){ | |
| var json_data = deserialize(content_string) | |
| json_data.snippets.forEach(snippet => { | |
| add_snippet(snippet.name, snippet.content) | |
| }) | |
| } | |
| function set_pref(name, data_string){ | |
| InspectorFrontendHost.setPreference(name, data_string) | |
| } | |
| function save_snippets(){ | |
| set_pref( "scriptSnippets", serialize(state.scriptSnippets) ) | |
| set_pref( "scriptSnippets_lastIdentifier", state.lastIdentifier) | |
| prompt('restart chrome now!') | |
| } | |
| function reset_snippets(){ | |
| var choice = window.confirm("DELETE ALL SNIPPETS IN DEVTOOLS?") | |
| if(choice) clear_chrome_snippets() | |
| init() | |
| } | |
| function clear_chrome_snippets(){ | |
| set_pref("scriptSnippets", "[]") | |
| set_pref("scriptSnippets_lastIdentifier", "0") | |
| } | |
| function add_snippet(name, snippet_content_string){ | |
| if(is_duplicate(name, state.scriptSnippets)) { | |
| if(!state.gui_switches.rename) return state.scriptSnippets[name] = snippet_content_string | |
| return add_snippet(name+"copy", snippet_content_string) | |
| } | |
| const currentIdentifier = serialize(parseInt(state.lastIdentifier)+1) | |
| const new_snip = { | |
| content: snippet_content_string, | |
| id: currentIdentifier, | |
| name: name | |
| } | |
| state.scriptSnippets.push( new_snip ) | |
| state.lastIdentifier = currentIdentifier | |
| update() | |
| } | |
| function external_bgrins(){ | |
| const brings_snippets = [ | |
| 'allcolors', | |
| 'cachebuster', | |
| 'cssreload', | |
| 'cssprettifier', | |
| 'hashlink' | |
| ] | |
| brings_snippets.forEach((snippet)=>{ | |
| request('https://raw.githubusercontent.com/bgrins/devtools-snippets/master/snippets/'+snippet+'/'+snippet+'.js', function(request){ | |
| const snippet_content_string = request.target.response | |
| add_snippet(snippet, snippet_content_string) | |
| }) | |
| }) | |
| } | |
| function external_bahmutov(){ | |
| const bahmutov_snippets = [ | |
| 'timing', | |
| 'profile-method-call', | |
| 'time-method-call' | |
| ] | |
| bahmutov_snippets.forEach((snippet)=>{ | |
| request('https://raw.githubusercontent.com/bahmutov/code-snippets/master/'+snippet+'.js', function(request){ | |
| const snippet_content_string = request.target.response | |
| add_snippet(snippet, snippet_content_string) | |
| }) | |
| }) | |
| } | |
| function export_snippets(){ | |
| if(state.gui_switches.format === "json") return download_json() | |
| return download_js() | |
| } | |
| function download_js(){ | |
| state.scriptSnippets.forEach((snippet)=>{ | |
| download(snippet.name+'.js', snippet.content) | |
| }) | |
| } | |
| function download_json(){ | |
| console.log("json") | |
| const fileName = serialize(Date()) | |
| const json_data = serialize({'snippets': state.scriptSnippets}, ['snippets', 'name', 'content'], 2) | |
| download(fileName+".json", json_data) | |
| } | |
| /* util & shorthand | |
| */ | |
| function request(url, success) { | |
| var xhr = new XMLHttpRequest(); | |
| xhr.open('GET', url); | |
| xhr.onload = success; | |
| xhr.send(); | |
| return xhr; | |
| } | |
| function getID(id){ | |
| const element = app_window.document.getElementById(id) | |
| element.on = function on(event_name, fn){ | |
| this.addEventListener(event_name, fn) | |
| return this | |
| } | |
| return element | |
| } | |
| function serialize(object, ...rest){ | |
| if(!object) throw Error("serialize needs an object") | |
| return JSON.stringify(object, ...rest) | |
| } | |
| function deserialize(string){ | |
| if(typeof string !== "string") throw Error("deserialize needs a string") | |
| if(string === "") throw Error("no snippets present") | |
| return JSON.parse(string) | |
| } | |
| function download(name, data){ | |
| const Blob = new window.Blob([data],{ | |
| 'type': 'text/utf-8' | |
| }) | |
| const a = document.createElement('a') | |
| a.href = URL.createObjectURL(Blob) | |
| a.download = name | |
| a.click() | |
| } | |
| function is_duplicate(name, snippets_arr){ | |
| const result = snippets_arr.filter(function(snippet){ | |
| return snippet.name === name | |
| }) | |
| if(result.length === 0) return false | |
| return true | |
| } | |
| function create_window(options, title){ | |
| const w = window.open("", "", options) | |
| w.document.title = title | |
| return w | |
| } | |
| /* | |
| * UNIT TESTS | |
| */ | |
| let_us("write some tests", ()=>{ | |
| // TODO | |
| // TDD tests are deleted now / remove harness | |
| }) | |
| /* Nanoharness | |
| */ | |
| function let_us(msg,f){ | |
| console.log("we_will: "+msg) | |
| try { f() } | |
| catch (exception) { | |
| console.warn(exception.stack.replace(/:(\d+):(\d+)/g, "$& (Line $1, Column $2)")) | |
| } | |
| } | |
| function ok(expr, msg){ | |
| log(expr, msg) | |
| } | |
| function log(expr, msg){ | |
| expr ? console.log("!pass "+msg) : console.log("?fail "+msg) | |
| } | |
| function html_log(){ | |
| const queue = [] | |
| return function log(expr, msg) { | |
| queue.push( expr ? `!pass ${msg}` : `?fail ${msg}` ) | |
| } | |
| } | |
| }("goodbye and thanks for all the fish") |
Great work 👍
👍
thanks, now I hopefully have the motivation to finish it and make it a "full" snippets manager.
Id love to store them somewhere online instead of .json, I still keep losing scripts.
And more than 50+ Scripts are very unmanagable still right now.
This is awesome, thank you 👏
the new version is still in progress, please use the 2016 one until it is finished.
2016 is no more working :'(
Really? Oh no :O !!!
Let me get back to you soon...
Using version 2016, try changing function create_window to the following:
function create_window(options, title){
var id = (new Date()).getTime();
const w = window.open('' , id, options);
w.document.title = title
return w
}I hope this helps.
2016 is no more working :'(
Did you inpect the inpector window?
You have to open inspector: ctrl+shift+i
Then undock it in a single window
Then again: ctrl+shift+i
Now paste the manager, does it work?
I will try to finish the new one soon
Thanks a lot, great work
Great work
Open Inspector (ctrl+shift+I)
Undock Inspector in Seperate Window
Inspect Inspector (ctrl+shift+i)
Paste Script Into Console: