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 `

Chrome Export

${sideMenu({getState})}

Current snippets buffer / state / preview:

${getState().scriptSnippets.forEach((snippet) => { return `
  • ${snippet}
  • `})}
    ${outMenu({getState})}
    `} function sideMenu({getState}) { return ` `}; function outMenu({getState}){ return ` `} // 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 ` ` } }("live long and prosper");