<commit_before>/*
 * angular-errorhandler
 * Copyright (C)2015 Martin Reinhardt
 * https://github.com/hypery2k/angular-errorhandler
 *
 * Version: 0.0.5
 * License: MIT
 */

var core = angular.module('ngErrorHandler.core', []);
var ui = angular.module('ngErrorHandler.ui', []);

// Core

// TODO move to config for translation
core.constant('httpErrors', {
    0: 'Der Server ist nicht erreichbar..',
    404: 'Dieser Dienst existiert nicht.',
    405: 'Zugriffsfehler.',
    500: 'Unbekannte Serverfehler.'
});

core.constant('errorHandlerConfig', {
    model: {
        alerts: 'alerts'
    },
    customErrorHandler: false,
    templateUrl: 'holi-error-handler-ui/error-handler-config.ng.html',
    template: '<alert ng-repeat=\"alert in alerts\" type=\"{{alert.type}}\" close=\"alerts.splice($index, 1)\">{{::alert.msg}}</alert>',
    feedbackAttach: false
});

core.provider('errorHandlerService', function () {
    'use strict';

    // Wrap a single function [func] in another function that handles both synchronous and asynchonous errors.
    function decorate($injector, obj, func) {
        return angular.extend(function () {
            var handler = $injector.get('errorHandlerService');
            return handler.call(func, obj, arguments);
        }, func);
    }

    // Decorate all functions of the service [$delegate] with error handling. This function should be used as decorator
    // function in a call to $provide.decorator().
    var decorator = ['$delegate', '$injector', function ($delegate, $injector) {
        // Loop over all functions in $delegate and wrap these functions using the [decorate] functions above.
        for (var prop in $delegate) {
            if (angular.isFunction($delegate[prop])) {
                $delegate[prop] = decorate($injector, $delegate, $delegate[prop]);
            }
        }
        return $delegate;
    }];

    // The actual service:
    return {
        // Decorate the mentioned [services] with automatic error handling.
        decorate: function ($provide, services) {
            angular.forEach(services, function (service) {
                $provide.decorator(service, decorator);
            });
        },

        $get: function ($log, $injector, feedbackUI, errorHandlerConfig, httpErrors) {

            var handler = {

                // The list of errors.
                errors: [],

                resolveErrorCode: function (func, err, callback) {
                    // This is a very limited error handler... you would probably want to check for user-friendly error messages
                    // that were returned by the server, etc, etc, etc. Our original code contains a lot of checks and handling
                    // of error messages to create the "perfect" error message for our users, you should probably do the same. :)
                    if (err) {

                        if (errorHandlerConfig.customErrorHandler) {
                            $injector.get(errorHandlerConfig.customErrorHandler).resolve(err, callback);

                        } else {
                            if (err && !angular.isUndefined(err.status)) {
                                // A lot of errors occur in relation to HTTP calls... translate these into user-friendly msgs.
                                err = httpErrors[err.status];
                            } else if (err && err.message) {
                                // Exceptions are unwrapped.
                                err = err.message;
                            }
                            if (!angular.isString(err)) {
                                err = 'Ein unbekannter Fehler ist aufgetreten.';
                            }

                            // Use the context provided by the service.
                            if (func && func.description) {
                                err = 'Aufruf zu ' + func.description + ' war fehlerhaft.';
                            }
                            $log.error('Es ist ein Fehler aufgetreten: ' + err);
                            callback(err);
                        }

                    }
                },
                // Report the error [err] in relation to the function [func].
                funcError: function (func, err) {
                    handler.resolveErrorCode(func, err, function (msg) {
                        if (errorHandlerConfig.feedbackAttach) {
                            feedbackUI.appendErrorMsg(msg);
                        }
                        handler.errors.push(msg);
                    });

                },

                // Call the provided function [func] with the provided [args] and error handling enabled.
                call: function (func, self, args) {
                    $log.debug('Function called: ', (func.name || func));

                    var result;
                    try {
                        result = func.apply(self, args);
                    } catch (err) {
                        // Catch synchronous errors.
                        handler.funcError(func, err);
                        throw err;
                    }

                    // Catch asynchronous errors.
                    var promise = result && result.$promise || result;
                    if (promise && angular.isFunction(promise.then) && angular.isFunction(promise['catch'])) {
                        // promise is a genuine promise, so we call [handler.async].
                        handler.async(func, promise);
                    }

                    return result;
                },

                // Automatically record rejections of the provided [promise].
                async: function (func, promise) {
                    promise['catch'](function (err) {
                        handler.funcError(func, err);
                    });
                    return promise;
                }
            };

            return handler;
        }
    };
});

core.factory('httpErrorInterceptor', function () {
    'use strict';

    return {
        request: function (config) {
            // 3 seconds timeout
            // TODO move to config
            config.timeout = 3000;
            return config;
        }
    };
});

core.config(function ($provide, $httpProvider) {
    'use strict';

    // adding interceptor, e.g. for timeouts ...
    $httpProvider.interceptors.push('httpErrorInterceptor');

    // configure exception logger
    $provide.decorator('$exceptionHandler', ['$delegate', function ($delegate) {
        return function (exception, cause) {
            $delegate(exception, cause);
        };
    }]);
});

// UI

ui.factory('feedbackUI', function (errorHandlerConfig, $timeout, $rootScope) {
        'use strict';

        // PUBLIC API

        return {
            appendErrorMsg: function (msg) {
                if (!$rootScope[errorHandlerConfig.model.alerts]) {
                    $rootScope[errorHandlerConfig.model.alerts] = [];
                }
                $rootScope[errorHandlerConfig.model.alerts].push({
                    type: 'danger',
                    msg: msg
                });
            },
            appendInfoMsg: function (msg) {
                if (!$rootScope[errorHandlerConfig.model.alerts]) {
                    $rootScope[errorHandlerConfig.model.alerts] = [];
                }
                $rootScope[errorHandlerConfig.model.alerts].push({
                    type: 'info',
                    msg: msg
                });
            }
        };
    }
);

ui.directive('uiErrorHandler', function ($rootScope, errorHandlerConfig) {
    'use strict';

    return {
        restrict: 'A',
        compile: function ($element) {
            // Class should be added here to prevent an animation delay error.
            $element.append(errorHandlerConfig.template);
        }
    };
});

ui.run(function ($document, errorHandlerConfig, $templateCache) {
    'use strict';

    // trigger directive
    $document.find('.header').attr('ui-error-handler', '');

    if (errorHandlerConfig.template) {
        // Swap the builtin template with the custom template.
        // Create a magic cache key and place the template in the cache.
        errorHandlerConfig.templateUrl = '$$angular-errorhandler-template$$';
        $templateCache.put(errorHandlerConfig.templateUrl, errorHandlerConfig.template);
    }
});<commit_msg>Implement #5<commit_after>/*
 * angular-errorhandler
 * Copyright (C)2015 Martin Reinhardt
 * https://github.com/hypery2k/angular-errorhandler
 *
 * Version: 0.0.5
 * License: MIT
 */

var core = angular.module('ngErrorHandler.core', []);
var ui = angular.module('ngErrorHandler.ui', []);

// Core

// TODO move to config for translation
core.constant('httpErrors', {
    0: 'Der Server ist nicht erreichbar..',
    404: 'Dieser Dienst existiert nicht.',
    405: 'Zugriffsfehler.',
    500: 'Unbekannte Serverfehler.'
});

core.constant('errorHandlerConfig', {
    model: {
        alerts: 'alerts'
    },
    customErrorHandler: false,
    templateUrl: 'holi-error-handler-ui/error-handler-config.ng.html',
    template: '<alert ng-repeat=\"alert in alerts\" type=\"{{alert.type}}\" close=\"alerts.splice($index, 1)\">{{::alert.msg}}</alert>',
    feedbackAttach: false
});

core.provider('errorHandlerService', function () {
    'use strict';

    // Wrap a single function [func] in another function that handles both synchronous and asynchonous errors.
    function decorate($injector, obj, func) {
        return angular.extend(function () {
            var handler = $injector.get('errorHandlerService');
            return handler.call(func, obj, arguments);
        }, func);
    }

    // Decorate all functions of the service [$delegate] with error handling. This function should be used as decorator
    // function in a call to $provide.decorator().
    var decorator = ['$delegate', '$injector', function ($delegate, $injector) {
        // Loop over all functions in $delegate and wrap these functions using the [decorate] functions above.
        for (var prop in $delegate) {
            if (angular.isFunction($delegate[prop])) {
                $delegate[prop] = decorate($injector, $delegate, $delegate[prop]);
            }
        }
        return $delegate;
    }];

    // The actual service:
    return {
        // Decorate the mentioned [services] with automatic error handling.
        decorate: function ($provide, services) {
            angular.forEach(services, function (service) {
                $provide.decorator(service, decorator);
            });
        },

        $get: function ($log, $injector, feedbackUI, errorHandlerConfig, httpErrors) {

            var handler = {

                // The list of errors.
                errors: [],

                resolveErrorCode: function (func, err, callback) {
                    // This is a very limited error handler... you would probably want to check for user-friendly error messages
                    // that were returned by the server, etc, etc, etc. Our original code contains a lot of checks and handling
                    // of error messages to create the "perfect" error message for our users, you should probably do the same. :)
                    if (err) {

                        if (errorHandlerConfig.customErrorHandler) {
                            $injector.get(errorHandlerConfig.customErrorHandler).resolve(err, callback);

                        } else {
                            if (err && !angular.isUndefined(err.status)) {
                                // A lot of errors occur in relation to HTTP calls... translate these into user-friendly msgs.
                                err = httpErrors[err.status];
                            } else if (err && err.message) {
                                // Exceptions are unwrapped.
                                err = err.message;
                            }
                            if (!angular.isString(err)) {
                                err = 'Ein unbekannter Fehler ist aufgetreten.';
                            }

                            // Use the context provided by the service.
                            if (func && func.description) {
                                err = 'Aufruf zu ' + func.description + ' war fehlerhaft.';
                            }
                            $log.error('Es ist ein Fehler aufgetreten: ' + err);
                            callback(err);
                        }

                    }
                },
                // Report the error [err] in relation to the function [func].
                funcError: function (func, err) {
                    handler.resolveErrorCode(func, err, function (msg) {
                        if (errorHandlerConfig.feedbackAttach) {
                            feedbackUI.appendErrorMsg(msg);
                        }
                        handler.errors.push(msg);
                    });

                },

                // Call the provided function [func] with the provided [args] and error handling enabled.
                call: function (func, self, args) {
                    $log.debug('Function called: ', (func.name || func));

                    var result;
                    try {
                        result = func.apply(self, args);
                    } catch (err) {
                        // Catch synchronous errors.
                        handler.funcError(func, err);
                        throw err;
                    }

                    // Catch asynchronous errors.
                    var promise = result && result.$promise || result;
                    if (promise && angular.isFunction(promise.then) && angular.isFunction(promise['catch'])) {
                        // promise is a genuine promise, so we call [handler.async].
                        handler.async(func, promise);
                    }

                    return result;
                },

                // Automatically record rejections of the provided [promise].
                async: function (func, promise) {
                    promise['catch'](function (err) {
                        handler.funcError(func, err);
                    });
                    return promise;
                }
            };

            return handler;
        }
    };
});

core.factory('httpErrorInterceptor', function () {
    'use strict';

    return {
        request: function (config) {
            // 3 seconds timeout
            // TODO move to config
            config.timeout = 3000;
            return config;
        }
    };
});

core.config(function ($provide, $httpProvider) {
    'use strict';

    // adding interceptor, e.g. for timeouts ...
    $httpProvider.interceptors.push('httpErrorInterceptor');

    // configure exception logger
    $provide.decorator('$exceptionHandler', ['$delegate', function ($delegate) {
        return function (exception, cause) {
            $delegate(exception, cause);
        };
    }]);
});

// UI

ui.factory('feedbackUI', function (errorHandlerConfig, $timeout, $rootScope) {
        'use strict';

        // PUBLIC API

        return {
            appendErrorMsg: function (msg) {
                if (!$rootScope[errorHandlerConfig.model.alerts]) {
                    $rootScope[errorHandlerConfig.model.alerts] = [];
                }
                $rootScope[errorHandlerConfig.model.alerts].push({
                    type: 'danger',
                    msg: msg
                });
            },
            appendInfoMsg: function (msg) {
                if (!$rootScope[errorHandlerConfig.model.alerts]) {
                    $rootScope[errorHandlerConfig.model.alerts] = [];
                }
                $rootScope[errorHandlerConfig.model.alerts].push({
                    type: 'info',
                    msg: msg
                });
            }
        };
    }
);

ui.directive('uiErrorHandler', function ($rootScope, errorHandlerConfig) {
    'use strict';

    return {
        restrict: 'A',
        compile: function ($element) {
            // Class should be added here to prevent an animation delay error.
            $element.append(errorHandlerConfig.template);
        }
    };
});

ui.run(function ($rootScope, $document, errorHandlerConfig, $templateCache) {
    'use strict';

    // register listener to watch route changes
    $rootScope.$on('$routeChangeStart', function () {
        // reset alerts
        $rootScope[errorHandlerConfig.model.alerts] = [];
    });

    // trigger directive
    $document.find('.header').attr('ui-error-handler', '');

    if (errorHandlerConfig.template) {
        // Swap the builtin template with the custom template.
        // Create a magic cache key and place the template in the cache.
        errorHandlerConfig.templateUrl = '$$angular-errorhandler-template$$';
        $templateCache.put(errorHandlerConfig.templateUrl, errorHandlerConfig.template);
    }
});<|endoftext|>


<commit_before>import { Router } from 'express'
import Measure from '../models/measure'
import { r } from '../db'
import { densityToBrix } from '../helpers/transformations'

export default ({ config, db }) => {
  let router = Router({ mergeParams: true })

  router.param('measure', (req, resp, next, id) => {
    req.measure = Measure.get(id)
    next()
  })

  router.get('/', async ({ reaction, params }, res) => {
    try {
      res.json((await reaction.getJoin({
        measures: {
          _apply (sequence) {
            return sequence.orderBy(r.desc('time'))
          }
        }})).measures || [])
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  router.post('/', async ({ reaction, body }, res) => {
    try {
      var measure = {}
      measure.temperature = body.temperature
      measure.time = new Date()
      measure.density = body.density
      measure.ph = body.ph
      const brix = densityToBrix(body.density)
      measure.brix = brix
      measure.alcoholicContents = 46
      await Measure.save(measure)
      res.json(await reaction.addRelation('measures', await measure))
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  router.delete('/:measure', async ({ reaction, measure }, res) => {
    try {
      res.json(await reaction.removeRelation('measures', await measure))
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  router.get('/graph', async ({ reaction, params }, res) => {
    try {
      var measuresModel = await reaction.getJoin({
        measures: {
          _apply (sequence) {
            return sequence.orderBy(r.desc('time'))
          }
        }
      })
      var measures = measuresModel.measures
      var brixData = measures.map((measure, index) => {
        return { x: index, y: measure.brix }
      })
      var glData = measures.map((measure, index) => {
        return { x: index, y: measure.alcoholicContents }
      })
      var array = [glData, brixData]
      res.json(array)
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  return router
}
<commit_msg>Adicionando rotina para calcular grau GL<commit_after>import { Router } from 'express'
import Measure from '../models/measure'
import { r } from '../db'
import { densityToBrix, actualGLDegree } from '../helpers/transformations'

export default ({ config, db }) => {
  let router = Router({ mergeParams: true })

  router.param('measure', (req, resp, next, id) => {
    req.measure = Measure.get(id)
    next()
  })

  router.get('/', async ({ reaction, params }, res) => {
    try {
      res.json((await reaction.getJoin({
        measures: {
          _apply (sequence) {
            return sequence.orderBy(r.desc('time'))
          }
        }})).measures || [])
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  router.post('/', async ({ reaction, body }, res) => {
    try {
      var measure = {}
      measure.temperature = body.temperature
      measure.time = new Date()
      measure.density = body.density
      measure.ph = body.ph
      const brix = densityToBrix(body.density)
      measure.brix = brix
      var measuresModel = await reaction.getJoin({
        measures: {
          _apply (sequence) {
            return sequence.orderBy(r.desc('time'))
          }
        }
      })
      var measures = measuresModel.measures
      if (measures.length >= 1) {
        var lastDensity = measures[0].density
        var actualGL = actualGLDegree(lastDensity, body.density)
        console.log(measures[0].alcoholicContents, actualGL)
        measure.alcoholicContents = measures[0].alcoholicContents + (actualGL * 1)
      } else {
        measure.alcoholicContents = 0
      }
      await Measure.save(measure)
      res.json(await reaction.addRelation('measures', await measure))
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  router.delete('/:measure', async ({ reaction, measure }, res) => {
    try {
      res.json(await reaction.removeRelation('measures', await measure))
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  router.get('/graph', async ({ reaction, params }, res) => {
    try {
      var measuresModel = await reaction.getJoin({
        measures: {
          _apply (sequence) {
            return sequence.orderBy(r.desc('time'))
          }
        }
      })
      var measures = measuresModel.measures
      var brixData = measures.map((measure, index) => {
        return { x: index, y: measure.brix }
      })
      var glData = measures.map((measure, index) => {
        return { x: index, y: measure.alcoholicContents }
      })
      var array = [glData, brixData]
      res.json(array)
    } catch (err) {
      res.status(404).json({ error: err.name + ': ' + err.message })
    }
  })

  return router
}
<|endoftext|>


<commit_before>var marked   = require('marked'),
    moment   = require('moment'),
    mongoose = require('mongoose'),
    Category = mongoose.model('category'),
    Post     = mongoose.model('post');

/**
 * List posts in given category
 */
exports.category = function(req, res) {
    var slug = req.param('slug');
    Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
        Category.findOne({ slug: slug }).exec(function(err, category) {
            var perPage   = 10,
                pageRange = 5,
                page      = req.param('page') || 1,
                q         = req.param('q') || '',
                criteria  = q ? { title: new RegExp(q, 'i') } : {};

            criteria.status     = 'activated';
            criteria.categories = { $in: [category._id] };

            Post.count(criteria, function(err, total) {
                Post.find(criteria).sort({ created_date: -1 }).skip((page - 1) * perPage).limit(perPage).exec(function(err, posts) {
                    if (err) {
                        posts = [];
                    }

                    var numPages   = Math.ceil(total / perPage),
                        startRange = (page == 1) ? 1 : pageRange * Math.floor((page - 1) / pageRange) + 1,
                        endRange   = startRange + pageRange;

                    if (endRange > numPages) {
                        endRange = numPages;
                    }

                    res.render('partial/posts', {
                        title: category.name,
                        categories: categories,
                        category: category,
                        req: req,
                        moment: moment,
                        total: total,
                        posts: posts,

                        // Criteria
                        q: q,
                        criteria: criteria,

                        // Pagination
                        page: page,
                        numPages: numPages,
                        startRange: startRange,
                        endRange: endRange
                    });
                });
            });
        });
    });
};

/**
 * Search for posts
 */
exports.search = function(req, res) {
    var slug = req.param('slug');
    Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
        var perPage   = 10,
            pageRange = 5,
            page      = req.param('page') || 1,
            q         = req.param('q') || '',
            criteria  = q ? { title: new RegExp(q, 'i') } : {};

        criteria.status = 'activated';

        Post.count(criteria, function(err, total) {
            Post.find(criteria).sort({ created_date: -1 }).skip((page - 1) * perPage).limit(perPage).exec(function(err, posts) {
                if (err) {
                    posts = [];
                }

                var numPages   = Math.ceil(total / perPage),
                    startRange = (page == 1) ? 1 : pageRange * Math.floor((page - 1) / pageRange) + 1,
                    endRange   = startRange + pageRange;

                if (endRange > numPages) {
                    endRange = numPages;
                }

                res.render('partial/posts', {
                    title: 'Search for ' + q,
                    categories: categories,
                    req: req,
                    moment: moment,
                    total: total,
                    posts: posts,

                    // Criteria
                    q: q,
                    criteria: criteria,

                    // Pagination
                    page: page,
                    numPages: numPages,
                    startRange: startRange,
                    endRange: endRange
                });
            });
        });
    });
};

/**
 * View post details
 */
exports.view = function(req, res) {
    var slug = req.param('slug');
    Post.findOne({ slug: slug }).populate('categories').exec(function(err, post) {
        res.render('post/view', {
            title: post.title,
            marked: marked,
            moment: moment,
            post: post,
            signedIn: (req.session && req.session.user),
            siteUrl: req.protocol + '://' + req.get('host')
        });
    });
};

/**
 * List posts
 */
exports.index = function(req, res) {
    var perPage       = 10,
        pageRange     = 5,
        page          = req.param('page') || 1,
        status        = req.param('status'),
        q             = req.param('q') || '',
        sortBy        = req.param('sort') || '-created_date',
        criteria      = q ? { title: new RegExp(q, 'i') } : {},
        sortCriteria  = {},
        sortDirection = ('-' == sortBy.substr(0, 1)) ? -1 : 1;

    sortBy = '-' == sortBy.substr(0, 1) ? sortBy.substr(1) : sortBy;
    sortCriteria[sortBy] = sortDirection;

    if (status) {
        criteria.status = status;
    }

    Post.count(criteria, function(err, total) {
        Post.find(criteria).sort(sortCriteria).skip((page - 1) * perPage).limit(perPage).exec(function(err, posts) {
            if (err) {
                posts = [];
            }

            var numPages   = Math.ceil(total / perPage),
                startRange = (page == 1) ? 1 : pageRange * Math.floor((page - 1) / pageRange) + 1,
                endRange   = startRange + pageRange;

            if (endRange > numPages) {
                endRange = numPages;
            }

            res.render('post/index', {
                title: 'Posts',
                req: req,
                moment: moment,
                total: total,
                posts: posts,

                // Criteria
                q: q,
                criteria: criteria,
                sortBy: sortBy,
                sortDirection: sortDirection,

                // Pagination
                page: page,
                numPages: numPages,
                startRange: startRange,
                endRange: endRange
            });
        });
    });
};

/**
 * Activate/deactivate post
 */
exports.activate = function(req, res) {
    var id = req.body.id;
    Post
        .findOne({ _id: id })
        .exec(function(err, post) {
            if (err || !post) {
                return res.json({ result: 'error'});
            }
            post.status = (post.status == 'activated') ? 'deactivated' : 'activated';
            post.save(function(err) {
                return res.json({ result: err ? 'error' : 'ok' });
            });
        });
};

/**
 * Add new post
 */
exports.add = function(req, res) {
    if ('post' == req.method.toLowerCase()) {
        var post = new Post({
            title: req.body.title,
            slug: req.body.slug,
            content: req.body.content,
            created_user: {
                username: req.session.user.username,
                full_name: req.session.user.full_name
            },
            categories: req.body.categories || []
        });

        if (req.body.publish) {
            post.status = 'activated';
        }
        if (req.body.draft) {
            post.status = 'draft';
        }

        post.prev_categories = null;
        post.save(function(err) {
            if (req.xhr) {
                return res.json({
                    result: err ? 'error' : 'ok',
                    id: err ? null : post._id
                });
            } else {
                req.flash(err ? 'error'                  : 'success',
                          err ? 'Could not add the post' : 'The post has been added successfully');
                return res.redirect(err ? '/admin/post/add' : '/admin/post/edit/' + post._id);
            }
        });
    } else {
        var config = req.app.get('config');
        Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
            res.render('post/add', {
                title: 'Write new post',
                autoSave: config.autoSave || 0,
                categories: categories,
                messages: {
                    warning: req.flash('error'),
                    success: req.flash('success')
                }
            });
        });
    }
};

/**
 * Edit post
 */
exports.edit = function(req, res) {
    var id     = req.param('id'),
        config = req.app.get('config');
    Post.findOne({ _id: id }).exec(function(err, post) {
        if ('post' == req.method.toLowerCase()) {
            // Backup current categories
            post.prev_categories = post.categories;

            post.title           = req.body.title;
            post.slug            = req.body.slug;
            post.content         = req.body.content;
            post.categories      = req.body.categories || [];
            post.updated_date    = new Date();
            post.updated_user    = {
                username: req.session.user.username,
                full_name: req.session.user.full_name
            };

            if (req.body.publish) {
                post.status = 'activated';
            }
            if (req.body.draft) {
                post.status = 'draft';
            }

            post.save(function(err) {
                // TODO: Export to PDF as background job

                if (req.xhr) {
                    return res.json({ result: err ? 'error' : 'ok' });
                }
                req.flash(err ? 'error'                     : 'success',
                          err ? 'Could not update the post' : 'The post has been updated successfully');
                return res.redirect('/admin/post/edit/' + id);
            });
        } else {
            Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
                res.render('post/edit', {
                    title: 'Edit post',
                    autoSave: config.autoSave || 0,
                    categories: categories,
                    messages: {
                        warning: req.flash('error'),
                        success: req.flash('success')
                    },
                    post: post
                });
            });
        }
    });
};

/**
 * Remove post
 */
exports.remove = function(req, res) {
    var id = req.body.id;
    Post
        .findOne({ _id: id })
        .exec(function(err, post) {
            if (err || !post) {
                return res.json({ result: 'error'});
            }
            post.remove(function(err) {
                return res.json({ result: err ? 'error' : 'ok' });
            });
        });
};

/**
 * Generate slug
 */
exports.slug = function(req, res) {
    var post = new Post({
        title: req.body.title
    });
    if (req.body.id) {
        post._id = req.body.id;
    }
    Post.generateSlug(post, function(slug) {
        res.json({ slug: slug });
    });
};<commit_msg>Fix issue #3<commit_after>var marked   = require('marked'),
    moment   = require('moment'),
    mongoose = require('mongoose'),
    Category = mongoose.model('category'),
    Post     = mongoose.model('post');

/**
 * List posts in given category
 */
exports.category = function(req, res) {
    var slug = req.param('slug');
    Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
        Category.findOne({ slug: slug }).exec(function(err, category) {
            var perPage   = 10,
                pageRange = 5,
                page      = req.param('page') || 1,
                q         = req.param('q') || '',
                criteria  = q ? { title: new RegExp(q, 'i') } : {};

            criteria.status     = 'activated';
            criteria.categories = { $in: [category._id] };

            Post.count(criteria, function(err, total) {
                Post.find(criteria).sort({ created_date: -1 }).skip((page - 1) * perPage).limit(perPage).exec(function(err, posts) {
                    if (err) {
                        posts = [];
                    }

                    var numPages   = Math.ceil(total / perPage),
                        startRange = (page == 1) ? 1 : pageRange * Math.floor((page - 1) / pageRange) + 1,
                        endRange   = startRange + pageRange;

                    if (endRange > numPages) {
                        endRange = numPages;
                    }

                    res.render('partial/posts', {
                        title: category.name,
                        categories: categories,
                        category: category,
                        req: req,
                        moment: moment,
                        total: total,
                        posts: posts,

                        // Criteria
                        q: q,
                        criteria: criteria,

                        // Pagination
                        page: page,
                        numPages: numPages,
                        startRange: startRange,
                        endRange: endRange
                    });
                });
            });
        });
    });
};

/**
 * Search for posts
 */
exports.search = function(req, res) {
    var slug = req.param('slug');
    Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
        var perPage   = 10,
            pageRange = 5,
            page      = req.param('page') || 1,
            q         = req.param('q') || '',
            criteria  = q ? { title: new RegExp(q, 'i') } : {};

        criteria.status = 'activated';

        Post.count(criteria, function(err, total) {
            Post.find(criteria).sort({ created_date: -1 }).skip((page - 1) * perPage).limit(perPage).exec(function(err, posts) {
                if (err) {
                    posts = [];
                }

                var numPages   = Math.ceil(total / perPage),
                    startRange = (page == 1) ? 1 : pageRange * Math.floor((page - 1) / pageRange) + 1,
                    endRange   = startRange + pageRange;

                if (endRange > numPages) {
                    endRange = numPages;
                }

                res.render('partial/posts', {
                    title: 'Search for ' + q,
                    categories: categories,
                    req: req,
                    moment: moment,
                    total: total,
                    posts: posts,

                    // Criteria
                    q: q,
                    criteria: criteria,

                    // Pagination
                    page: page,
                    numPages: numPages,
                    startRange: startRange,
                    endRange: endRange
                });
            });
        });
    });
};

/**
 * View post details
 */
exports.view = function(req, res) {
    var slug = req.param('slug');
    Post.findOne({ slug: slug }).populate('categories').exec(function(err, post) {
        res.render('post/view', {
            title: post.title,
            marked: marked,
            moment: moment,
            post: post,
            signedIn: (req.session && req.session.user),
            siteUrl: req.protocol + '://' + req.get('host')
        });
    });
};

/**
 * List posts
 */
exports.index = function(req, res) {
    var perPage       = 10,
        pageRange     = 5,
        page          = req.param('page') || 1,
        status        = req.param('status'),
        q             = req.param('q') || '',
        sortBy        = req.param('sort') || '-created_date',
        criteria      = q ? { title: new RegExp(q, 'i') } : {},
        sortCriteria  = {},
        sortDirection = ('-' == sortBy.substr(0, 1)) ? -1 : 1;

    sortBy = '-' == sortBy.substr(0, 1) ? sortBy.substr(1) : sortBy;
    sortCriteria[sortBy] = sortDirection;

    if (status) {
        criteria.status = status;
    }

    Post.count(criteria, function(err, total) {
        Post.find(criteria).sort(sortCriteria).skip((page - 1) * perPage).limit(perPage).exec(function(err, posts) {
            if (err) {
                posts = [];
            }

            var numPages   = Math.ceil(total / perPage),
                startRange = (page == 1) ? 1 : pageRange * Math.floor((page - 1) / pageRange) + 1,
                endRange   = startRange + pageRange;

            if (endRange > numPages) {
                endRange = numPages;
            }

            res.render('post/index', {
                title: 'Posts',
                req: req,
                moment: moment,
                total: total,
                posts: posts,

                // Criteria
                q: q,
                criteria: criteria,
                sortBy: sortBy,
                sortDirection: sortDirection,

                // Pagination
                page: page,
                numPages: numPages,
                startRange: startRange,
                endRange: endRange
            });
        });
    });
};

/**
 * Activate/deactivate post
 */
exports.activate = function(req, res) {
    var id = req.body.id;
    Post
        .findOne({ _id: id })
        .exec(function(err, post) {
            if (err || !post) {
                return res.json({ result: 'error'});
            }
            post.status          = (post.status == 'activated') ? 'deactivated' : 'activated';
            post.prev_categories = post.categories;
            post.save(function(err) {
                return res.json({ result: err ? 'error' : 'ok' });
            });
        });
};

/**
 * Add new post
 */
exports.add = function(req, res) {
    if ('post' == req.method.toLowerCase()) {
        var post = new Post({
            title: req.body.title,
            slug: req.body.slug,
            content: req.body.content,
            created_user: {
                username: req.session.user.username,
                full_name: req.session.user.full_name
            },
            categories: req.body.categories || []
        });

        if (req.body.publish) {
            post.status = 'activated';
        }
        if (req.body.draft) {
            post.status = 'draft';
        }

        post.prev_categories = null;
        post.save(function(err) {
            if (req.xhr) {
                return res.json({
                    result: err ? 'error' : 'ok',
                    id: err ? null : post._id
                });
            } else {
                req.flash(err ? 'error'                  : 'success',
                          err ? 'Could not add the post' : 'The post has been added successfully');
                return res.redirect(err ? '/admin/post/add' : '/admin/post/edit/' + post._id);
            }
        });
    } else {
        var config = req.app.get('config');
        Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
            res.render('post/add', {
                title: 'Write new post',
                autoSave: config.autoSave || 0,
                categories: categories,
                messages: {
                    warning: req.flash('error'),
                    success: req.flash('success')
                }
            });
        });
    }
};

/**
 * Edit post
 */
exports.edit = function(req, res) {
    var id     = req.param('id'),
        config = req.app.get('config');
    Post.findOne({ _id: id }).exec(function(err, post) {
        if ('post' == req.method.toLowerCase()) {
            // Backup current categories
            post.prev_categories = post.categories;

            post.title           = req.body.title;
            post.slug            = req.body.slug;
            post.content         = req.body.content;
            post.categories      = req.body.categories || [];
            post.updated_date    = new Date();
            post.updated_user    = {
                username: req.session.user.username,
                full_name: req.session.user.full_name
            };

            if (req.body.publish) {
                post.status = 'activated';
            }
            if (req.body.draft) {
                post.status = 'draft';
            }

            post.save(function(err) {
                // TODO: Export to PDF as background job

                if (req.xhr) {
                    return res.json({ result: err ? 'error' : 'ok' });
                }
                req.flash(err ? 'error'                     : 'success',
                          err ? 'Could not update the post' : 'The post has been updated successfully');
                return res.redirect('/admin/post/edit/' + id);
            });
        } else {
            Category.find({}).sort({ position: 1 }).exec(function(err, categories) {
                res.render('post/edit', {
                    title: 'Edit post',
                    autoSave: config.autoSave || 0,
                    categories: categories,
                    messages: {
                        warning: req.flash('error'),
                        success: req.flash('success')
                    },
                    post: post
                });
            });
        }
    });
};

/**
 * Remove post
 */
exports.remove = function(req, res) {
    var id = req.body.id;
    Post
        .findOne({ _id: id })
        .exec(function(err, post) {
            if (err || !post) {
                return res.json({ result: 'error'});
            }
            post.remove(function(err) {
                return res.json({ result: err ? 'error' : 'ok' });
            });
        });
};

/**
 * Generate slug
 */
exports.slug = function(req, res) {
    var post = new Post({
        title: req.body.title
    });
    if (req.body.id) {
        post._id = req.body.id;
    }
    Post.generateSlug(post, function(slug) {
        res.json({ slug: slug });
    });
};<|endoftext|>


<commit_before>/**
 * Contains the logic for connecting the modes with the website.
 *
 * @param graph the graph that belongs to these controls
 * @returns {{}}
 */
module.exports = function (graph) {

	var SAME_COLOR_MODE = {text: "Multicolor", type: "same"};
	var GRADIENT_COLOR_MODE = {text: "Multicolor", type: "gradient"};

	var modeMenu = {},
		checkboxes = [],
		colorModeSwitch;

	var dynamicLabelWidthCheckBox;
	// getter and setter for the state of color modes
	modeMenu.colorModeState = function (s) {
		if (!arguments.length) return colorModeSwitch.datum().active;
		colorModeSwitch.datum().active = s;
		return modeMenu;
	};

	modeMenu.setDynamicLabelWidth=function(val){
        dynamicLabelWidthCheckBox.property("checked",val);
	};
	// getter for checkboxes
	modeMenu.getCheckBoxContainer = function () {
		return checkboxes;
	};
	// getter for the color switch [needed? ]
	modeMenu.colorModeSwitch = function () {
		return colorModeSwitch;
	};

	/**
	 * Connects the website with the available graph modes.
	 */
	modeMenu.setup = function (pickAndPin, nodeScaling, compactNotation, colorExternals) {
		var menuEntry= d3.select("#m_modes");
		menuEntry.on("mouseover",function(){
			var searchMenu=graph.options().searchMenu();
			searchMenu.hideSearchEntries();
		});
        addCheckBoxD("labelWidth","Dynamic label width","#dynamicLabelWidth",graph.options().dynamicLabelWidth,1);
        addCheckBox("editorMode","Editing ","#editMode",graph.editorMode);
		addModeItem(pickAndPin, "pickandpin", "Pick & pin", "#pickAndPinOption", false);
		addModeItem(nodeScaling, "nodescaling", "Node scaling", "#nodeScalingOption", true);
		addModeItem(compactNotation, "compactnotation", "Compact notation", "#compactNotationOption", true);
		var container = addModeItem(colorExternals, "colorexternals", "Color externals", "#colorExternalsOption", true);
		colorModeSwitch = addExternalModeSelection(container, colorExternals);
	};
    function addCheckBoxD(identifier, modeName, selector,onChangeFunc,updateLvl) {
        var moduleOptionContainer = d3.select(selector)
            .append("div")
            .classed("checkboxContainer", true);

        var moduleCheckbox = moduleOptionContainer.append("input")
            .classed("moduleCheckbox", true)
            .attr("id", identifier + "ModuleCheckbox")
            .attr("type", "checkbox")
            .property("checked", onChangeFunc());

        moduleCheckbox.on("click", function (d) {
            var isEnabled = moduleCheckbox.property("checked");
            onChangeFunc(isEnabled);
            d3.select("#maxLabelWidthSlider").node().disabled=!isEnabled;
            d3.select("#maxLabelWidthvalueLabel").classed("disabledLabelForSlider", !isEnabled);
            d3.select("#maxLabelWidthDescriptionLabel").classed("disabledLabelForSlider", !isEnabled);

            if (updateLvl>0){
					graph.animateDynamicLabelWidth();
                // graph.lazyRefresh();
            }
        });
        moduleOptionContainer.append("label")
            .attr("for", identifier + "ModuleCheckbox")
            .text(modeName);
        if (identifier==="editorMode"){
            moduleOptionContainer.append("label")
				.attr("style","font-size:10px;padding-top:3px")
				.text("(experimental)");
		}

        dynamicLabelWidthCheckBox=moduleCheckbox;
    }

    function addCheckBox(identifier, modeName, selector,onChangeFunc) {
        var moduleOptionContainer = d3.select(selector)
            .append("div")
            .classed("checkboxContainer", true);

        var moduleCheckbox = moduleOptionContainer.append("input")
            .classed("moduleCheckbox", true)
            .attr("id", identifier + "ModuleCheckbox")
            .attr("type", "checkbox")
            .property("checked", onChangeFunc());

        moduleCheckbox.on("click", function (d) {
            var isEnabled = moduleCheckbox.property("checked");
            onChangeFunc(isEnabled);
        });
        moduleOptionContainer.append("label")
            .attr("for", identifier + "ModuleCheckbox")
            .text(modeName);
        if (identifier==="editorMode"){
            moduleOptionContainer.append("label")
                .attr("style","font-size:10px;padding-top:3px")
                .text(" (experimental)");
        }
    }

	function addModeItem(module, identifier, modeName, selector, updateGraphOnClick) {
		var moduleOptionContainer,
			moduleCheckbox;

		moduleOptionContainer = d3.select(selector)
			.append("div")
			.classed("checkboxContainer", true)
			.datum({module: module, defaultState: module.enabled()});

		moduleCheckbox = moduleOptionContainer.append("input")
			.classed("moduleCheckbox", true)
			.attr("id", identifier + "ModuleCheckbox")
			.attr("type", "checkbox")
			.property("checked", module.enabled());

		// Store for easier resetting all modes
		checkboxes.push(moduleCheckbox);

		moduleCheckbox.on("click", function (d, silent) {
			var isEnabled = moduleCheckbox.property("checked");
			d.module.enabled(isEnabled);
			if (updateGraphOnClick && silent !== true) {
				graph.executeColorExternalsModule();
				graph.executeCompactNotationModule();
				graph.lazyRefresh();
			}
		});

		moduleOptionContainer.append("label")
			.attr("for", identifier + "ModuleCheckbox")
			.text(modeName);

		return moduleOptionContainer;
	}

	function addExternalModeSelection(container, colorExternalsMode) {
		var button = container.append("button").datum({active: false}).classed("color-mode-switch", true);
		applyColorModeSwitchState(button, colorExternalsMode);

		button.on("click", function (silent) {
			var data = button.datum();
			data.active = !data.active;
			applyColorModeSwitchState(button, colorExternalsMode);
			if (colorExternalsMode.enabled() && silent !== true) {
                graph.executeColorExternalsModule();
                graph.lazyRefresh();
            }
		});

		return button;
	}

	function applyColorModeSwitchState(element, colorExternalsMode) {
		var isActive = element.datum().active;
		var activeColorMode = getColorModeByState(isActive);

		element.classed("active", isActive)
			.text(activeColorMode.text);

		if (colorExternalsMode) {
			colorExternalsMode.colorModeType(activeColorMode.type);
		}
	}

	function getColorModeByState(isActive) {
		return isActive ? GRADIENT_COLOR_MODE : SAME_COLOR_MODE;
	}

	/**
	 * Resets the modes to their default.
	 */
	modeMenu.reset = function () {
		checkboxes.forEach(function (checkbox) {
			var defaultState = checkbox.datum().defaultState,
				isChecked = checkbox.property("checked");

			if (isChecked !== defaultState) {
				checkbox.property("checked", defaultState);
				// Call onclick event handlers programmatically
				checkbox.on("click")(checkbox.datum());
			}

			// Reset the module that is connected with the checkbox
			checkbox.datum().module.reset();
		});

		// set the switch to active and simulate disabling
		colorModeSwitch.datum().active = true;
		colorModeSwitch.on("click")();
	};

	/** importer functions **/
	// setting manually the values of the filter
	// no update of the gui settings, these are updated in updateSettings
	modeMenu.setCheckBoxValue = function (id, checked) {
		for (var i = 0; i < checkboxes.length; i++) {
			var cbdId = checkboxes[i].attr("id");

			if (cbdId === id) {
				checkboxes[i].property("checked", checked);
				break;
			}
		}
	};
    modeMenu.getCheckBoxValue = function (id) {
        for (var i = 0; i < checkboxes.length; i++) {
            var cbdId = checkboxes[i].attr("id");
            if (cbdId === id) {
                return checkboxes[i].property("checked");
            }
        }
    };

	modeMenu.setColorSwitchState = function (state) {
		// need the !state because we simulate later a click
		modeMenu.colorModeState(!state);
	};
    modeMenu.setColorSwitchStateUsingURL = function (state) {
        // need the !state because we simulate later a click
        modeMenu.colorModeState(!state);
        colorModeSwitch.on("click")(true);
    };

    modeMenu.updateSettingsUsingURL = function () {
        var silent = true;
        checkboxes.forEach(function (checkbox) {
            checkbox.on("click")(checkbox.datum(), silent);
        });
    };

	modeMenu.updateSettings = function () {
		var silent = true;
		checkboxes.forEach(function (checkbox) {
			checkbox.on("click")(checkbox.datum(), silent);
		});
		// this simulates onclick and inverts its state
		colorModeSwitch.on("click")(silent);
	};
	return modeMenu;
};
<commit_msg>initial editor hint shows when changing to editor mode<commit_after>/**
 * Contains the logic for connecting the modes with the website.
 *
 * @param graph the graph that belongs to these controls
 * @returns {{}}
 */
module.exports = function (graph) {

	var SAME_COLOR_MODE = {text: "Multicolor", type: "same"};
	var GRADIENT_COLOR_MODE = {text: "Multicolor", type: "gradient"};

	var modeMenu = {},
		checkboxes = [],
		colorModeSwitch;

	var dynamicLabelWidthCheckBox;
	// getter and setter for the state of color modes
	modeMenu.colorModeState = function (s) {
		if (!arguments.length) return colorModeSwitch.datum().active;
		colorModeSwitch.datum().active = s;
		return modeMenu;
	};

	modeMenu.setDynamicLabelWidth=function(val){
        dynamicLabelWidthCheckBox.property("checked",val);
	};
	// getter for checkboxes
	modeMenu.getCheckBoxContainer = function () {
		return checkboxes;
	};
	// getter for the color switch [needed? ]
	modeMenu.colorModeSwitch = function () {
		return colorModeSwitch;
	};

	/**
	 * Connects the website with the available graph modes.
	 */
	modeMenu.setup = function (pickAndPin, nodeScaling, compactNotation, colorExternals) {
		var menuEntry= d3.select("#m_modes");
		menuEntry.on("mouseover",function(){
			var searchMenu=graph.options().searchMenu();
			searchMenu.hideSearchEntries();
		});
        addCheckBoxD("labelWidth","Dynamic label width","#dynamicLabelWidth",graph.options().dynamicLabelWidth,1);
        addCheckBox("editorMode","Editing ","#editMode",graph.editorMode);
		addModeItem(pickAndPin, "pickandpin", "Pick & pin", "#pickAndPinOption", false);
		addModeItem(nodeScaling, "nodescaling", "Node scaling", "#nodeScalingOption", true);
		addModeItem(compactNotation, "compactnotation", "Compact notation", "#compactNotationOption", true);
		var container = addModeItem(colorExternals, "colorexternals", "Color externals", "#colorExternalsOption", true);
		colorModeSwitch = addExternalModeSelection(container, colorExternals);
	};
    function addCheckBoxD(identifier, modeName, selector,onChangeFunc,updateLvl) {
        var moduleOptionContainer = d3.select(selector)
            .append("div")
            .classed("checkboxContainer", true);

        var moduleCheckbox = moduleOptionContainer.append("input")
            .classed("moduleCheckbox", true)
            .attr("id", identifier + "ModuleCheckbox")
            .attr("type", "checkbox")
            .property("checked", onChangeFunc());

        moduleCheckbox.on("click", function (d) {
            var isEnabled = moduleCheckbox.property("checked");
            onChangeFunc(isEnabled);
            d3.select("#maxLabelWidthSlider").node().disabled=!isEnabled;
            d3.select("#maxLabelWidthvalueLabel").classed("disabledLabelForSlider", !isEnabled);
            d3.select("#maxLabelWidthDescriptionLabel").classed("disabledLabelForSlider", !isEnabled);

            if (updateLvl>0){
					graph.animateDynamicLabelWidth();
                // graph.lazyRefresh();
            }
        });
        moduleOptionContainer.append("label")
            .attr("for", identifier + "ModuleCheckbox")
            .text(modeName);
        if (identifier==="editorMode"){
            moduleOptionContainer.append("label")
				.attr("style","font-size:10px;padding-top:3px")
				.text("(experimental)");
		}

        dynamicLabelWidthCheckBox=moduleCheckbox;
    }

    function addCheckBox(identifier, modeName, selector,onChangeFunc) {
        var moduleOptionContainer = d3.select(selector)
            .append("div")
            .classed("checkboxContainer", true);

        var moduleCheckbox = moduleOptionContainer.append("input")
            .classed("moduleCheckbox", true)
            .attr("id", identifier + "ModuleCheckbox")
            .attr("type", "checkbox")
            .property("checked", onChangeFunc());

        moduleCheckbox.on("click", function (d) {
            var isEnabled = moduleCheckbox.property("checked");
            onChangeFunc(isEnabled);
            if (isEnabled===true)
                graph.showEditorHintIfNeeded();
        });
        moduleOptionContainer.append("label")
            .attr("for", identifier + "ModuleCheckbox")
            .text(modeName);
        if (identifier==="editorMode"){
            moduleOptionContainer.append("label")
                .attr("style","font-size:10px;padding-top:3px")
                .text(" (experimental)");
        }
    }

	function addModeItem(module, identifier, modeName, selector, updateGraphOnClick) {
		var moduleOptionContainer,
			moduleCheckbox;

		moduleOptionContainer = d3.select(selector)
			.append("div")
			.classed("checkboxContainer", true)
			.datum({module: module, defaultState: module.enabled()});

		moduleCheckbox = moduleOptionContainer.append("input")
			.classed("moduleCheckbox", true)
			.attr("id", identifier + "ModuleCheckbox")
			.attr("type", "checkbox")
			.property("checked", module.enabled());

		// Store for easier resetting all modes
		checkboxes.push(moduleCheckbox);

		moduleCheckbox.on("click", function (d, silent) {
			var isEnabled = moduleCheckbox.property("checked");
			d.module.enabled(isEnabled);
			if (updateGraphOnClick && silent !== true) {
				graph.executeColorExternalsModule();
				graph.executeCompactNotationModule();
				graph.lazyRefresh();
			}
		});

		moduleOptionContainer.append("label")
			.attr("for", identifier + "ModuleCheckbox")
			.text(modeName);

		return moduleOptionContainer;
	}

	function addExternalModeSelection(container, colorExternalsMode) {
		var button = container.append("button").datum({active: false}).classed("color-mode-switch", true);
		applyColorModeSwitchState(button, colorExternalsMode);

		button.on("click", function (silent) {
			var data = button.datum();
			data.active = !data.active;
			applyColorModeSwitchState(button, colorExternalsMode);
			if (colorExternalsMode.enabled() && silent !== true) {
                graph.executeColorExternalsModule();
                graph.lazyRefresh();
            }
		});

		return button;
	}

	function applyColorModeSwitchState(element, colorExternalsMode) {
		var isActive = element.datum().active;
		var activeColorMode = getColorModeByState(isActive);

		element.classed("active", isActive)
			.text(activeColorMode.text);

		if (colorExternalsMode) {
			colorExternalsMode.colorModeType(activeColorMode.type);
		}
	}

	function getColorModeByState(isActive) {
		return isActive ? GRADIENT_COLOR_MODE : SAME_COLOR_MODE;
	}

	/**
	 * Resets the modes to their default.
	 */
	modeMenu.reset = function () {
		checkboxes.forEach(function (checkbox) {
			var defaultState = checkbox.datum().defaultState,
				isChecked = checkbox.property("checked");

			if (isChecked !== defaultState) {
				checkbox.property("checked", defaultState);
				// Call onclick event handlers programmatically
				checkbox.on("click")(checkbox.datum());
			}

			// Reset the module that is connected with the checkbox
			checkbox.datum().module.reset();
		});

		// set the switch to active and simulate disabling
		colorModeSwitch.datum().active = true;
		colorModeSwitch.on("click")();
	};

	/** importer functions **/
	// setting manually the values of the filter
	// no update of the gui settings, these are updated in updateSettings
	modeMenu.setCheckBoxValue = function (id, checked) {
		for (var i = 0; i < checkboxes.length; i++) {
			var cbdId = checkboxes[i].attr("id");

			if (cbdId === id) {
				checkboxes[i].property("checked", checked);
				break;
			}
		}
	};
    modeMenu.getCheckBoxValue = function (id) {
        for (var i = 0; i < checkboxes.length; i++) {
            var cbdId = checkboxes[i].attr("id");
            if (cbdId === id) {
                return checkboxes[i].property("checked");
            }
        }
    };

	modeMenu.setColorSwitchState = function (state) {
		// need the !state because we simulate later a click
		modeMenu.colorModeState(!state);
	};
    modeMenu.setColorSwitchStateUsingURL = function (state) {
        // need the !state because we simulate later a click
        modeMenu.colorModeState(!state);
        colorModeSwitch.on("click")(true);
    };

    modeMenu.updateSettingsUsingURL = function () {
        var silent = true;
        checkboxes.forEach(function (checkbox) {
            checkbox.on("click")(checkbox.datum(), silent);
        });
    };

	modeMenu.updateSettings = function () {
		var silent = true;
		checkboxes.forEach(function (checkbox) {
			checkbox.on("click")(checkbox.datum(), silent);
		});
		// this simulates onclick and inverts its state
		colorModeSwitch.on("click")(silent);
	};
	return modeMenu;
};
<|endoftext|>


<commit_before>import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import Icon from '../icon';
import InputMetaPropTypes from '../input/InputMetaPropTypes';
import NavigationBar from './NavigationBar';
import WeekDay from './WeekDay';
import { convertModifiersToClassnames, isSelectingFirstDay } from './utils';
import { DateUtils } from 'react-day-picker/lib/src/index';
import { IconCalendarSmallOutline, IconWarningBadgedSmallFilled } from '@teamleader/ui-icons';
import { TextSmall } from '../typography';
import cx from 'classnames';
import omit from 'lodash.omit';
import theme from './theme.css';

class DatePickerInputRange extends PureComponent {
  state = {
    selectedStartDate: null,
    selectedEndDate: null,
    mouseEnteredEndDate: null,
    inputHasFocus: false,
  };

  static getDerivedStateFromProps(props, state) {
    if (
      props.selectedRange !== undefined &&
      (props.selectedRange.selectedStartDate !== state.selectedStartDate ||
        props.selectedRange.selectedEndDate !== state.selectedEndDate)
    ) {
      return {
        selectedStartDate: props.selectedRange.selectedStartDate,
        selectedEndDate: props.selectedRange.selectedEndDate,
        mouseEnteredEndDate: props.selectedRange.selectedEndDate,
      };
    }

    return null;
  }

  componentWillUnmount() {
    clearTimeout(this.timeout);
  }

  focusFrom = () => {
    this.timeout = setTimeout(() => this.startDate.getInput().focus(), 100);
  };

  focusTo = () => {
    this.timeout = setTimeout(() => this.endDate.getInput().focus(), 0);
  };

  handleFromBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleFromFocus = () => {
    this.setState({ inputHasFocus: true });
  };

  handleFromChange = day => {
    this.setState({ selectedStartDate: day }, () => {
      const { selectedEndDate } = this.state;
      this.focusTo();
      this.props.onChange({ selectedStartDate: day, selectedEndDate });
    });
  };

  handleToChange = day => {
    this.setState({ selectedEndDate: day, mouseEnteredEndDate: day }, () => {
      const { selectedStartDate } = this.state;
      this.showFromMonth();
      this.props.onChange({ selectedStartDate, selectedEndDate: day });
    });
  };

  handleToBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleToFocus = () => {
    this.setState({ inputHasFocus: true });

    if (!this.state.selectedStartDate) {
      this.focusFrom();
    }
  };

  renderDayPickerInput = () => {
    const {
      className,
      dayPickerProps,
      dayPickerStartDateProps,
      dayPickerEndDateProps,
      dayPickerInputStartDateProps,
      dayPickerInputEndDateProps,
      disabled,
      inputProps,
      inputStartDateProps,
      inputEndDateProps,
      readOnly,
      size,
      ...others
    } = this.props;

    const { selectedStartDate, selectedEndDate, mouseEnteredEndDate } = this.state;

    const propsWithoutBoxProps = omitBoxProps(others);
    const dayPickerClassNames = cx(theme['date-picker'], theme['has-range'], theme[`is-${size}`], className);
    const dayPickerInputProps = omit(propsWithoutBoxProps, ['helpText', 'meta', 'onBlur', 'onChange', 'onFocus']);

    const modifiers = { from: selectedStartDate, to: mouseEnteredEndDate };
    const selectedDays = [selectedStartDate, { from: selectedStartDate, to: mouseEnteredEndDate }];

    const commonDayPickerProps = {
      className: dayPickerClassNames,
      classNames: theme,
      modifiers: convertModifiersToClassnames(modifiers, theme),
      selectedDays,
      navbarElement: <NavigationBar size={size} />,
      weekdayElement: <WeekDay size={size} />,
      ...dayPickerProps,
    };

    const commonDayPickerInputProps = {
      classNames: theme,
      hideOnDayClick: false,
      ...dayPickerInputProps,
    };

    const commonInputProps = {
      disabled: disabled || readOnly,
      ...inputProps,
    };

    return (
      <Fragment>
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { after: selectedEndDate },
            toMonth: selectedEndDate,
            ...commonDayPickerProps,
            ...dayPickerStartDateProps,
          }}
          onDayChange={this.handleFromChange}
          inputProps={{
            onBlur: this.handleFromBlur,
            onFocus: this.handleFromFocus,
            ...commonInputProps,
            ...inputStartDateProps,
          }}
          ref={el => (this.startDate = el)}
          {...commonDayPickerInputProps}
          {...dayPickerInputStartDateProps}
        />
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { before: selectedStartDate },
            month: selectedStartDate,
            fromMonth: selectedStartDate,
            onDayMouseEnter: this.handleDayMouseEnter,
            ...commonDayPickerProps,
            ...dayPickerEndDateProps,
          }}
          onDayChange={this.handleToChange}
          inputProps={{
            onBlur: this.handleToBlur,
            onFocus: this.handleToFocus,
            ...commonInputProps,
            ...inputEndDateProps,
          }}
          ref={el => (this.endDate = el)}
          {...commonDayPickerInputProps}
          {...dayPickerInputEndDateProps}
        />
      </Fragment>
    );
  };

  renderIcon = () => {
    const { inverse } = this.props;

    return (
      <Icon
        className={theme['input-icon']}
        color={inverse ? 'teal' : 'neutral'}
        tint={inverse ? 'light' : 'darkest'}
        marginHorizontal={2}
      >
        <IconCalendarSmallOutline />
      </Icon>
    );
  };

  renderHelpText = () => {
    const { helpText, inverse } = this.props;

    if (helpText) {
      return (
        <TextSmall color={inverse ? 'white' : 'neutral'} marginTop={1} soft>
          {helpText}
        </TextSmall>
      );
    }
  };

  renderValidationMessage = () => {
    return (
      <Box marginTop={2}>
        <IconWarningBadgedSmallFilled className={theme['validation-icon']} />
        <TextSmall className={theme['validation-text']} element="span" marginLeft={1}>
          {this.props.meta.error}
        </TextSmall>
      </Box>
    );
  };

  showFromMonth = () => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!selectedStartDate) {
      return;
    }

    this.endDate.getDayPicker().showMonth(DateUtils.addMonths(selectedEndDate, -1));
  };

  handleDayMouseEnter = day => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!isSelectingFirstDay(selectedStartDate, selectedEndDate, day)) {
      this.setState({
        mouseEnteredEndDate: day,
      });
    }
  };

  render() {
    const { bold, disabled, error, inverse, readOnly, size, ...others } = this.props;

    const boxProps = pickBoxProps(others);

    const classNames = cx(theme['date-picker-input-range'], theme[`is-${size}`], {
      [theme['is-bold']]: bold,
      [theme['is-disabled']]: disabled,
      [theme['is-inverse']]: inverse,
      [theme['is-read-only']]: readOnly,
      [theme['has-error']]: error,
      [theme['has-focus']]: this.state.inputHasFocus,
    });

    return (
      <Box className={classNames} {...boxProps}>

          {this.renderIcon()}
          {this.renderDayPickerInput()}

        {error ? this.renderValidationMessage() : this.renderHelpText()}
      </Box>
    );
  }
}

DatePickerInputRange.propTypes = {
  bold: PropTypes.bool,
  className: PropTypes.string,
  disabled: PropTypes.bool,
  /** The text string/element to use as error message below the input. */
  error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  helpText: PropTypes.string,
  inverse: PropTypes.bool,
  inputProps: PropTypes.object,
  inputStartDateProps: PropTypes.object,
  inputEndDateProps: PropTypes.object,
  meta: InputMetaPropTypes,
  modifiers: PropTypes.object,
  dayPickerProps: PropTypes.object,
  dayPickerStartDateProps: PropTypes.object,
  dayPickerEndDateProps: PropTypes.object,
  dayPickerInputEndDateProps: PropTypes.object,
  dayPickerInputStartDateProps: PropTypes.object,
  onChange: PropTypes.func,
  readOnly: PropTypes.bool,
  selectedRange: PropTypes.object,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  inputStartDateValue: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
  inputEndDateValue: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
};

DatePickerInputRange.defaultProps = {
  bold: false,
  disabled: false,
  inverse: false,
  readOnly: false,
  size: 'medium',
};

export default DatePickerInputRange;
<commit_msg>DatePickerInputRange: remove implementation of the 'meta' prop<commit_after>import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import Icon from '../icon';
import InputMetaPropTypes from '../input/InputMetaPropTypes';
import NavigationBar from './NavigationBar';
import WeekDay from './WeekDay';
import { convertModifiersToClassnames, isSelectingFirstDay } from './utils';
import { DateUtils } from 'react-day-picker/lib/src/index';
import { IconCalendarSmallOutline, IconWarningBadgedSmallFilled } from '@teamleader/ui-icons';
import { TextSmall } from '../typography';
import cx from 'classnames';
import omit from 'lodash.omit';
import theme from './theme.css';

class DatePickerInputRange extends PureComponent {
  state = {
    selectedStartDate: null,
    selectedEndDate: null,
    mouseEnteredEndDate: null,
    inputHasFocus: false,
  };

  static getDerivedStateFromProps(props, state) {
    if (
      props.selectedRange !== undefined &&
      (props.selectedRange.selectedStartDate !== state.selectedStartDate ||
        props.selectedRange.selectedEndDate !== state.selectedEndDate)
    ) {
      return {
        selectedStartDate: props.selectedRange.selectedStartDate,
        selectedEndDate: props.selectedRange.selectedEndDate,
        mouseEnteredEndDate: props.selectedRange.selectedEndDate,
      };
    }

    return null;
  }

  componentWillUnmount() {
    clearTimeout(this.timeout);
  }

  focusFrom = () => {
    this.timeout = setTimeout(() => this.startDate.getInput().focus(), 100);
  };

  focusTo = () => {
    this.timeout = setTimeout(() => this.endDate.getInput().focus(), 0);
  };

  handleFromBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleFromFocus = () => {
    this.setState({ inputHasFocus: true });
  };

  handleFromChange = day => {
    this.setState({ selectedStartDate: day }, () => {
      const { selectedEndDate } = this.state;
      this.focusTo();
      this.props.onChange({ selectedStartDate: day, selectedEndDate });
    });
  };

  handleToChange = day => {
    this.setState({ selectedEndDate: day, mouseEnteredEndDate: day }, () => {
      const { selectedStartDate } = this.state;
      this.showFromMonth();
      this.props.onChange({ selectedStartDate, selectedEndDate: day });
    });
  };

  handleToBlur = () => {
    this.setState({ inputHasFocus: false });
  };

  handleToFocus = () => {
    this.setState({ inputHasFocus: true });

    if (!this.state.selectedStartDate) {
      this.focusFrom();
    }
  };

  renderDayPickerInput = () => {
    const {
      className,
      dayPickerProps,
      dayPickerStartDateProps,
      dayPickerEndDateProps,
      dayPickerInputStartDateProps,
      dayPickerInputEndDateProps,
      disabled,
      inputProps,
      inputStartDateProps,
      inputEndDateProps,
      readOnly,
      size,
      ...others
    } = this.props;

    const { selectedStartDate, selectedEndDate, mouseEnteredEndDate } = this.state;

    const propsWithoutBoxProps = omitBoxProps(others);
    const dayPickerClassNames = cx(theme['date-picker'], theme['has-range'], theme[`is-${size}`], className);
    const dayPickerInputProps = omit(propsWithoutBoxProps, ['helpText', 'onBlur', 'onChange', 'onFocus']);

    const modifiers = { from: selectedStartDate, to: mouseEnteredEndDate };
    const selectedDays = [selectedStartDate, { from: selectedStartDate, to: mouseEnteredEndDate }];

    const commonDayPickerProps = {
      className: dayPickerClassNames,
      classNames: theme,
      modifiers: convertModifiersToClassnames(modifiers, theme),
      selectedDays,
      navbarElement: <NavigationBar size={size} />,
      weekdayElement: <WeekDay size={size} />,
      ...dayPickerProps,
    };

    const commonDayPickerInputProps = {
      classNames: theme,
      hideOnDayClick: false,
      ...dayPickerInputProps,
    };

    const commonInputProps = {
      disabled: disabled || readOnly,
      ...inputProps,
    };

    return (
      <Fragment>
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { after: selectedEndDate },
            toMonth: selectedEndDate,
            ...commonDayPickerProps,
            ...dayPickerStartDateProps,
          }}
          onDayChange={this.handleFromChange}
          inputProps={{
            onBlur: this.handleFromBlur,
            onFocus: this.handleFromFocus,
            ...commonInputProps,
            ...inputStartDateProps,
          }}
          ref={el => (this.startDate = el)}
          {...commonDayPickerInputProps}
          {...dayPickerInputStartDateProps}
        />
        <DayPickerInput
          dayPickerProps={{
            disabledDays: { before: selectedStartDate },
            month: selectedStartDate,
            fromMonth: selectedStartDate,
            onDayMouseEnter: this.handleDayMouseEnter,
            ...commonDayPickerProps,
            ...dayPickerEndDateProps,
          }}
          onDayChange={this.handleToChange}
          inputProps={{
            onBlur: this.handleToBlur,
            onFocus: this.handleToFocus,
            ...commonInputProps,
            ...inputEndDateProps,
          }}
          ref={el => (this.endDate = el)}
          {...commonDayPickerInputProps}
          {...dayPickerInputEndDateProps}
        />
      </Fragment>
    );
  };

  renderIcon = () => {
    const { inverse } = this.props;

    return (
      <Icon
        className={theme['input-icon']}
        color={inverse ? 'teal' : 'neutral'}
        tint={inverse ? 'light' : 'darkest'}
        marginHorizontal={2}
      >
        <IconCalendarSmallOutline />
      </Icon>
    );
  };

  renderHelpText = () => {
    const { helpText, inverse } = this.props;

    if (helpText) {
      return (
        <TextSmall color={inverse ? 'white' : 'neutral'} marginTop={1} soft>
          {helpText}
        </TextSmall>
      );
    }
  };

  renderValidationMessage = () => {
    return (
      <Box marginTop={2}>
        <IconWarningBadgedSmallFilled className={theme['validation-icon']} />
        <TextSmall className={theme['validation-text']} element="span" marginLeft={1}>
          {this.props.error}
        </TextSmall>
      </Box>
    );
  };

  showFromMonth = () => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!selectedStartDate) {
      return;
    }

    this.endDate.getDayPicker().showMonth(DateUtils.addMonths(selectedEndDate, -1));
  };

  handleDayMouseEnter = day => {
    const { selectedStartDate, selectedEndDate } = this.state;

    if (!isSelectingFirstDay(selectedStartDate, selectedEndDate, day)) {
      this.setState({
        mouseEnteredEndDate: day,
      });
    }
  };

  render() {
    const { bold, disabled, error, inverse, readOnly, size, ...others } = this.props;

    const boxProps = pickBoxProps(others);

    const classNames = cx(theme['date-picker-input-range'], theme[`is-${size}`], {
      [theme['is-bold']]: bold,
      [theme['is-disabled']]: disabled,
      [theme['is-inverse']]: inverse,
      [theme['is-read-only']]: readOnly,
      [theme['has-error']]: error,
      [theme['has-focus']]: this.state.inputHasFocus,
    });

    return (
      <Box className={classNames} {...boxProps}>

          {this.renderIcon()}
          {this.renderDayPickerInput()}

        {error ? this.renderValidationMessage() : this.renderHelpText()}
      </Box>
    );
  }
}

DatePickerInputRange.propTypes = {
  bold: PropTypes.bool,
  className: PropTypes.string,
  disabled: PropTypes.bool,
  /** The text string/element to use as error message below the input. */
  error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  helpText: PropTypes.string,
  inverse: PropTypes.bool,
  inputProps: PropTypes.object,
  inputStartDateProps: PropTypes.object,
  inputEndDateProps: PropTypes.object,
  modifiers: PropTypes.object,
  dayPickerProps: PropTypes.object,
  dayPickerStartDateProps: PropTypes.object,
  dayPickerEndDateProps: PropTypes.object,
  dayPickerInputEndDateProps: PropTypes.object,
  dayPickerInputStartDateProps: PropTypes.object,
  onChange: PropTypes.func,
  readOnly: PropTypes.bool,
  selectedRange: PropTypes.object,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  inputStartDateValue: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
  inputEndDateValue: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
};

DatePickerInputRange.defaultProps = {
  bold: false,
  disabled: false,
  inverse: false,
  readOnly: false,
  size: 'medium',
};

export default DatePickerInputRange;
<|endoftext|>


<commit_before>
//Helper utility functions

APP.factory('AppHelpers',function() {

    var factory = {};

    /**
     * Utility function to reset form
     * @param form
     */
    factory.resetForm = function(form) {
        console.log(form);
        if(form) {
            form.$setPristine();
            form.$setUntouched();
        }
    };

    return factory;
});
<commit_msg>Update helper.js<commit_after>
//Helper utility functions

APP.factory('AppHelpers',function() {

    var factory = {};

    /**
     * Utility function to reset form
     * @param form
     */
    factory.resetForm = function(form) {
        if(form) {
            form.$setPristine();
            form.$setUntouched();
        }
    };

    return factory;
});
<|endoftext|>