Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KIRBY 4 - start #8

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

178 changes: 90 additions & 88 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,100 +6,102 @@ function fitsConstraint(constraints, type, width) {
return true;
}

const cache = new WeakMap();

function createProxyForBlocks(blocks) {
if(cache.has(blocks)) {
return cache.get(blocks);
}

const {constraints, cwidth} = blocks;

return cache.set(blocks, new Proxy(blocks, {
get(target, key) {
if(key === 'fieldsets') {
return Object.fromEntries(
Object.entries(target.fieldsets).filter(([type]) => fitsConstraint(constraints, type, cwidth))
);
}
return target[key];
}
})).get(blocks);
}

panel.plugin("rasteiner/conditionalblocks", {

use: [
function (Vue) {
const LayoutField = Vue.component("k-layout-field").options;
const BlockLayouts = LayoutField.components["k-block-layouts"];
const Layout = BlockLayouts.components["k-layout"];
const LayoutColumn = Layout.components["k-layout-column"];
const BlockSelector = Vue.component("k-block-selector").options;
const LayoutColumn = Vue.component("k-layout-column").options;
const Blocks = Vue.component("k-blocks").options;

Vue.component("k-layout-field", {
extends: LayoutField,

provide() {
return {
constraints: (this.requires && !Array.isArray(this.requires)) ? this.requires : {},
};
},
props: {
requires: {
type: Object|Array,
required: false,
},
},
});

LayoutColumn.provide = function () {
const [num, denum] = this.width.split("/");
const cwidth = parseInt(num) / parseInt(denum);

return {
cwidth,
};
};

const inject = {
constraints: {
from: "constraints",
default: {},
},
cwidth: {
from: "cwidth",
default: 1,
},
}

Vue.component("k-blocks", {
extends: Blocks,
inject: inject,
methods: {
append(what, index) {
if(this.constraints && this.cwidth && Array.isArray(what)) {
what = what.filter((block) => fitsConstraint(this.constraints, block.type, this.cwidth));
}

Blocks.methods.append.call(this, what, index);
}
},
computed: {
draggableOptions() {
const original = Blocks.computed.draggableOptions.call(this);

if (this.constraints && this.cwidth) {
//remove fieldsets that are not allowed by constraints
original.data.fieldsets = Object.fromEntries(
Object.entries(original.data.fieldsets).filter(([type]) => fitsConstraint(this.constraints, type, this.cwidth))
);
}

return original;
},
},
});

BlockSelector.inject = inject;

const open = BlockSelector.methods.open;
BlockSelector.methods.open = function () {
open.call(this, ...arguments);

if (!this.constraints || !this.cwidth) return;
const width = this.cwidth;

const myDisabled = Object.entries(this.constraints)
.filter(([_, value]) => {
return (
(value.min && width < value.min) ||
(value.max && width > value.max)
);
})
.map(([key, _]) => key);

this.disabled = [...this.disabled, ...myDisabled];
};
LayoutField.provide = function() {
return {
constraints: (this.requires && !Array.isArray(this.requires)) ? this.requires : {},
};
};

LayoutField.props.requires = {
type: Object|Array,
required: false,
};

LayoutColumn.provide = function() {
const [num, denum] = this.width.split("/");
const cwidth = parseInt(num) / parseInt(denum);

return {
cwidth,
};
};

Blocks.inject = {
constraints: {
from: "constraints",
default: {},
},
cwidth: {
from: "cwidth",
default: null,
},
};

for(const fn of ['choose', 'chooseToConvert']) {
const orig = Blocks.methods[fn];
Blocks.methods[fn] = function(...args) {
// If I'm in a column with constraints
if(Object.entries(this.constraints).length > 0 && this.cwidth) {
// create a proxy for `this` that returns a filtered set of fieldsets
const proxy = createProxyForBlocks(this);

// and call the original method on the proxy
Reflect.apply(orig, proxy, args);
} else {

// otherwise call the method on the original object
Reflect.apply(orig, this, args);
}
};
}

Blocks.methods.canAcceptBlockType = function(type) {
if(!type in this.fieldsets) return false;
if(!type in this.constraints) return true;

return fitsConstraint(this.constraints, type, this.cwidth);
}

const move = Blocks.methods.move;
Blocks.methods.move = function(event) {
if(Reflect.apply(move, this, arguments)) {
let target = event.relatedContext.component;
while(target && !target.canAcceptBlockType) target = target.$parent;
const block = event.draggedContext.element;
return target?.canAcceptBlockType(block.type) ?? false;
}

return false;
};
},
],
});