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 `
${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");