|
import Tool from '../DevTools/Tool' |
|
import Settings from '../Settings/Settings' |
|
import $ from 'licia/$' |
|
import escape from 'licia/escape' |
|
import isEmpty from 'licia/isEmpty' |
|
import contain from 'licia/contain' |
|
import unique from 'licia/unique' |
|
import each from 'licia/each' |
|
import sameOrigin from 'licia/sameOrigin' |
|
import ajax from 'licia/ajax' |
|
import MutationObserver from 'licia/MutationObserver' |
|
import toArr from 'licia/toArr' |
|
import concat from 'licia/concat' |
|
import map from 'licia/map' |
|
import { isErudaEl, classPrefix as c } from '../lib/util' |
|
import evalCss from '../lib/evalCss' |
|
import Storage from './Storage' |
|
import Cookie from './Cookie' |
|
import { setState, getState } from './util' |
|
|
|
export default class Resources extends Tool { |
|
constructor() { |
|
super() |
|
|
|
this._style = evalCss(require('./Resources.scss')) |
|
|
|
this.name = 'resources' |
|
this.displayName = 'リソース' |
|
this._hideErudaSetting = false |
|
this._observeElement = true |
|
} |
|
init($el, container) { |
|
super.init($el) |
|
|
|
this._container = container |
|
|
|
this._initTpl() |
|
this._localStorage = new Storage( |
|
this._$localStorage, |
|
container, |
|
this, |
|
'local' |
|
) |
|
this._sessionStorage = new Storage( |
|
this._$sessionStorage, |
|
container, |
|
this, |
|
'session' |
|
) |
|
this._cookie = new Cookie(this._$cookie, container) |
|
|
|
this._bindEvent() |
|
this._initObserver() |
|
this._initCfg() |
|
} |
|
refresh() { |
|
return this.refreshLocalStorage() |
|
.refreshSessionStorage() |
|
.refreshCookie() |
|
.refreshScript() |
|
.refreshStylesheet() |
|
.refreshIframe() |
|
.refreshImage() |
|
} |
|
destroy() { |
|
super.destroy() |
|
|
|
this._localStorage.destroy() |
|
this._sessionStorage.destroy() |
|
this._disableObserver() |
|
evalCss.remove(this._style) |
|
this._rmCfg() |
|
} |
|
refreshScript() { |
|
let scriptData = [] |
|
|
|
$('script').each(function () { |
|
const src = this.src |
|
|
|
if (src !== '') scriptData.push(src) |
|
}) |
|
|
|
scriptData = unique(scriptData) |
|
|
|
const scriptState = getState('script', scriptData.length) |
|
let scriptDataHtml = '<li>なし</li>' |
|
if (!isEmpty(scriptData)) { |
|
scriptDataHtml = map(scriptData, (script) => { |
|
script = escape(script) |
|
return `<li><a href="${script}" target="_blank" class="${c( |
|
'js-link' |
|
)}">${script}</a></li>` |
|
}).join('') |
|
} |
|
|
|
const scriptHtml = `<h2 class="${c('title')}"> |
|
スクリプト |
|
<div class="${c('btn refresh-script')}"> |
|
<span class="${c('icon-refresh')}"></span> |
|
</div> |
|
</h2> |
|
<ul class="${c('link-list')}"> |
|
${scriptDataHtml} |
|
</ul>` |
|
|
|
const $script = this._$script |
|
setState($script, scriptState) |
|
$script.html(scriptHtml) |
|
|
|
return this |
|
} |
|
refreshStylesheet() { |
|
let stylesheetData = [] |
|
|
|
$('link').each(function () { |
|
if (this.rel !== 'stylesheet') return |
|
|
|
stylesheetData.push(this.href) |
|
}) |
|
|
|
stylesheetData = unique(stylesheetData) |
|
|
|
const stylesheetState = getState('stylesheet', stylesheetData.length) |
|
let stylesheetDataHtml = '<li>なし</li>' |
|
if (!isEmpty(stylesheetData)) { |
|
stylesheetDataHtml = map(stylesheetData, (stylesheet) => { |
|
stylesheet = escape(stylesheet) |
|
return ` <li><a href="${stylesheet}" target="_blank" class="${c( |
|
'css-link' |
|
)}">${stylesheet}</a></li>` |
|
}).join('') |
|
} |
|
|
|
const stylesheetHtml = `<h2 class="${c('title')}"> |
|
スタイルシート |
|
<div class="${c('btn refresh-stylesheet')}"> |
|
<span class="${c('icon-refresh')}"></span> |
|
</div> |
|
</h2> |
|
<ul class="${c('link-list')}"> |
|
${stylesheetDataHtml} |
|
</ul>` |
|
|
|
const $stylesheet = this._$stylesheet |
|
setState($stylesheet, stylesheetState) |
|
$stylesheet.html(stylesheetHtml) |
|
|
|
return this |
|
} |
|
refreshIframe() { |
|
let iframeData = [] |
|
|
|
$('iframe').each(function () { |
|
const $this = $(this) |
|
const src = $this.attr('src') |
|
|
|
if (src) iframeData.push(src) |
|
}) |
|
|
|
iframeData = unique(iframeData) |
|
|
|
let iframeDataHtml = '<li>なし</li>' |
|
if (!isEmpty(iframeData)) { |
|
iframeDataHtml = map(iframeData, (iframe) => { |
|
iframe = escape(iframe) |
|
return `<li><a href="${iframe}" target="_blank" class="${c( |
|
'iframe-link' |
|
)}">${iframe}</a></li>` |
|
}).join('') |
|
} |
|
const iframeHtml = `<h2 class="${c('title')}"> |
|
Iframe |
|
<div class="${c('btn refresh-iframe')}"> |
|
<span class="${c('icon-refresh')}"></span> |
|
</div> |
|
</h2> |
|
<ul class="${c('link-list')}"> |
|
${iframeDataHtml} |
|
</ul>` |
|
|
|
this._$iframe.html(iframeHtml) |
|
|
|
return this |
|
} |
|
refreshLocalStorage() { |
|
this._localStorage.refresh() |
|
|
|
return this |
|
} |
|
refreshSessionStorage() { |
|
this._sessionStorage.refresh() |
|
|
|
return this |
|
} |
|
refreshCookie() { |
|
this._cookie.refresh() |
|
|
|
return this |
|
} |
|
refreshImage() { |
|
let imageData = [] |
|
|
|
const performance = (this._performance = |
|
window.webkitPerformance || window.performance) |
|
if (performance && performance.getEntries) { |
|
const entries = this._performance.getEntries() |
|
entries.forEach((entry) => { |
|
if (entry.initiatorType === 'img' || isImg(entry.name)) { |
|
if (contain(entry.name, 'exclude=true')) { |
|
return |
|
} |
|
imageData.push(entry.name) |
|
} |
|
}) |
|
} else { |
|
$('img').each(function () { |
|
const $this = $(this) |
|
const src = $this.attr('src') |
|
|
|
if ($this.data('exclude') === 'true') { |
|
return |
|
} |
|
|
|
imageData.push(src) |
|
}) |
|
} |
|
|
|
imageData = unique(imageData) |
|
imageData.sort() |
|
|
|
const imageState = getState('image', imageData.length) |
|
let imageDataHtml = '<li>なし</li>' |
|
if (!isEmpty(imageData)) { |
|
|
|
imageDataHtml = map(imageData, (image) => { |
|
return `<li class="${c('image')}"> |
|
<img src="${escape(image)}" data-exclude="true" class="${c('img-link')}"/> |
|
</li>` |
|
}).join('') |
|
} |
|
|
|
const imageHtml = `<h2 class="${c('title')}"> |
|
画像 |
|
<div class="${c('btn refresh-image')}"> |
|
<span class="${c('icon-refresh')}"></span> |
|
</div> |
|
</h2> |
|
<ul class="${c('image-list')}"> |
|
${imageDataHtml} |
|
</ul>` |
|
|
|
const $image = this._$image |
|
setState($image, imageState) |
|
$image.html(imageHtml) |
|
|
|
return this |
|
} |
|
show() { |
|
super.show() |
|
if (this._observeElement) this._enableObserver() |
|
|
|
return this.refresh() |
|
} |
|
hide() { |
|
this._disableObserver() |
|
|
|
return super.hide() |
|
} |
|
_initTpl() { |
|
const $el = this._$el |
|
$el.html( |
|
c(`<div class="section local-storage"></div> |
|
<div class="section session-storage"></div> |
|
<div class="section cookie"></div> |
|
<div class="section script"></div> |
|
<div class="section stylesheet"></div> |
|
<div class="section iframe"></div> |
|
<div class="section image"></div>`) |
|
) |
|
this._$localStorage = $el.find(c('.local-storage')) |
|
this._$sessionStorage = $el.find(c('.session-storage')) |
|
this._$cookie = $el.find(c('.cookie')) |
|
this._$script = $el.find(c('.script')) |
|
this._$stylesheet = $el.find(c('.stylesheet')) |
|
this._$iframe = $el.find(c('.iframe')) |
|
this._$image = $el.find(c('.image')) |
|
} |
|
_bindEvent() { |
|
const $el = this._$el |
|
const container = this._container |
|
|
|
$el |
|
.on('click', '.eruda-refresh-script', () => { |
|
container.notify('更新しました', { icon: 'success' }) |
|
this.refreshScript() |
|
}) |
|
.on('click', '.eruda-refresh-stylesheet', () => { |
|
container.notify('更新しました', { icon: 'success' }) |
|
this.refreshStylesheet() |
|
}) |
|
.on('click', '.eruda-refresh-iframe', () => { |
|
container.notify('更新しました', { icon: 'success' }) |
|
this.refreshIframe() |
|
}) |
|
.on('click', '.eruda-refresh-image', () => { |
|
container.notify('更新しました', { icon: 'success' }) |
|
this.refreshImage() |
|
}) |
|
.on('click', '.eruda-img-link', function () { |
|
const src = $(this).attr('src') |
|
|
|
showSources('img', src) |
|
}) |
|
.on('click', '.eruda-css-link', linkFactory('css')) |
|
.on('click', '.eruda-js-link', linkFactory('js')) |
|
.on('click', '.eruda-iframe-link', linkFactory('iframe')) |
|
|
|
function showSources(type, data) { |
|
const sources = container.get('sources') |
|
if (!sources) return |
|
|
|
sources.set(type, data) |
|
|
|
container.showTool('sources') |
|
|
|
return true |
|
} |
|
|
|
function linkFactory(type) { |
|
return function (e) { |
|
if (!container.get('sources')) return |
|
e.preventDefault() |
|
|
|
const url = $(this).attr('href') |
|
|
|
if (type === 'iframe' || !sameOrigin(location.href, url)) { |
|
showSources('iframe', url) |
|
} else { |
|
ajax({ |
|
url, |
|
success: (data) => { |
|
showSources(type, data) |
|
}, |
|
dataType: 'raw', |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
_rmCfg() { |
|
const cfg = this.config |
|
|
|
const settings = this._container.get('settings') |
|
|
|
if (!settings) return |
|
|
|
settings |
|
.remove(cfg, 'hideErudaSetting') |
|
.remove(cfg, 'observeElement') |
|
.remove('Resources') |
|
} |
|
_initCfg() { |
|
const cfg = (this.config = Settings.createCfg('resources', { |
|
hideErudaSetting: true, |
|
observeElement: true, |
|
})) |
|
|
|
if (cfg.get('hideErudaSetting')) this._hideErudaSetting = true |
|
if (!cfg.get('observeElement')) this._observeElement = false |
|
|
|
cfg.on('change', (key, val) => { |
|
switch (key) { |
|
case 'hideErudaSetting': |
|
this._hideErudaSetting = val |
|
return |
|
case 'observeElement': |
|
this._observeElement = val |
|
return val ? this._enableObserver() : this._disableObserver() |
|
} |
|
}) |
|
|
|
const settings = this._container.get('settings') |
|
settings |
|
.text('リソース') |
|
.switch(cfg, 'hideErudaSetting', 'Eruda設定を非表示にする') |
|
.switch(cfg, 'observeElement', '自動リフレッシュ要素') |
|
.separator() |
|
} |
|
_initObserver() { |
|
this._observer = new MutationObserver((mutations) => { |
|
each(mutations, (mutation) => { |
|
this._handleMutation(mutation) |
|
}) |
|
}) |
|
} |
|
_handleMutation(mutation) { |
|
if (isErudaEl(mutation.target)) return |
|
|
|
const checkEl = (el) => { |
|
const tagName = getLowerCaseTagName(el) |
|
switch (tagName) { |
|
case 'script': |
|
this.refreshScript() |
|
break |
|
case 'img': |
|
this.refreshImage() |
|
break |
|
case 'link': |
|
this.refreshStylesheet() |
|
break |
|
} |
|
} |
|
|
|
if (mutation.type === 'attributes') { |
|
checkEl(mutation.target) |
|
} else if (mutation.type === 'childList') { |
|
checkEl(mutation.target) |
|
let nodes = toArr(mutation.addedNodes) |
|
nodes = concat(nodes, toArr(mutation.removedNodes)) |
|
|
|
for (const node of nodes) { |
|
checkEl(node) |
|
} |
|
} |
|
} |
|
_enableObserver() { |
|
this._observer.observe(document.documentElement, { |
|
attributes: true, |
|
childList: true, |
|
subtree: true, |
|
}) |
|
} |
|
_disableObserver() { |
|
this._observer.disconnect() |
|
} |
|
} |
|
|
|
function getLowerCaseTagName(el) { |
|
if (!el.tagName) return '' |
|
return el.tagName.toLowerCase() |
|
} |
|
|
|
const regImg = /\.(jpeg|jpg|gif|png)$/ |
|
|
|
const isImg = (url) => regImg.test(url) |
|
|