src/schemas/types/Dimension.js
const pd = require("parse-dimensions");
const numRange = bucket =>
bucket.to
? `${bucket.from || 0}-${bucket.to}${bucket.unit}`
: `${bucket.from}${bucket.unit}+`;
const Dimension = function(options) {
this.options = options;
this.defaultUnit = options.defaultUnit || "mm";
this.defaultSearchUnit = options.defaultSearchUnit || "cm";
/*
name
type
searchName
defaultUnit
defaultSearchUnit
title(i18n)
widthTitle(i18n)
heightTitle(i18n)
placeholder(i18n)
*/
};
Dimension.prototype = {
searchName() {
return this.options.searchName || this.options.name;
},
value(query) {
const heightMin = query[`${this.searchName()}.heightMin`];
const heightMax = query[`${this.searchName()}.heightMax`];
const widthMin = query[`${this.searchName()}.widthMin`];
const widthMax = query[`${this.searchName()}.widthMax`];
const unit =
query[`${this.searchName()}.unit`] ||
this.defaultSearchUnit ||
this.defaultUnit;
if (heightMin || heightMax || widthMin || widthMax) {
return {heightMin, heightMax, widthMin, widthMax, unit};
}
},
searchTitle(value, i18n) {
const expectedUnit = this.defaultSearchUnit || this.defaultUnit;
const unit = value.unit || expectedUnit;
const title = [];
if (value.heightMin || value.heightMax) {
const name = this.options.heightTitle(i18n);
const range = numRange({
from: pd.convertNumber(value.heightMin, unit, expectedUnit),
to: pd.convertNumber(value.heightMax, unit, expectedUnit),
unit,
});
title.push(`${name}: ${range}`);
}
if (value.widthMin || value.widthMax) {
const name = this.options.widthTitle(i18n);
const range = numRange({
from: pd.convertNumber(value.widthMin, unit, expectedUnit),
to: pd.convertNumber(value.widthMax, unit, expectedUnit),
unit,
});
title.push(`${name}: ${range}`);
}
return title.join(", ");
},
fields(value) {
const ret = {};
const defaultUnit = this.defaultSearchUnit || this.defaultUnit;
if (value.height) {
ret[`${this.searchName()}.heightMin`] = value.height;
ret[`${this.searchName()}.heightMax`] = value.height;
}
if (value.heightMin) {
ret[`${this.searchName()}.heightMin`] = value.heightMin;
}
if (value.heightMax) {
ret[`${this.searchName()}.heightMax`] = value.heightMax;
}
if (value.width) {
ret[`${this.searchName()}.widthMin`] = value.width;
ret[`${this.searchName()}.widthMax`] = value.width;
}
if (value.widthMin) {
ret[`${this.searchName()}.widthMin`] = value.widthMin;
}
if (value.widthMax) {
ret[`${this.searchName()}.widthMax`] = value.widthMax;
}
if (value.unit && value.unit !== defaultUnit) {
ret[`${this.searchName()}.unit`] = value.unit;
}
return ret;
},
breadcrumbs(value, i18n) {
const breadcrumbs = [];
if (value.heightMin || value.heightMax) {
const title = this.options.heightTitle(i18n);
const range = numRange({
from: value.heightMin,
to: value.heightMax,
unit: value.unit,
});
const newValue = Object.assign({}, value);
delete newValue.heightMin;
delete newValue.heightMax;
breadcrumbs.push({
name: `${title}: ${range}`,
value: newValue,
});
}
if (value.widthMin || value.widthMax) {
const title = this.options.widthTitle(i18n);
const range = numRange({
from: value.widthMin,
to: value.widthMax,
unit: value.unit,
});
const newValue = Object.assign({}, value);
delete newValue.widthMin;
delete newValue.widthMax;
breadcrumbs.push({
name: `${title}: ${range}`,
value: newValue,
});
}
return breadcrumbs;
},
filter(value) {
const filters = [];
if (value.widthMin) {
filters.push({
range: {
[`${this.options.name}.width`]: {
gte: pd.convertNumber(
parseFloat(value.widthMin),
value.unit,
this.defaultUnit,
),
},
},
});
}
if (value.widthMax) {
filters.push({
range: {
[`${this.options.name}.width`]: {
lte: pd.convertNumber(
parseFloat(value.widthMax),
value.unit,
this.defaultUnit,
),
},
},
});
}
if (value.heightMin) {
filters.push({
range: {
[`${this.options.name}.height`]: {
gte: pd.convertNumber(
parseFloat(value.heightMin),
value.unit,
this.defaultUnit,
),
},
},
});
}
if (value.heightMax) {
filters.push({
range: {
[`${this.options.name}.height`]: {
lte: pd.convertNumber(
parseFloat(value.heightMax),
value.unit,
this.defaultUnit,
),
},
},
});
}
return filters;
},
facet() {
const defaultUnit = this.defaultUnit;
const unit = this.defaultSearchUnit || this.defaultUnit;
const formatFacetBucket = bucket => {
const text = numRange({
from: pd.convertNumber(bucket.from, defaultUnit, unit),
to: pd.convertNumber(bucket.to, defaultUnit, unit),
unit,
});
return {
text,
count: bucket.doc_count,
url: {
[this.options.name]: {
widthMin: bucket.from,
widthMax: bucket.to,
unit,
},
},
};
};
const ranges = [
{to: 99},
{from: 100, to: 199},
{from: 200, to: 299},
{from: 300, to: 399},
{from: 400, to: 499},
{from: 500, to: 599},
{from: 600, to: 699},
{from: 700, to: 799},
{from: 800, to: 899},
{from: 900, to: 999},
{from: 1000, to: 1249},
{from: 1250, to: 1599},
{from: 1500, to: 1749},
{from: 1750, to: 1999},
{from: 2000},
];
return {
[`${this.options.name}.width`]: {
title: i18n => this.options.widthTitle(i18n),
facet: () => ({
range: {
field: `${this.options.name}.width`,
ranges,
},
}),
formatBuckets: buckets => buckets.map(formatFacetBucket),
},
[`${this.options.name}.height`]: {
title: i18n => this.options.heightTitle(i18n),
facet: () => ({
range: {
field: `${this.options.name}.height`,
ranges,
},
}),
formatBuckets: buckets => buckets.map(formatFacetBucket),
},
};
},
schema(Schema) {
const DimensionSchema = new Schema({
// An ID for the dimension, computed from the original +
// width/height properties before validation.
_id: String,
// The source string from which the dimensions were generated
original: String,
// The width/height/depth of the object (stored in millimeters)
width: {type: Number, es_indexed: true},
height: {type: Number, es_indexed: true},
depth: {type: Number, es_indexed: true},
// A label for the dimensions (e.g. "with frame")
label: String,
// The unit for the dimensions (defaults to millimeters)
unit: {type: String, es_indexed: true},
});
DimensionSchema.methods = {
toJSON() {
const obj = this.toObject();
delete obj.original;
return obj;
},
};
// Dynamically generate the _id attribute
DimensionSchema.pre("validate", function(next) {
this._id =
this.original || [this.width, this.height, this.unit].join(",");
next();
});
return {
type: [DimensionSchema],
convert: obj =>
typeof obj === "string"
? pd.parseDimension(obj, true, this.defaultUnit)
: pd.convertDimension(obj, this.defaultUnit),
validateArray: val => (val.width || val.height) && val.unit,
validationMsg: i18n =>
i18n.gettext(
"Dimensions must have a " +
"unit specified and at least a width or height.",
),
};
},
};
module.exports = Dimension;