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

Release v14.1.0 #172

Merged
merged 11 commits into from
Apr 13, 2022
8 changes: 6 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,13 @@ module.exports = {
// disallow whitespace before properties
'no-whitespace-before-property': 'error',
// enforce consistent spacing inside braces
'object-curly-spacing': ['error', 'always' ],
'object-curly-spacing': ['error', 'always'],
// enforce placing object properties on separate lines
'object-property-newline': 'error',
'object-property-newline': [
'error', {
'allowAllPropertiesOnSameLine': true,
},
],
// require or disallow newlines around variable declarations
'one-var-declaration-per-line': 'error',
// enforce consistent linebreak style for operators
Expand Down
7 changes: 6 additions & 1 deletion client/components/Location/Forms/Export/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ module.exports = function (location) {
var listeners = {};

self.bind = function ($mount) {
// Token is not needed if download is publicly allowed.
var tokenQuery = '';
if (account.hasToken()) {
tokenQuery = '&token=' + account.getToken();
}
// Render
$mount.html(template({
id: location._id,
token: account.getToken(),
tokenQuery: tokenQuery,
__: georap.i18n.__,
}));

Expand Down
6 changes: 3 additions & 3 deletions client/components/Location/Forms/Export/template.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
<div class="panel-body">

<p>
<a href="/api/locations/<%= id %>?format=kml&amp;token=<%= token %>" class="btn btn-default" role="button" target="_blank">KML</a>
<a href="/api/locations/<%= id %>?format=kml<%= tokenQuery %>" class="btn btn-default" role="button" target="_blank">KML</a>
<%= __('for-google-earth') %>
</p>
<p>
<a href="/api/locations/<%= id %>?format=gpx&amp;token=<%= token %>" class="btn btn-default" role="button" target="_blank">GPX</a>
<a href="/api/locations/<%= id %>?format=gpx<%= tokenQuery %>" class="btn btn-default" role="button" target="_blank">GPX</a>
<%= __('for-gps-devices') %>
</p>
<p>
<a href="/api/locations/<%= id %>?format=geojson&amp;token=<%= token %>" class="btn btn-default" role="button" target="_blank">GeoJSON</a>
<a href="/api/locations/<%= id %>?format=geojson<%= tokenQuery %>" class="btn btn-default" role="button" target="_blank">GeoJSON</a>
<%= __('for-web-apps') %>
</p>

Expand Down
29 changes: 20 additions & 9 deletions client/components/Map/lib/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,52 @@
// Map marker icon definitions. The icons can be used only after google maps
// api has been loaded. Therefore, call the methods after initMap.

var sizes = georap.config.markerTemplateSizes;
var staticUrl = georap.config.staticUrl;
var geolocationUrl = staticUrl + '/images/mapicons/geolocation.png';
var crosshairUrl = staticUrl + '/images/mapicons/crosshair.png';
var additionMarkerUrl = staticUrl + '/images/mapicons/additionMarker.png';
var labelOffset = 6;

// NOTE google.maps is populated asynchronously and therefore
// we cannot shorten Point and Size references.

exports.marker = function (url) {
var w = sizes.md.width;
var h = sizes.md.height;
var wmid = Math.floor(w / 2);
return {
labelOrigin: new google.maps.Point(11, 46),
labelOrigin: new google.maps.Point(wmid, h + labelOffset),
url: url,
size: new google.maps.Size(22, 40),
size: new google.maps.Size(w, h),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(11, 40),
anchor: new google.maps.Point(wmid, h),
};
};

exports.small = function (url) {
var w = sizes.sm.width;
var h = sizes.sm.height;
var wmid = Math.floor(w / 2);
return {
labelOrigin: new google.maps.Point(4, 20),
labelOrigin: new google.maps.Point(wmid, h + labelOffset),
url: url,
size: new google.maps.Size(9, 14),
size: new google.maps.Size(w, h),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(4, 14),
anchor: new google.maps.Point(wmid, h),
};
};

exports.large = function (url) {
var w = sizes.lg.width;
var h = sizes.lg.height;
var wmid = Math.floor(w / 2);
return {
labelOrigin: new google.maps.Point(19, 72),
labelOrigin: new google.maps.Point(wmid, h + labelOffset),
url: url,
size: new google.maps.Size(38, 66),
size: new google.maps.Size(w, h),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(19, 65),
anchor: new google.maps.Point(wmid, h),
};
};

Expand Down
Binary file removed config-sample/images/markers/source.xcf
Binary file not shown.
1 change: 1 addition & 0 deletions config-sample/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ module.exports = {
locationTypes: locations.locationTypes,
// Location marker template image settings
markerTemplates: locations.markerTemplates,
markerTemplateSizes: locations.markerTemplateSizes,

// Posts and comments
// See config/posts.js
Expand Down
19 changes: 19 additions & 0 deletions config-sample/locations.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,22 @@ exports.markerTemplates = {
},
},
};

// Marker template sizes.
// For correct alignment, these should match the template image dimensions.
// The available size classes: 'sm', 'md', 'lg'.
// Maybe in future the sizes are detected automatically.
exports.markerTemplateSizes = {
'sm': {
width: 9,
height: 14,
},
'md': {
width: 22,
height: 40,
},
'lg': {
width: 38,
height: 66,
},
};
34 changes: 34 additions & 0 deletions local_modules/georap-config/ensureOptional.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Ensure that optional config properties have values.
// Detect missing optional properties and set them.
//
// This helps in backward compatibility and prevents
// MAJOR version increaments when new config props are introduced.
// Also, this way we need to write default config values only here.
//
// Modify this file when new optional props are introduced.
//

module.exports = (config) => {
// Modify in place.

// markerTemplateSizes
// Introduced in v14.1. Required in v15.
if (!config.markerTemplateSizes) {
config.markerTemplateSizes = {
sm: {
width: 9,
height: 14,
},
md: {
width: 22,
height: 40,
},
lg: {
width: 38,
height: 66,
},
};
}

return config;
};
4 changes: 4 additions & 0 deletions local_modules/georap-config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

const config = require('../../config');
const schema = require('./schema');
const ensureOptional = require('./ensureOptional');
const Ajv = require('ajv');

// Ensure that config/index.js is not accidentally included in client code
Expand All @@ -12,6 +13,9 @@ if (typeof window !== 'undefined') {
'Ensure that georap-config module is used only in server-side code.');
}

// Ensure optional properties have values.
ensureOptional(config);

// Validate against JSON schema
const ajv = new Ajv();
const valid = ajv.validate(schema, config);
Expand Down
2 changes: 1 addition & 1 deletion local_modules/georap-config/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "georap-config",
"private": true,
"version": "1.0.0",
"version": "14.1.0",
"description": "Provide georap configuration as a package",
"keywords": [],
"main": "index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const iconSchema = require('./iconSchema');
const exportServicesSchema = require('./exportServicesSchema');
const smtpSchema = require('./smtpSchema');
const entryFlagsSchema = require('./entryFlagsSchema');
const sizeSchema = require('./sizeSchema');

// Then the full config

Expand Down Expand Up @@ -194,6 +195,16 @@ module.exports = {
markerTemplates: {
type: 'object',
},
markerTemplateSizes: {
type: 'object',
properties: {
sm: sizeSchema,
md: sizeSchema,
lg: sizeSchema,
},
required: ['sm', 'md', 'lg'],
additionalProperties: false,
},
entries: {
type: 'object',
properties: {
Expand Down Expand Up @@ -310,6 +321,7 @@ module.exports = {
'rewards',
'entryFlags',
'markerTemplates',
// 'markerTemplateSizes', // new in v14.1, require in v15
'entries',
'comments',
'enableSupportPage', // new in v12, require in v13
Expand Down
13 changes: 13 additions & 0 deletions local_modules/georap-config/schema/sizeSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
type: 'object',
properties: {
width: {
type: 'integer',
},
height: {
type: 'integer',
},
},
required: ['width', 'height'],
additionalProperties: false,
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "georap",
"private": true,
"version": "14.0.1",
"version": "14.1.0",
"description": "Geographical messaging board built on Express.js",
"keywords": [
"GIS",
Expand Down
97 changes: 47 additions & 50 deletions server/api/icons/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const fse = require('fs-extra');
const sharp = require('sharp');
const status = require('http-status-codes');
const config = require('georap-config');
const symbolPosition = require('./symbolPosition');
const templateConfig = config.markerTemplates;

const markersBase = path.join(config.staticDir, 'images', 'markers');
const templatesBase = path.join(markersBase, 'templates');
Expand Down Expand Up @@ -47,12 +49,15 @@ exports.getOrGenerate = function (req, res, next) {
}
// else generate the icon.

// Analyze the template name better
const templateParts = templateName.split('_');
const markerSize = templateParts[2];

// Construct file paths
const templatePath = path.join(templatesBase, templateName + '.png');
const symbolPath = path.join(symbolsBase, symbolName + '.png');
// Path for a child marker to denote a hidden location(s)
let childPath = null;
if (childStatus !== 'none') {
const childName = templateConfig[childStatus].default.sm;
childPath = path.join(templatesBase, childName + '.png');
}

fse.pathExists(templatePath, (errxt, templateExists) => {
if (errxt) {
Expand Down Expand Up @@ -86,57 +91,49 @@ exports.getOrGenerate = function (req, res, next) {
return res.status(status.NOT_FOUND).send(msgs);
}

// Select images to merge.
const compositeParts = [];
// Position the symbol according to template size
switch (markerSize) {
case 'md':
compositeParts.push({
input: symbolPath,
});
break;
case 'lg':
const templateImage = sharp(templatePath);
// Read template size to position the symbol.
templateImage
.metadata()
.then((metadata) => {
// Find alignment for symbol.
const templateSize = {
width: metadata.width,
height: metadata.height,
};
const symbolSize = { width: 22, height: 40 };
const pos = symbolPosition(templateSize, symbolSize);

// Select images to merge.
const compositeParts = [];
// Add symbol on the marker
compositeParts.push({
input: symbolPath,
top: 9,
left: 8,
top: pos.top,
left: pos.left,
});
break;
case 'sm':
compositeParts.push({
input: symbolPath,
// TODO top left
});
break;
default:
compositeParts.push({
input: symbolPath,
});
}

// Merge a sub-location
if (childStatus !== 'none') {
const childTemplate = config.markerTemplates[childStatus].default.sm;
const childPath = path.join(templatesBase, childTemplate + '.png');
compositeParts.push({
input: childPath,
gravity: 'southeast',
});
}

sharp(templatePath)
.composite(compositeParts)
.png()
.toFile(iconPath, (errf) => {
if (errf) {
return next(errf);
// Add a child marker to denote a hidden location(s)
if (childPath) {
compositeParts.push({
input: childPath,
gravity: 'southeast',
});
}

return res.sendFile(iconPath, sendFileOptions, (errs) => {
if (errs) {
return next(errs);
}
});
templateImage
.composite(compositeParts)
.png()
.toFile(iconPath, (errf) => {
if (errf) {
return next(errf);
}

return res.sendFile(iconPath, sendFileOptions, (errs) => {
if (errs) {
return next(errs);
}
});
});
});
});
});
Expand Down
Loading