diff --git a/README.md b/README.md index 9270d5d..bded9fd 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Features: - **Does not affect structure** or existing styles 👌 - Detects **Knockout** components and templates 🤜 +- Detects **jQuery** widget registration and usage 💲 - Finds Magento **mage-init scripts** within templates/layouts 📌 - Uses dev-tools like **element picker** to select elements 🔫 - Prints **browseable structure** and internal informations in console 👀 diff --git a/view/base/web/js/LayoutHints.js b/view/base/web/js/LayoutHints.js index fe658a8..d23cc6f 100644 --- a/view/base/web/js/LayoutHints.js +++ b/view/base/web/js/LayoutHints.js @@ -1,21 +1,26 @@ define([ './highlights', + './debug/JQueryWidgetDebugger', './debug/KnockoutDebugger', './debug/MageLayoutDebugger', './debug/MageInitDebugger' -], function (highlights, KnockoutDebugger, MageLayoutDebugger, MageInitDebugger) { +], function (highlights, JQueryWidgetDebugger, KnockoutDebugger, MageLayoutDebugger, MageInitDebugger) { var colors = { - blue4: "36 47 155", - blue3: "100 111 212", - blue2: "155 163 235", - blue1: "219 223 253", - navy: "42 37 80", - brown: "84 18 18", + blue5: "36 80 190", + blue4: "36 47 155", + blue3: "100 111 212", + blue2: "155 163 235", + blue1: "219 223 253", + navy: "42 37 80", + brown: "84 18 18", + orange: "225 70 0" } - var labelStyle = "padding-left: 3px; padding-right: 3px; border-radius: 3px; margin-right: .5em; display: inline-block; cursor: pointer;" + var labelStyle = "padding-left: 3px; padding-right: 3px; border-radius: 3px; margin-right: .5em; display: inline-block; font-weight: bold; cursor: pointer;" + var labelStyleAqua = `${labelStyle} background: rgb(${colors.blue5}); color: white;` var labelStyleBlue = `${labelStyle} background: rgb(${colors.blue4}); color: white;` var labelStyleNavy = `${labelStyle} background: rgb(${colors.navy}); color: white;` var labelStyleBrown = `${labelStyle} background: rgb(${colors.brown}); color: white;` + var labelStyleOrange = `${labelStyle} background: rgb(${colors.orange}); color: white;` return class LayoutHints { constructor (mageLayoutTree, initOptions) { @@ -27,28 +32,33 @@ define([ this.debuggers = {} - this.debuggers.mageInit = new MageInitDebugger(this) - this.debuggers.mageLayout = new MageLayoutDebugger( - this, mageLayoutTree, { largerFontSize: "1.25em", - labelStyleBlue, labelStyleNavy, labelStyleBrown, blockEditUrl: initOptions.blockEditUrl, - mageInitDebugger: this.debuggers.mageInit } ) - this.debuggers.knockout = new KnockoutDebugger( - this, - { - largerFontSize: "1.25em", - labelStyles: labelStyleBrown, - } - ) + this.debuggers.mageInit = new MageInitDebugger({ + largerFontSize: "1.25em", + }) + + this.debuggers.jqueryWidget = new JQueryWidgetDebugger({ + largerFontSize: "1.25em", + }) + + this.debuggers.knockout = new KnockoutDebugger(this, { + largerFontSize: "1.25em", + labelStyles: labelStyleBrown, + }) + + this.debuggers.mageInit.badgeStyle = labelStyleBlue + this.debuggers.mageLayout.badgeStyle = labelStyleOrange + this.debuggers.jqueryWidget.badgeStyle = labelStyleAqua + this.debuggers.knockout.badgeStyle = labelStyleBrown // set up basic highlight styles document.documentElement.style.setProperty('--hl-bg', `rgb(${colors.blue1} / .85)`) @@ -67,7 +77,6 @@ define([ } this.highlight(inspectable, { printOnClick: false }) - this.consolePrint(inspectable) } findInspectable (element) { @@ -79,11 +88,7 @@ define([ continue } - var inspectable = typeDebugger.getInspectable(element) - inspectable.element = element - inspectable.type = type - - return inspectable + return element } } while (element = element.parentElement) } @@ -110,42 +115,94 @@ define([ this.highlight(closestHighlightable) } - highlight (data, options) { - if (!this.debuggers[data.type] || typeof this.debuggers[data.type].highlight !== 'function') { - throw new Error(`Cannot highlight element of type ${data.type}`) - } + highlight (element) { + let elementsData = new Map() - return this.debuggers[data.type].highlight(data, options) - } + // collect data from debuggers + for (let type in this.debuggers) { + const typeDebugger = this.debuggers[type] + + if (typeof typeDebugger.isInspectable !== 'function' + || typeof typeDebugger.getHighlightsData !== 'function' + || !typeDebugger.isInspectable(element) + ) { + continue + } + + const highlights = typeDebugger.getHighlightsData(element) + + for (const highlight of highlights) { + const highlightedEl = highlight.element || element - consolePrint (data, options) { - if (!this.debuggers[data.type] || typeof this.debuggers[data.type].consolePrint !== 'function') { - throw new Error(`Cannot consolePrint element of type ${data.type}`) + const elementData = elementsData.get(highlightedEl) || [] + elementData.push(Object.assign(highlight, { type })) + + elementsData.set(highlightedEl, elementData) + } } - return this.debuggers[data.type].consolePrint(data, options) + for (const [highlightedEl, highlightData] of elementsData) { + let content = '' + + for (let highlight of highlightData) { + content += `
${JSON.stringify(i.options, null, 2)}` + } + }) + + if (element === document.body) { + const unusedWidgets = this.filterUnusedWidgets() + + highlightsData.push({ + badges: [`${unusedWidgets.length} Unused jQuery Widgets`], + content: `
${unusedWidgets.join('; ')}` + }) + } + + return highlightsData + } + + consolePrint (element) { + const inits = initialized.filter(i => i.element === element) + + if (!inits.length === 0) { + return + } + + inits.forEach(initData => { + console.group( + `%c$.${initData.widget}`, + `${this.badgeStyle || ''}; font-size: ${this.largerFontSize}`, + ) + console.log("Options: ", initData.options) + console.groupEnd() + }) + + if (document.body === element) { + console.log("Unused jQuery Widgets: ", this.filterUnusedWidgets()) + } + } + + filterUnusedWidgets () { + return registeredWidgets.filter(widgetName => { + const parts = widgetName.split('.') + const name = parts[parts.length - 1] + + return !initialized.find(init => init.widget === name) + }) + } + + dump () { + console.log("JQuery Registered Widgets: ", registeredWidgets) + console.log("JQuery Widget Usage: ", initialized) + + console.log("Unused widgets: ", this.filterUnusedWidgets()) + } + } +}) diff --git a/view/base/web/js/debug/KnockoutDebugger.js b/view/base/web/js/debug/KnockoutDebugger.js index 38e41ab..a3986e9 100644 --- a/view/base/web/js/debug/KnockoutDebugger.js +++ b/view/base/web/js/debug/KnockoutDebugger.js @@ -19,8 +19,7 @@ define(['knockout', '../highlights'], function (ko, highlights) { constructor (layoutHints, options = {}) { this.layoutHints = layoutHints - this.labelStyles = options.labelStyles || '' - this.largerFontSize = options.largerFontSize || '' + this.largerFontSize = options.largerFontSize || '1em' this.initTemplateCollector() } @@ -83,24 +82,24 @@ define(['knockout', '../highlights'], function (ko, highlights) { throw new Error("This element is not inspectable!") } - var context = ko.contextFor(element) - var templates = new Set(this.templates.get(element)) + const context = ko.contextFor(element) + const templates = new Set(this.templates.get(element)) while (ko.contextFor(element.parentElement) === context) { element = element.parentElement // merge templates if (this.templates.has(element)) { - for (var template of this.templates.get(element)) { + for (let template of this.templates.get(element)) { templates.add(template) } } } - var parent = element.parentElement - var elements = [] + const parent = element.parentElement + const elements = [] - for (var child of parent.children) { + for (let child of parent.children) { if (ko.contextFor(child) === context) { elements.push(child) } @@ -109,38 +108,33 @@ define(['knockout', '../highlights'], function (ko, highlights) { return { element, elements, context, templates } } - highlight (data, { printOnClick = true } = {}) { - var $data = data.context.$data + getHighlightsData (element) { + const inspectable = this.getInspectable(element) + const $data = inspectable.context.$data - var content - var names = getNames(data) - - content = `
- KO - ${names.map(n => `${n}`).join(' ')} -
` + let content = '' if ($data.component) { - content += `${$data.component}
${$data.component}
${$data.template}
${$data.template}