eruda3 / src /Resources /Resources.js
soiz1's picture
Update src/Resources/Resources.js
3634354 verified
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)) {
// prettier-ignore
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)