dragonroll/backend/node_modules/mongoose-slug-generator/lib/slug-generator.js

185 lines
4.4 KiB
JavaScript

'use strict';
var getSlug = require('speakingurl'),
shortId = require('shortid'),
async = require('async');
module.exports = function (schema, options) {
var watcher = [],
slugs = [],
opts = {
separator: "-",
lang: "en",
truncate: 120
};
//merge de options
for (var attrname in options) {
opts[attrname] = options[attrname];
}
schema.eachPath(function (pathname, schemaType) {
if (schemaType.instance == "String" && schemaType.options && schemaType.options.slug) {
var slug = {
"name": pathname
};
if (typeof(schemaType.options.slug) === "string") {
slug.values = [schemaType.options.slug]
} else if (schemaType.options.slug instanceof Array) {
slug.values = schemaType.options.slug
} else {
//TODO launch error
}
if (schemaType.options.unique || schemaType.options.unique_slug) {
slug.unique = true;
}
if (schemaType.options.slug_padding_size === undefined) {
slug.isShortIdMode = true;
} else {
slug.isShortIdMode = false;
slug.padding = schemaType.options.slug_padding_size;
}
watcher = watcher.concat(slug.values.filter(function (item) {
return watcher.indexOf(item) < 0;
}));
slugs.push(slug);
}
});
/**
* Executed before save value
*/
schema.pre('save', function (next) {
var doc = this,
reSlug = false;
watcher.forEach(function (item) {
if (doc.isModified(item)) {
reSlug = true;
}
});
if (!reSlug) {
return next();
}
async.each(slugs, function (item, callback) {
var values = [];
item.values.forEach(function (item) {
values.push(doc[item]);
});
if (!(item.unique || item.unique_slug)) {
doc[item.name] = makeSlug(values, opts);
callback();
} else {
if (item.isShortIdMode) {
makeUniqueShortIdSlug(doc, item.name, values, opts, function (err, slug) {
doc[item.name] = slug;
callback();
})
} else {
makeUniqueCounterSlug(doc, item.name, values, opts, item.padding , function (err, slug) {
doc[item.name] = slug;
callback();
})
}
}
}, function (err, res) {
next();
});
});
};
function makeSlug(values, options) {
var slug = getSlug(
values.join(" "),
options
);
return slug;
}
function makeUniqueCounterSlug(doc, field, values, options, padding, next) {
var slug = makeSlug(values, options),
count = 0,
match = null,
test = new RegExp(options.separator + '(\\d+)$'),
query = {},
search = new RegExp(slug + "(" + options.separator + '(\\d+))?$'),
sort = {};
sort[field] = -1;
if (doc._id) {
query["_id"] = {
$ne: doc._id
}
}
query[field] = search;
// field = search and doc != doc
doc.model(doc.constructor.modelName).findOne(query).sort(sort).exec(function (err, result) {
if (result) {
if (match = result[field].match(test)) {
count = match[1];
}
count++;
slug += options.separator + pad(count, padding);
}
next(null, slug);
})
}
function pad(num, size) {
var s = num+"";
while (s.length < size) s = "0" + s;
return s;
}
/***
* Generates a unique slug. If the slug is already used, the generated slug has an appended random string, eg: my-slug-NJw9XvZ5l
*
* @param doc
* @param field
* @param values
* @param options
* @param next
*/
function makeUniqueShortIdSlug(doc, field, values, options, next) {
var slug = makeSlug(values, options),
query = {};
query[field] = slug;
doc.model(doc.constructor.modelName).findOne(query).exec(function (err, result) {
if (result) {
slug += options.separator + shortId.generate();
}
next(null, slug);
});
}