first
This commit is contained in:
@ -0,0 +1,250 @@
|
||||
import './style.scss';
|
||||
|
||||
import { Component } from '@wordpress/element';
|
||||
|
||||
const { navigator } = window;
|
||||
|
||||
// generate dom tree.
|
||||
function getNodeTree(node) {
|
||||
if (node && node.hasChildNodes()) {
|
||||
const children = [];
|
||||
|
||||
for (let j = 0; j < node.childNodes.length; j += 1) {
|
||||
children.push(getNodeTree(node.childNodes[j]));
|
||||
}
|
||||
|
||||
return {
|
||||
classList: node.classList,
|
||||
nodeName: node.nodeName,
|
||||
children,
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component Class
|
||||
*/
|
||||
export default class ClassesTree extends Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.state = {
|
||||
nodes: false,
|
||||
};
|
||||
|
||||
this.onFrameLoad = this.onFrameLoad.bind(this);
|
||||
this.maybeFindIframe = this.maybeFindIframe.bind(this);
|
||||
this.updateTreeData = this.updateTreeData.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.maybeFindIframe();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.maybeFindIframe();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (!this.iframePreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.iframePreview.removeEventListener('load', this.onFrameLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* On frame load event.
|
||||
*/
|
||||
onFrameLoad() {
|
||||
if (!this.iframePreview.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this.frameWindow = this.iframePreview.contentWindow;
|
||||
this.frameJQuery = this.iframePreview.contentWindow.jQuery;
|
||||
|
||||
if (this.frameJQuery) {
|
||||
this.$framePortfolio = this.frameJQuery('.vp-portfolio');
|
||||
}
|
||||
|
||||
this.updateTreeData();
|
||||
}
|
||||
|
||||
maybeFindIframe() {
|
||||
if (this.iframePreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { clientId } = this.props;
|
||||
|
||||
const iframePreview = document.querySelector(
|
||||
`#block-${clientId} iframe`
|
||||
);
|
||||
|
||||
if (iframePreview) {
|
||||
this.iframePreview = iframePreview;
|
||||
this.iframePreview.addEventListener('load', this.onFrameLoad);
|
||||
this.onFrameLoad();
|
||||
}
|
||||
}
|
||||
|
||||
updateTreeData() {
|
||||
if (this.$framePortfolio) {
|
||||
this.setState({
|
||||
nodes: getNodeTree(this.$framePortfolio[0]),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.iframePreview) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="vpf-component-classes-tree">
|
||||
<ClassesTree.TreeItem
|
||||
node={this.state.nodes}
|
||||
skipNodeByClass={/vp-portfolio__item-popup/}
|
||||
collapseByClass={
|
||||
/^(vp-portfolio__preloader-wrap|vp-portfolio__filter-wrap|vp-portfolio__sort-wrap|vp-portfolio__items-wrap|vp-portfolio__pagination-wrap)$/
|
||||
}
|
||||
skipClass={/vp-uid-/}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ClassesTree.TreeItem = class TreeItem extends Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.state = {
|
||||
isCollapsed: null,
|
||||
};
|
||||
|
||||
this.isCollapsed = this.isCollapsed.bind(this);
|
||||
}
|
||||
|
||||
isCollapsed() {
|
||||
const { node, collapseByClass } = this.props;
|
||||
|
||||
let { isCollapsed } = this.state;
|
||||
|
||||
// check if collapsed by default.
|
||||
if (
|
||||
isCollapsed === null &&
|
||||
node &&
|
||||
node.classList &&
|
||||
node.classList.length
|
||||
) {
|
||||
node.classList.forEach((className) => {
|
||||
if (collapseByClass && collapseByClass.test(className)) {
|
||||
isCollapsed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return isCollapsed;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { node, skipNodeByClass, skipClass } = this.props;
|
||||
|
||||
if (!node || !node.children.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const classes = [];
|
||||
let skip = false;
|
||||
|
||||
// Classes.
|
||||
if (node.classList && node.classList.length) {
|
||||
node.classList.forEach((className) => {
|
||||
if (!skipClass || !skipClass.test(className)) {
|
||||
classes.push(className);
|
||||
}
|
||||
|
||||
// Skip?
|
||||
if (skipNodeByClass && skipNodeByClass.test(className)) {
|
||||
skip = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ul>
|
||||
<li
|
||||
className={`vpf-component-classes-tree-node ${
|
||||
this.isCollapsed() ? '' : 'is-collapsed'
|
||||
}`}
|
||||
>
|
||||
<div>
|
||||
{node.children.length ? (
|
||||
<button
|
||||
type="button"
|
||||
className="vpf-component-classes-tree-node-collapse"
|
||||
onClick={() =>
|
||||
this.setState({
|
||||
isCollapsed: !this.isCollapsed(),
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<
|
||||
{node.nodeName.toLowerCase()}
|
||||
{classes.length ? (
|
||||
<>
|
||||
{' class="'}
|
||||
{classes.map((className) => (
|
||||
<button
|
||||
key={className}
|
||||
type="button"
|
||||
className="vpf-component-classes-tree-node-class"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
className
|
||||
);
|
||||
}}
|
||||
>
|
||||
{className}
|
||||
</button>
|
||||
))}
|
||||
{'" '}
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
{node.children.length && this.isCollapsed()
|
||||
? node.children.map((childNode) => {
|
||||
if (childNode) {
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<li className="vpf-component-classes-tree-child">
|
||||
<ClassesTree.TreeItem
|
||||
{...this.props}
|
||||
node={childNode}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
: ''}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
};
|
@ -0,0 +1,126 @@
|
||||
@use "sass:color";
|
||||
|
||||
$dom_tree_color_bg_node_class: #dcdfe6 !default;
|
||||
$dom_tree_color_text_node_class: #595d67 !default;
|
||||
|
||||
/**
|
||||
* DOM Tree
|
||||
*/
|
||||
.vpf-component-classes-tree-help code {
|
||||
display: inline-block;
|
||||
padding: 2px 6px;
|
||||
line-height: 1.2;
|
||||
color: $dom_tree_color_text_node_class;
|
||||
cursor: pointer;
|
||||
background-color: $dom_tree_color_bg_node_class;
|
||||
border-radius: 3px;
|
||||
transition: 0.15s background-color, 0.15s color;
|
||||
|
||||
&:hover {
|
||||
color: color.adjust($dom_tree_color_text_node_class, $lightness: -20%);
|
||||
background-color: color.adjust($dom_tree_color_bg_node_class, $lightness: -10%);
|
||||
}
|
||||
}
|
||||
|
||||
.vpf-component-classes-tree {
|
||||
padding: 15px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 0;
|
||||
padding-left: 0;
|
||||
font-family: monospace;
|
||||
color: #67666d;
|
||||
background-color: #f9f9fa;
|
||||
border: 1px solid #ddd;
|
||||
|
||||
.spinner {
|
||||
float: none;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: relative;
|
||||
padding-left: 15px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
// Node
|
||||
.vpf-component-classes-tree-node > div {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
// Node Class
|
||||
.vpf-component-classes-tree-node-class {
|
||||
display: inline;
|
||||
padding: 2px 6px;
|
||||
line-height: 1.2;
|
||||
color: $dom_tree_color_text_node_class;
|
||||
cursor: pointer;
|
||||
background-color: $dom_tree_color_bg_node_class;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
transition: 0.15s background-color, 0.15s color;
|
||||
|
||||
&:hover {
|
||||
color: color.adjust($dom_tree_color_text_node_class, $lightness: -20%);
|
||||
background-color: color.adjust($dom_tree_color_bg_node_class, $lightness: -10%);
|
||||
}
|
||||
|
||||
+ .vpf-component-classes-tree-node-class {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
// Collapse
|
||||
.vpf-component-classes-tree-node-collapse {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-top: 6px solid;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
right: -10px;
|
||||
bottom: -7px;
|
||||
left: -10px;
|
||||
display: block;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
.is-collapsed .vpf-component-classes-tree-node-collapse {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
// Hover
|
||||
.vpf-component-classes-tree-child {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
right: 0;
|
||||
bottom: -3px;
|
||||
left: 8px;
|
||||
display: block;
|
||||
content: "";
|
||||
background-color: #f0f0f1;
|
||||
border-radius: 4px;
|
||||
opacity: 0;
|
||||
transition: 0.2s opacity;
|
||||
}
|
||||
}
|
||||
|
||||
.vpf-component-classes-tree-node:hover ~ .vpf-component-classes-tree-child::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user