<commit_before>Package.describe({
  name: 'urbanetic:accounts-ui',
  summary: 'Simple UI for Meteor Accounts',
  git: 'https://github.com/urbanetic/meteor-accounts-ui.git',
  version: '0.5.0'
});

Package.on_use(function(api) {
  api.versionsFrom('METEOR@0.9.0');
  api.use([
    'accounts-password',
    'coffeescript',
    'email',
    'http',
    'underscore',
    'tracker@1.0.5',
    'aldeed:collection2@2.3.2',
    'aldeed:simple-schema@1.3.0',
    'aramk:checkbox@0.1.0',
    'aramk:q@1.0.1_1',
    'aramk:routes@0.2.2',
    'aramk:utility@0.9.0',
    'digilord:roles@1.2.12',
    'matb33:collection-hooks@0.7.6',
    'reactive-var@1.0.5',
  ], ['client', 'server']);
  api.use([
    'templating',
    'jquery',
    'less',
    'aldeed:autoform@5.1.2',
    'aramk:collection-table@0.3.4'
  ], 'client');
  api.use([
    'urbanetic:accounts-local@0.1.1'
  ], 'server', {weak: true});
  api.imply(['accounts-password', 'digilord:roles', 'aldeed:autoform']);
  api.addFiles([
    'src/AccountsUi.coffee',
    'src/AccountsUtil.coffee'
  ], ['client', 'server']);
  api.addFiles([
    'src/AccountsForm.coffee',
    'src/accounts-ui.less',
    'src/loginForm.html',
    'src/loginForm.coffee',
    'src/forgotPasswordForm.html',
    'src/forgotPasswordForm.coffee',
    'src/resetPasswordForm.html',
    'src/resetPasswordForm.coffee',
    'src/signUpForm.html',
    'src/signUpForm.coffee',
    'src/userNav.html',
    'src/userNav.coffee',
    'src/userForm.html',
    'src/userForm.coffee',
    'src/usersTable.html',
    'src/usersTable.coffee',
    'src/verifyForm.html',
    'src/verifyForm.coffee'
  ], 'client');
  api.addFiles([
    'src/users.coffee'
  ], ['server']);
  api.export([
    'AccountsUi',
    'AccountsUtil'
  ], ['client', 'server']);
});
<commit_msg>Switch back to urbanetic:utility<commit_after>Package.describe({
  name: 'urbanetic:accounts-ui',
  summary: 'Simple UI for Meteor Accounts',
  git: 'https://github.com/urbanetic/meteor-accounts-ui.git',
  version: '0.5.0'
});

Package.on_use(function(api) {
  api.versionsFrom('METEOR@0.9.0');
  api.use([
    'accounts-password',
    'coffeescript',
    'email',
    'http',
    'underscore',
    'tracker@1.0.5',
    'aldeed:collection2@2.3.2',
    'aldeed:simple-schema@1.3.0',
    'aramk:checkbox@0.1.0',
    'aramk:q@1.0.1_1',
    'aramk:routes@0.2.2',
    'digilord:roles@1.2.12',
    'matb33:collection-hooks@0.7.6',
    'reactive-var@1.0.5',
    'urbanetic:utility@1.0.1'
  ], ['client', 'server']);
  api.use([
    'templating',
    'jquery',
    'less',
    'aldeed:autoform@5.1.2',
    'aramk:collection-table@0.3.4'
  ], 'client');
  api.use([
    'urbanetic:accounts-local@0.1.1'
  ], 'server', {weak: true});
  api.imply(['accounts-password', 'digilord:roles', 'aldeed:autoform']);
  api.addFiles([
    'src/AccountsUi.coffee',
    'src/AccountsUtil.coffee'
  ], ['client', 'server']);
  api.addFiles([
    'src/AccountsForm.coffee',
    'src/accounts-ui.less',
    'src/loginForm.html',
    'src/loginForm.coffee',
    'src/forgotPasswordForm.html',
    'src/forgotPasswordForm.coffee',
    'src/resetPasswordForm.html',
    'src/resetPasswordForm.coffee',
    'src/signUpForm.html',
    'src/signUpForm.coffee',
    'src/userNav.html',
    'src/userNav.coffee',
    'src/userForm.html',
    'src/userForm.coffee',
    'src/usersTable.html',
    'src/usersTable.coffee',
    'src/verifyForm.html',
    'src/verifyForm.coffee'
  ], 'client');
  api.addFiles([
    'src/users.coffee'
  ], ['server']);
  api.export([
    'AccountsUi',
    'AccountsUtil'
  ], ['client', 'server']);
});
<|endoftext|>


<commit_before>var express = require('express')
var _ = require('lodash')
var path = require('path')
var mongoose = require('mongoose')
var liveReload = require('express-livereload')
var schema = require('./schema')
var Movie = schema.Movie
var Account = schema.Account
var InvoiceRow = schema.InvoiceRow
var enums = require('../shared/enums')

var app = express()

app.use(express.json())

mongoose.connect('mongodb://localhost/meku')

app.get('/movies/search/:page/:q?', function(req, res) {
  var page = req.params.page || 0
  Movie.find(query()).skip(page * 100).limit(100).sort('name').exec(function(err, results) {
    res.send(results)
  })

  function query() {
    var q = (req.params.q || '').trim().toLowerCase().split(/\s+/)
    if (q.length == 1 && q[0] == '') return { 'name': /^a/i }
    var regexps = q.map(function(s) { return new RegExp('^' + escapeRegExp(s)) })
    return { 'all-names': { $all: regexps } }
  }
})

app.get('/movies/:id', function(req, res) {
  Movie.findById(req.params.id, function(err, movie) { res.send(movie) })
})

app.post('/movies/new', function(req, res, next) {
  new Movie({ classifications: [{ 'creation-date':new Date(), status: 'in_process' }], 'production-companies': [], actors: [] }).save(function(err, movie) {
    if (err) return next(err)
    return res.send(movie)
  })
})

app.post('/movies/:id/register', function(req, res, next) {
  var data = {
    'classifications.0.registration-date': new Date(),
    'classifications.0.status': 'registered'
  }

  Movie.findByIdAndUpdate(req.params.id, data, null, function(err, movie) {
    if (err) return next(err)
    InvoiceRow.create({
      account: movie.billing,
      type: 'registration',
      movie: movie._id,
      name: movie.name,
      duration: movie.duration,
      'registration-date': movie.classifications[0]['registration-date'],
      price: 700,
    }, function(err, saved) {
      if (err) return next(err)
      return res.send(movie)
    })
  })
})

app.post('/movies/:id', function(req, res, next) {
  Movie.findByIdAndUpdate(req.params.id, req.body, null, function(err, movie) {
    if (err) return next(err)
    movie.populateAllNames()
    movie.save(function(err) {
      if (err) return next(err)
      return res.send(movie)
    })
  })
})

app.get('/accounts/search/:query', function(req, res, next) {
  var roles = req.query.roles ? req.query.roles.split(',') : []
  Account.find({name: new RegExp("^" + req.params.query, 'i'), roles: { $in: roles }}).limit(20).exec(function(err, data) {
    return res.send(data)
  })
})

app.get('/accounts/:id', function(req, res, next) {
  Account.findById(req.params.id, function(err, account) { res.send(account) })
})

app.get('/actors/search/:query', function(req, res, next) {
  Movie.aggregate([
    {$unwind: '$actors'},
    {$match: {actors: new RegExp("\\b" + req.params.query, 'i')}},
    {$project: {actors: 1}},
    {$group: {_id: "$actors"}}
  ]).exec(function(err, data) {
      return res.send(data.reduce(function(acc, doc) {
        return acc.concat([doc._id])
      }, []))
    })
})

app.get('/directors/search/:query', function(req, res, next) {
  if (req.params.query.length < 3) return res.send([])
  else {
    Movie.aggregate([
      {$unwind: '$directors'},
      {$match: {directors: new RegExp("\\b" + req.params.query, 'i')}},
      {$project: {directors: 1}},
      {$group: {_id: "$directors"}}
    ]).exec(function(err, data) {
        return res.send(data.reduce(function(acc, doc) {
          return acc.concat([doc._id])
        }, []))
      })
  }
})

app.use(nocache)
app.use(express.static(path.join(__dirname, '../client')))
app.use('/shared', express.static(path.join(__dirname, '../shared')))

liveReload(app, { watchDir: path.join(__dirname, '../client') })

var server = app.listen(3000, function() {
  console.log('Listening on port ' + server.address().port)
})

function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
}

function nocache(req, res, next) {
  res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
  res.header('Expires', '-1')
  res.header('Pragma', 'no-cache')
  next()
}
<commit_msg>Attempt to support exact words is search with "word"<commit_after>var express = require('express')
var _ = require('lodash')
var path = require('path')
var mongoose = require('mongoose')
var liveReload = require('express-livereload')
var schema = require('./schema')
var Movie = schema.Movie
var Account = schema.Account
var InvoiceRow = schema.InvoiceRow
var enums = require('../shared/enums')

var app = express()

app.use(express.json())

mongoose.connect('mongodb://localhost/meku')

app.get('/movies/search/:page/:q?', function(req, res) {
  var page = req.params.page || 0
  Movie.find(query()).skip(page * 100).limit(100).sort('name').exec(function(err, results) {
    res.send(results)
  })

  function query() {
    var q = (req.params.q || '').trim().toLowerCase().split(/\s+/)
    if (q.length == 1 && q[0] == '') return { 'name': /^a/i }
    return { 'all-names': { $all: q.map(toTerm) } }
  }

  function toTerm(s) {
    if (/^".+"$/.test(s)) {
      return s.substring(1, s.length - 1)
    } else {
      return new RegExp('^' + escapeRegExp(s))
    }
  }
})

app.get('/movies/:id', function(req, res) {
  Movie.findById(req.params.id, function(err, movie) { res.send(movie) })
})

app.post('/movies/new', function(req, res, next) {
  new Movie({ classifications: [{ 'creation-date':new Date(), status: 'in_process' }], 'production-companies': [], actors: [] }).save(function(err, movie) {
    if (err) return next(err)
    return res.send(movie)
  })
})

app.post('/movies/:id/register', function(req, res, next) {
  var data = {
    'classifications.0.registration-date': new Date(),
    'classifications.0.status': 'registered'
  }

  Movie.findByIdAndUpdate(req.params.id, data, null, function(err, movie) {
    if (err) return next(err)
    InvoiceRow.create({
      account: movie.billing,
      type: 'registration',
      movie: movie._id,
      name: movie.name,
      duration: movie.duration,
      'registration-date': movie.classifications[0]['registration-date'],
      price: 700,
    }, function(err, saved) {
      if (err) return next(err)
      return res.send(movie)
    })
  })
})

app.post('/movies/:id', function(req, res, next) {
  Movie.findByIdAndUpdate(req.params.id, req.body, null, function(err, movie) {
    if (err) return next(err)
    movie.populateAllNames()
    movie.save(function(err) {
      if (err) return next(err)
      return res.send(movie)
    })
  })
})

app.get('/accounts/search/:query', function(req, res, next) {
  var roles = req.query.roles ? req.query.roles.split(',') : []
  Account.find({name: new RegExp("^" + req.params.query, 'i'), roles: { $in: roles }}).limit(20).exec(function(err, data) {
    return res.send(data)
  })
})

app.get('/accounts/:id', function(req, res, next) {
  Account.findById(req.params.id, function(err, account) { res.send(account) })
})

app.get('/actors/search/:query', function(req, res, next) {
  Movie.aggregate([
    {$unwind: '$actors'},
    {$match: {actors: new RegExp("\\b" + req.params.query, 'i')}},
    {$project: {actors: 1}},
    {$group: {_id: "$actors"}}
  ]).exec(function(err, data) {
      return res.send(data.reduce(function(acc, doc) {
        return acc.concat([doc._id])
      }, []))
    })
})

app.get('/directors/search/:query', function(req, res, next) {
  if (req.params.query.length < 3) return res.send([])
  else {
    Movie.aggregate([
      {$unwind: '$directors'},
      {$match: {directors: new RegExp("\\b" + req.params.query, 'i')}},
      {$project: {directors: 1}},
      {$group: {_id: "$directors"}}
    ]).exec(function(err, data) {
        return res.send(data.reduce(function(acc, doc) {
          return acc.concat([doc._id])
        }, []))
      })
  }
})

app.use(nocache)
app.use(express.static(path.join(__dirname, '../client')))
app.use('/shared', express.static(path.join(__dirname, '../shared')))

liveReload(app, { watchDir: path.join(__dirname, '../client') })

var server = app.listen(3000, function() {
  console.log('Listening on port ' + server.address().port)
})

function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
}

function nocache(req, res, next) {
  res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
  res.header('Expires', '-1')
  res.header('Pragma', 'no-cache')
  next()
}
<|endoftext|>


<commit_before>odoo.define('hr_attendance_extra_hours.attendance', function (require) {
"use strict";

    var core = require('web.core');

    var hr_attendance = require('hr_attendance.my_attendances');
    var greeting_message = require('hr_attendance.greeting_message');

    var Model = require('web.Model');

    var QWeb = core.qweb;
    var _t = core._t;

    hr_attendance.include({
        start: function () {
            var self = this;
            var result = this._super();
            var hr_employee = new Model('hr.employee');
            hr_employee.query(['attendance_state', 'name', 'extra_hours_formatted', 'today_hour_formatted', 'time_warning_balance', 'time_warning_today', 'extra_hours_today'])
                .filter([['user_id', '=', self.session.uid]])
                .all()
                .then(function (res) {
                    if (_.isEmpty(res) ) {
                        self.$('.o_hr_attendance_employee').append(_t("Error : Could not find employee linked to user"));
                        return;
                    }
                    self.employee = res[0];
                    self.$el.html(QWeb.render("HrAttendanceMyMainMenu", {widget: self}));

                    // auto-counter
                    $('#moment_pl').html(Date.now());
                    setInterval(function () {
                        if ($('#moment_pl').length) {
                            var moment_start = moment(new Date(parseInt($('#moment_pl').text())));
                            var diff_minutes = moment().diff(moment_start, 'minutes');

                            ['worked_today', 'balance_today'].forEach(
                                function (el) {
                                    var matches = $('#' + el + '_pl').text().match(/^-?(\d{2}):(\d{2})$/);

                                    if (matches != null && $('#state').text() == 'checked in') {
                                        var hours = parseInt(matches[1]);
                                        var minutes = parseInt(matches[2]);

                                        var total_minutes = (minutes + (hours * 60)) * (matches[0].substring(0, 1) === '-' ? -1 : 1);// eslint-disable-line no-extra-parens
                                        var negative = total_minutes + diff_minutes < 0;

                                        var new_total = Math.abs(total_minutes + diff_minutes);
                                        var new_hours = ('0' + Math.trunc(new_total / 60)).slice(-2); // eslint-disable-line no-extra-parens
                                        var new_minutes = ('0' + (new_total % 60)).slice(-2); // eslint-disable-line no-extra-parens

                                        $('#' + el).text((negative ? '-' : '') + new_hours + ':' + new_minutes);

                                        if (el != 'worked_today') {
                                            $('#' + el).parent().get(0).style.color = negative ? 'red' : 'green';
                                        }
                                    }
                                });
                        }
                    }, 20000);
                });

            return result;
        }
    });

    greeting_message.include({

        setAttendanceMessageTimeout: function(context) {
            return function() {
                setTimeout(function() {
                    context.do_action(context.next_action, {
                        clear_breadcrumbs: true
                    });
                }, 5000);
            }
        },

        welcome_message: function () {
            this._super();
            if (!this.attendance.due_hours && !this.attendance.check_out && this.attendance.total_attendance === 0 && !this.attendance.has_change_day_request) {
                // remove timeout that redirects to main page after 5 seconds
                clearTimeout(this.return_to_main_menu);
                window.attendance_message_timeout = this.setAttendanceMessageTimeout(this);
                window.add_timeout_button_event = function(className) {
                    $('.'+className).click(window.attendance_message_timeout);
                };
                this.do_action('hr_attendance_management.change_day_wizard');
            }
        }
    });
});
<commit_msg>CO-2055 Fix wizard change day request<commit_after>odoo.define('hr_attendance_extra_hours.attendance', function (require) {
"use strict";

    var core = require('web.core');

    var hr_attendance = require('hr_attendance.my_attendances');
    var greeting_message = require('hr_attendance.greeting_message');

    var Model = require('web.Model');

    var QWeb = core.qweb;
    var _t = core._t;

    hr_attendance.include({
        start: function () {
            var self = this;
            var result = this._super();
            var hr_employee = new Model('hr.employee');
            hr_employee.query(['attendance_state', 'name', 'extra_hours_formatted', 'today_hour_formatted', 'time_warning_balance', 'time_warning_today', 'extra_hours_today'])
                .filter([['user_id', '=', self.session.uid]])
                .all()
                .then(function (res) {
                    if (_.isEmpty(res) ) {
                        self.$('.o_hr_attendance_employee').append(_t("Error : Could not find employee linked to user"));
                        return;
                    }
                    self.employee = res[0];
                    self.$el.html(QWeb.render("HrAttendanceMyMainMenu", {widget: self}));

                    // auto-counter
                    $('#moment_pl').html(Date.now());
                    setInterval(function () {
                        if ($('#moment_pl').length) {
                            var moment_start = moment(new Date(parseInt($('#moment_pl').text())));
                            var diff_minutes = moment().diff(moment_start, 'minutes');

                            ['worked_today', 'balance_today'].forEach(
                                function (el) {
                                    var matches = $('#' + el + '_pl').text().match(/^-?(\d{2}):(\d{2})$/);

                                    if (matches != null && $('#state').text() == 'checked in') {
                                        var hours = parseInt(matches[1]);
                                        var minutes = parseInt(matches[2]);

                                        var total_minutes = (minutes + (hours * 60)) * (matches[0].substring(0, 1) === '-' ? -1 : 1);// eslint-disable-line no-extra-parens
                                        var negative = total_minutes + diff_minutes < 0;

                                        var new_total = Math.abs(total_minutes + diff_minutes);
                                        var new_hours = ('0' + Math.trunc(new_total / 60)).slice(-2); // eslint-disable-line no-extra-parens
                                        var new_minutes = ('0' + (new_total % 60)).slice(-2); // eslint-disable-line no-extra-parens

                                        $('#' + el).text((negative ? '-' : '') + new_hours + ':' + new_minutes);

                                        if (el != 'worked_today') {
                                            $('#' + el).parent().get(0).style.color = negative ? 'red' : 'green';
                                        }
                                    }
                                });
                        }
                    }, 20000);
                });

            return result;
        }
    });

    greeting_message.include({

        setAttendanceMessageTimeout: function(context) {
            return function() {
                setTimeout(function() {
                    context.do_action(context.next_action, {
                        clear_breadcrumbs: true
                    });
                }, 5000);
            }
        },

        welcome_message: function () {
            this._super();
            if (!this.attendance.due_hours && !this.attendance.check_out && this.attendance.total_attendance === 0 && !this.attendance.has_change_day_request) {
                // remove timeout that redirects to main page after 5 seconds
                clearTimeout(this.return_to_main_menu);
                window.attendance_message_timeout = this.setAttendanceMessageTimeout(this);
                window.add_timeout_button_event = function(className) {
                    $('.'+className).click(window.attendance_message_timeout);
                };
                this.do_action('hr_attendance_extra_hours.change_day_wizard');
            }
        }
    });
});
<|endoftext|>


<commit_before>/*
 * @title BrowserSync
 * @description A task used to initialise a local server
 * @example (cli) gulp browserSync
 */

/*********************************************************************************
 1. DEPENDENCIES
 *********************************************************************************/

var browserSync = require('browser-sync');
var config = require('../shared/config.js');
var gulp = require('gulp');

/*********************************************************************************
 2. TASK
 *********************************************************************************/

gulp.task('browserSync', function () {
  browserSync.init([
    config.path.outputJs,
    config.path.outputCss
  ], {
    server: {
      baseDir: config.path.outputDir
    },
    open: true,
    notify: false,
    scrollProportionally: true
  });
});
<commit_msg>refactor(browserSync): renaming shared paths variables and updating description<commit_after>/*
 * @title BrowserSync
 * @description A task to initialise a local server
 * @example (cli) gulp browserSync
 */

/*********************************************************************************
 1. DEPENDENCIES
 *********************************************************************************/

var browserSync = require('browser-sync');
var gulp = require('gulp');
var sharedPaths = require('../shared/paths.js');

/*********************************************************************************
 2. TASK
 *********************************************************************************/

gulp.task('browserSync', function () {
  browserSync.init([
    sharedPaths.outputJs,
    sharedPaths.outputCss
  ], {
    server: {
      baseDir: sharedPaths.outputDir
    },
    open: true,
    notify: false,
    scrollProportionally: true
  });
});
<|endoftext|>


<commit_before>/**
 * $.form
 *
 * author Maxime Cousinou
 */
(function (factory) {
	if ( typeof exports === 'object' ) {
		module.exports = factory(require('jquery'));
	} else {
		factory(jQuery);
	}
}(function ($) {
	function delegate(method, instance) {
		return function () {
			return method.apply(instance, arguments);
		}
	}

	var default_options = {
		required:              false,
		validate:              function (value, options) {
			return !FormManager.emptyOrTip(value, options);
		},
		fieldContainer:        undefined,
		errorMessage:          'Merci de renseigner ce champ correctement.',
		errorContainer:        undefined,
		errorMessageContainer: undefined,
		tipValue:              '',
		defaultValue:          ''
	};

	/**************************************************
	 * MANAGER
	 **************************************************/

	function FormManager(jForm, options) {
		this.jForm = jForm;
		this.rules = [];

		$.extend(this, options);
		0
	}

	var p = FormManager.prototype;

	window.FormManager = window.FormManager || FormManager;

	/**************************************************
	 * VALIDATOR
	 **************************************************/

	FormManager.empty = function (str) {
		return ( (str === undefined) || (str === null) || (str === false) || (str === "") || (str === 0) || (str === "0") );
	}

	FormManager.emptyOrTip = function (value, options) {
		var ok = !FormManager.empty(value);

		if ( ok && !FormManager.empty(options.tipValue) ) {
			ok = ok && (options.tipValue != value);
		}

		return !ok;
	}

	FormManager.validateEmail = function (email) {
		var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
		return re.test(email);
	}

	/**************************************************
	 * ERROR MESSAGE
	 **************************************************/

	p.hideMessage = function () {
		if ( this.errorContainer != undefined ) {
			if ( this.errorMessageContainer != undefined ) {
				this.errorMessageContainer.empty();
			}
			else {
				this.errorContainer.empty();
			}
			this.errorContainer.hide();
		}
	}

	p.showMessage = function (message) {
		if ( this.errorContainer != undefined ) {
			if ( this.errorMessageContainer != undefined ) {
				this.errorMessageContainer.append('
' + message + '
');
			}
			else {
				this.errorContainer.append('
' + message + '
');
			}
			this.errorContainer.show();
		}
	}

	/**************************************************
	 * INIT
	 **************************************************/

	/**
	 * initField
	 * @param name
	 * @param value
	 */
	p.initField = function (name, value) {
		var o = $('input[name=' + name + ']', this.jForm);
		o.val(value);

		return (this);
	};

	/**
	 * tipField
	 * @param name
	 * @param value
	 */
	p.tipField = function (name, value) {
		var o = $('input[name=' + name + ']', this.jForm);

		if ( FormManager.empty(o.val()) ) {
			o.val(value);
		}

		o.focus(function () {
			if ( o.val() == value ) {
				o.val('');
			}
		});
		o.blur(function () {
			if ( o.val() === '' ) {
				o.val(value);
			}
		});

		return (this);
	};

	/**
	 * initSelect
	 * @param name
	 * @param value
	 */
	p.initSelect = function (name, value) {
		var option = $('select[name=' + name + '] option[value=' + value + ']', this.jForm);
		option[ 0 ].selected = true;

		return (this);
	};

	/**
	 * initRadio
	 * @param name
	 * @param value
	 */
	p.initRadio = function (name, value) {
		var o = $('input[name=' + name + '][value=' + value + ']', this.jForm);
		o[ 0 ].checked = true;

		return (this);
	};

	/**************************************************
	 * RULES
	 **************************************************/

	/**
	 * addField
	 * @param name
	 * @param options
	 */
	p.addField = function (name, options) {
		options = $.extend({}, default_options, options);

		var $f = $('[name=' + name + ']', this.jForm);
		var placeholder = $f.attr('placeholder');

		if ( 'placeholder' in document.createElement("input") ) {
			if ( !placeholder && options.tipValue ) {
				$f.attr('placeholder', options.tipValue);
			}
		}
		else {
			if ( placeholder && !options.tipValue ) {
				options.tipValue = placeholder;
			}

			this.tipField(name, options.tipValue);
		}

		if ( options.defaultValue !== '' ) {
			this.initField(name, options.defaultValue);
		}

		var r = {
			name:    name,
			type:    'field',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**
	 * addSelect
	 * @param name
	 * @param options
	 */
	p.addSelect = function (name, options) {
		options = $.extend({}, default_options, options);

		this.initSelect(name, options.defaultValue);

		var r = {
			name:    name,
			type:    'field',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**
	 * addRadio
	 * @param name
	 * @param options
	 */
	p.addRadio = function (name, options) {
		options = $.extend({}, default_options, options);

		if ( options.defaultValue ) {
			this.initRadio(name, options.defaultValue);
		}

		var r = {
			name:    name,
			type:    'radio',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**
	 * addRule
	 * @param name
	 * @param options
	 */
	p.addRule = function (name, options) {
		options = $.extend({}, default_options, options);
		options.required = true;

		var r = {
			name:    name,
			type:    'rule',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**************************************************
	 * CHECK
	 **************************************************/

	p.check = function (e) {
		var ok = true;

		this.hideMessage();

		for ( var i = 0, l = this.rules.length; i < l; i++ ) {
			var name = this.rules[ i ].name;
			var type = this.rules[ i ].type;
			var options = this.rules[ i ].options;

			var value;
			switch ( type ) {
				case 'field':
					value = $('[name=' + name + ']', this.jForm).val();
					break;

				case 'radio':
					value = $('[name=' + name + ']:checked', this.jForm).val();
					break;
			}

			if ( (options.required || !FormManager.emptyOrTip(value, options)) && !options.validate(value, options) ) {
				ok = false;

				if ( options.errorContainer != undefined ) {
					if ( options.errorMessageContainer != undefined ) {
						options.errorMessageContainer.html(options.errorMessage);
					}
					else {
						options.errorContainer.html(options.errorMessage);
					}
					options.errorContainer.show();
				}
				else {
					this.showMessage(options.errorMessage);
				}

				if ( (options.fieldContainer != undefined) && (!options.fieldContainer.hasClass("error")) ) {
					options.fieldContainer.addClass("error");
				}
			}
			else {
				if ( options.errorContainer != undefined ) {
					options.errorContainer.hide();
				}

				if ( options.fieldContainer != undefined ) {
					options.fieldContainer.removeClass("error");
				}
			}
		}

		if ( ok ) {
			this.hideMessage();
		}

		if ( !ok ) {
			e.preventDefault();
		}
	};

	/***************************************************************************
	 * jQuery
	 **************************************************************************/

	$.fn.form = function (options) {
		options = $.extend({}, options);

		var dom = this.get(0);

		if ( dom === undefined ) {
			return new FormManager(null, options);
		}

		if ( dom.formManager === undefined ) {
			dom.formManager = new FormManager(this, options);

			this.submit(delegate(dom.formManager.check, dom.formManager));
		}

		return (dom.formManager);
	};
}));
<commit_msg>static jQuery call<commit_after>/**
 * $.form
 *
 * author Maxime Cousinou
 */
(function (factory) {
	if ( typeof exports === 'object' ) {
		module.exports = factory(jQuery);
	} else {
		factory(jQuery);
	}
}(function ($) {
	function delegate(method, instance) {
		return function () {
			return method.apply(instance, arguments);
		}
	}

	var default_options = {
		required:              false,
		validate:              function (value, options) {
			return !FormManager.emptyOrTip(value, options);
		},
		fieldContainer:        undefined,
		errorMessage:          'Merci de renseigner ce champ correctement.',
		errorContainer:        undefined,
		errorMessageContainer: undefined,
		tipValue:              '',
		defaultValue:          ''
	};

	/**************************************************
	 * MANAGER
	 **************************************************/

	function FormManager(jForm, options) {
		this.jForm = jForm;
		this.rules = [];

		$.extend(this, options);
		0
	}

	var p = FormManager.prototype;

	window.FormManager = window.FormManager || FormManager;

	/**************************************************
	 * VALIDATOR
	 **************************************************/

	FormManager.empty = function (str) {
		return ( (str === undefined) || (str === null) || (str === false) || (str === "") || (str === 0) || (str === "0") );
	}

	FormManager.emptyOrTip = function (value, options) {
		var ok = !FormManager.empty(value);

		if ( ok && !FormManager.empty(options.tipValue) ) {
			ok = ok && (options.tipValue != value);
		}

		return !ok;
	}

	FormManager.validateEmail = function (email) {
		var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
		return re.test(email);
	}

	/**************************************************
	 * ERROR MESSAGE
	 **************************************************/

	p.hideMessage = function () {
		if ( this.errorContainer != undefined ) {
			if ( this.errorMessageContainer != undefined ) {
				this.errorMessageContainer.empty();
			}
			else {
				this.errorContainer.empty();
			}
			this.errorContainer.hide();
		}
	}

	p.showMessage = function (message) {
		if ( this.errorContainer != undefined ) {
			if ( this.errorMessageContainer != undefined ) {
				this.errorMessageContainer.append('
' + message + '
');
			}
			else {
				this.errorContainer.append('
' + message + '
');
			}
			this.errorContainer.show();
		}
	}

	/**************************************************
	 * INIT
	 **************************************************/

	/**
	 * initField
	 * @param name
	 * @param value
	 */
	p.initField = function (name, value) {
		var o = $('input[name=' + name + ']', this.jForm);
		o.val(value);

		return (this);
	};

	/**
	 * tipField
	 * @param name
	 * @param value
	 */
	p.tipField = function (name, value) {
		var o = $('input[name=' + name + ']', this.jForm);

		if ( FormManager.empty(o.val()) ) {
			o.val(value);
		}

		o.focus(function () {
			if ( o.val() == value ) {
				o.val('');
			}
		});
		o.blur(function () {
			if ( o.val() === '' ) {
				o.val(value);
			}
		});

		return (this);
	};

	/**
	 * initSelect
	 * @param name
	 * @param value
	 */
	p.initSelect = function (name, value) {
		var option = $('select[name=' + name + '] option[value=' + value + ']', this.jForm);
		option[ 0 ].selected = true;

		return (this);
	};

	/**
	 * initRadio
	 * @param name
	 * @param value
	 */
	p.initRadio = function (name, value) {
		var o = $('input[name=' + name + '][value=' + value + ']', this.jForm);
		o[ 0 ].checked = true;

		return (this);
	};

	/**************************************************
	 * RULES
	 **************************************************/

	/**
	 * addField
	 * @param name
	 * @param options
	 */
	p.addField = function (name, options) {
		options = $.extend({}, default_options, options);

		var $f = $('[name=' + name + ']', this.jForm);
		var placeholder = $f.attr('placeholder');

		if ( 'placeholder' in document.createElement("input") ) {
			if ( !placeholder && options.tipValue ) {
				$f.attr('placeholder', options.tipValue);
			}
		}
		else {
			if ( placeholder && !options.tipValue ) {
				options.tipValue = placeholder;
			}

			this.tipField(name, options.tipValue);
		}

		if ( options.defaultValue !== '' ) {
			this.initField(name, options.defaultValue);
		}

		var r = {
			name:    name,
			type:    'field',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**
	 * addSelect
	 * @param name
	 * @param options
	 */
	p.addSelect = function (name, options) {
		options = $.extend({}, default_options, options);

		this.initSelect(name, options.defaultValue);

		var r = {
			name:    name,
			type:    'field',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**
	 * addRadio
	 * @param name
	 * @param options
	 */
	p.addRadio = function (name, options) {
		options = $.extend({}, default_options, options);

		if ( options.defaultValue ) {
			this.initRadio(name, options.defaultValue);
		}

		var r = {
			name:    name,
			type:    'radio',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**
	 * addRule
	 * @param name
	 * @param options
	 */
	p.addRule = function (name, options) {
		options = $.extend({}, default_options, options);
		options.required = true;

		var r = {
			name:    name,
			type:    'rule',
			options: options
		};

		this.rules.push(r);

		return (this);
	};

	/**************************************************
	 * CHECK
	 **************************************************/

	p.check = function (e) {
		var ok = true;

		this.hideMessage();

		for ( var i = 0, l = this.rules.length; i < l; i++ ) {
			var name = this.rules[ i ].name;
			var type = this.rules[ i ].type;
			var options = this.rules[ i ].options;

			var value;
			switch ( type ) {
				case 'field':
					value = $('[name=' + name + ']', this.jForm).val();
					break;

				case 'radio':
					value = $('[name=' + name + ']:checked', this.jForm).val();
					break;
			}

			if ( (options.required || !FormManager.emptyOrTip(value, options)) && !options.validate(value, options) ) {
				ok = false;

				if ( options.errorContainer != undefined ) {
					if ( options.errorMessageContainer != undefined ) {
						options.errorMessageContainer.html(options.errorMessage);
					}
					else {
						options.errorContainer.html(options.errorMessage);
					}
					options.errorContainer.show();
				}
				else {
					this.showMessage(options.errorMessage);
				}

				if ( (options.fieldContainer != undefined) && (!options.fieldContainer.hasClass("error")) ) {
					options.fieldContainer.addClass("error");
				}
			}
			else {
				if ( options.errorContainer != undefined ) {
					options.errorContainer.hide();
				}

				if ( options.fieldContainer != undefined ) {
					options.fieldContainer.removeClass("error");
				}
			}
		}

		if ( ok ) {
			this.hideMessage();
		}

		if ( !ok ) {
			e.preventDefault();
		}
	};

	/***************************************************************************
	 * jQuery
	 **************************************************************************/

	$.fn.form = function (options) {
		options = $.extend({}, options);

		var dom = this.get(0);

		if ( dom === undefined ) {
			return new FormManager(null, options);
		}

		if ( dom.formManager === undefined ) {
			dom.formManager = new FormManager(this, options);

			this.submit(delegate(dom.formManager.check, dom.formManager));
		}

		return (dom.formManager);
	};
}));
<|endoftext|>


<commit_before>import { isString, extend } from 'lodash';

import { LivePaginator } from '@/lib/pagination';
import template from './dashboard-list.html';
import './dashboard-list.css';

function DashboardListCtrl($scope, currentUser, $location, Dashboard) {
  const page = parseInt($location.search().page || 1, 10);

  // use $parent because we're using a component as route target instead of controller;
  // $parent refers to scope created for the page by router
  this.resource = $scope.$parent.$resolve.resource;
  this.currentPage = $scope.$parent.$resolve.currentPage;

  this.defaultOptions = {};

  this.searchText = $location.search().q;

  this.currentUser = currentUser;

  this.selectedTags = new Set();
  this.onTagsUpdate = (tags) => {
    this.selectedTags = tags;
    this.update();
  };

  this.showEmptyState = false;
  this.loaded = false;

  const fetcher = (requestedPage, itemsPerPage, paginator) => {
    $location.search('page', requestedPage);

    const request = Object.assign({}, this.defaultOptions, {
      page: requestedPage,
      page_size: itemsPerPage,
      tags: [...this.selectedTags], // convert Set to Array
    });

    if (isString(this.searchText) && this.searchText !== '') {
      request.q = this.searchText;
    }

    this.loaded = false;
    return this.resource(request).$promise.then((data) => {
      this.loaded = true;
      const rows = data.results.map(d => new Dashboard(d));
      paginator.updateRows(rows, data.count);
      this.showEmptyState = data.count === 0;
    });
  };

  this.paginator = new LivePaginator(fetcher, { page });

  this.navigateTo = ($event, url) => {
    if ($event.altKey || $event.ctrlKey || $event.metaKey || $event.shiftKey) {
      // keep default browser behavior
      return;
    }
    $event.preventDefault();
    $location.url(url);
  };

  this.update = () => {
    // trigger paginator refresh
    this.paginator.setPage(1);
  };
}

export default function init(ngModule) {
  ngModule.component('pageDashboardList', {
    template,
    controller: DashboardListCtrl,
  });

  const route = {
    template: '<page-dashboard-list></page-dashboard-list>',
    reloadOnSearch: false,
  };

  return {
    '/dashboards': extend(
      {
        title: 'Dashboards',
        resolve: {
          currentPage: () => 'all',
          resource(Dashboard) {
            'ngInject';

            return Dashboard.query.bind(Dashboard);
          },
        },
      },
      route,
    ),
    '/dashboards/favorites': extend(
      {
        title: 'Favorite Dashboards',
        resolve: {
          currentPage: () => 'favorites',
          resource(Dashboard) {
            'ngInject';

            return Dashboard.favorites.bind(Dashboard);
          },
        },
      },
      route,
    ),
  };
}
<commit_msg>Fix: dashboards list page wasn't updated to new paginator API.<commit_after>import { isString, extend } from 'lodash';

import { LivePaginator } from '@/lib/pagination';
import template from './dashboard-list.html';
import './dashboard-list.css';

function DashboardListCtrl($scope, currentUser, $location, Dashboard) {
  const page = parseInt($location.search().page || 1, 10);

  // use $parent because we're using a component as route target instead of controller;
  // $parent refers to scope created for the page by router
  this.resource = $scope.$parent.$resolve.resource;
  this.currentPage = $scope.$parent.$resolve.currentPage;

  this.defaultOptions = {};

  this.searchText = $location.search().q;

  this.currentUser = currentUser;

  this.selectedTags = new Set();
  this.onTagsUpdate = (tags) => {
    this.selectedTags = tags;
    this.update();
  };

  this.showEmptyState = false;
  this.loaded = false;

  const fetcher = (requestedPage, itemsPerPage, orderByField, orderByReverse, paginator) => {
    $location.search('page', requestedPage);

    const request = Object.assign({}, this.defaultOptions, {
      page: requestedPage,
      page_size: itemsPerPage,
      tags: [...this.selectedTags], // convert Set to Array
    });

    if (isString(this.searchText) && this.searchText !== '') {
      request.q = this.searchText;
    }

    this.loaded = false;
    return this.resource(request).$promise.then((data) => {
      this.loaded = true;
      const rows = data.results.map(d => new Dashboard(d));
      paginator.updateRows(rows, data.count);
      this.showEmptyState = data.count === 0;
    });
  };

  this.paginator = new LivePaginator(fetcher, { page });

  this.navigateTo = ($event, url) => {
    if ($event.altKey || $event.ctrlKey || $event.metaKey || $event.shiftKey) {
      // keep default browser behavior
      return;
    }
    $event.preventDefault();
    $location.url(url);
  };

  this.update = () => {
    // trigger paginator refresh
    this.paginator.setPage(1);
  };
}

export default function init(ngModule) {
  ngModule.component('pageDashboardList', {
    template,
    controller: DashboardListCtrl,
  });

  const route = {
    template: '<page-dashboard-list></page-dashboard-list>',
    reloadOnSearch: false,
  };

  return {
    '/dashboards': extend(
      {
        title: 'Dashboards',
        resolve: {
          currentPage: () => 'all',
          resource(Dashboard) {
            'ngInject';

            return Dashboard.query.bind(Dashboard);
          },
        },
      },
      route,
    ),
    '/dashboards/favorites': extend(
      {
        title: 'Favorite Dashboards',
        resolve: {
          currentPage: () => 'favorites',
          resource(Dashboard) {
            'ngInject';

            return Dashboard.favorites.bind(Dashboard);
          },
        },
      },
      route,
    ),
  };
}
<|endoftext|>


<commit_before>Package.describe({
  summary: "Foundation 5 with Sass support",
  version: "0.1.16",
  git: "https://github.com/matthewforr/meteor-foundation5-sass.git"
});

Package.onUse(function (api) {
  api.versionsFrom('METEOR@0.9.0');

  api.use("fourseven:scss@0.9.4", ['client', 'server']);
  api.imply('fourseven:scss@0.9.4', ['client', 'server']);
  api.use(['ui', 'jquery', 'templating'], 'client');

  api.addFiles([
    "js/vendor/modernizr.js",
    "js/vendor/fastclick.js",
    "js/foundation/foundation.js",
    "js/foundation/foundation.abide.js",
    "js/foundation/foundation.accordion.js",
    "js/foundation/foundation.alert.js",
    "js/foundation/foundation.clearing.js",
    "js/foundation/foundation.dropdown.js",
    "js/foundation/foundation.equalizer.js",
    "js/foundation/foundation.interchange.js",
    "js/foundation/foundation.joyride.js",
    "js/foundation/foundation.magellan.js",
    "js/foundation/foundation.offcanvas.js",
    "js/foundation/foundation.orbit.js",
    "js/foundation/foundation.reveal.js",
    "js/foundation/foundation.slider.js",
    "js/foundation/foundation.tab.js",
    "js/foundation/foundation.tooltip.js",
    "js/foundation/foundation.topbar.js",
    "kitchensink.html",
    "foundation.js"
  ], "client");

  api.addFiles([
    "_foundation.scss",
    "_settings.scss",
    "scss/foundation.scss",
    "scss/normalize.scss",
    "scss/foundation/_functions.scss",
    "scss/foundation/_settings.scss",
    "scss/foundation/components/_accordion.scss",
    "scss/foundation/components/_alert-boxes.scss",
    "scss/foundation/components/_block-grid.scss",
    "scss/foundation/components/_breadcrumbs.scss",
    "scss/foundation/components/_button-groups.scss",
    "scss/foundation/components/_buttons.scss",
    "scss/foundation/components/_clearing.scss",
    "scss/foundation/components/_dropdown-buttons.scss",
    "scss/foundation/components/_dropdown.scss",
    "scss/foundation/components/_flex-video.scss",
    "scss/foundation/components/_forms.scss",
    "scss/foundation/components/_global.scss",
    "scss/foundation/components/_grid.scss",
    "scss/foundation/components/_icon-bar.scss",
    "scss/foundation/components/_inline-lists.scss",
    "scss/foundation/components/_joyride.scss",
    "scss/foundation/components/_keystrokes.scss",
    "scss/foundation/components/_labels.scss",
    "scss/foundation/components/_magellan.scss",
    "scss/foundation/components/_offcanvas.scss",
    "scss/foundation/components/_orbit.scss",
    "scss/foundation/components/_pagination.scss",
    "scss/foundation/components/_panels.scss",
    "scss/foundation/components/_pricing-tables.scss",
    "scss/foundation/components/_progress-bars.scss",
    "scss/foundation/components/_range-slider.scss",
    "scss/foundation/components/_reveal.scss",
    "scss/foundation/components/_side-nav.scss",
    "scss/foundation/components/_split-buttons.scss",
    "scss/foundation/components/_sub-nav.scss",
    "scss/foundation/components/_switches.scss",
    "scss/foundation/components/_tables.scss",
    "scss/foundation/components/_tabs.scss",
    "scss/foundation/components/_thumbs.scss",
    "scss/foundation/components/_toolbar.scss",
    "scss/foundation/components/_tooltips.scss",
    "scss/foundation/components/_top-bar.scss",
    "scss/foundation/components/_type.scss",
    "scss/foundation/components/_visibility.scss"
  ], "server");
});

Package.onTest(function(api) {
  api.versionsFrom('METEOR@0.9.0');

  api.use("matthew:foundation5-sass@0.1.15");
  api.use(["fourseven:scss@0.9.5", "tinytest@1.0.0", "test-helpers", "templating"]);

  api.addFiles([
      "test.html",
      "test.scss",
      "test.js"
    ], "client");
});
<commit_msg>update version of fourseven:scss to work on Linux server<commit_after>Package.describe({
  summary: "Foundation 5 with Sass support",
  version: "0.1.16",
  git: "https://github.com/matthewforr/meteor-foundation5-sass.git"
});

Package.onUse(function (api) {
  api.versionsFrom('METEOR@0.9.0');

  api.use("fourseven:scss@0.9.6", ['client', 'server']);
  api.imply('fourseven:scss@0.9.6', ['client', 'server']);
  api.use(['ui', 'jquery', 'templating'], 'client');

  api.addFiles([
    "js/vendor/modernizr.js",
    "js/vendor/fastclick.js",
    "js/foundation/foundation.js",
    "js/foundation/foundation.abide.js",
    "js/foundation/foundation.accordion.js",
    "js/foundation/foundation.alert.js",
    "js/foundation/foundation.clearing.js",
    "js/foundation/foundation.dropdown.js",
    "js/foundation/foundation.equalizer.js",
    "js/foundation/foundation.interchange.js",
    "js/foundation/foundation.joyride.js",
    "js/foundation/foundation.magellan.js",
    "js/foundation/foundation.offcanvas.js",
    "js/foundation/foundation.orbit.js",
    "js/foundation/foundation.reveal.js",
    "js/foundation/foundation.slider.js",
    "js/foundation/foundation.tab.js",
    "js/foundation/foundation.tooltip.js",
    "js/foundation/foundation.topbar.js",
    "kitchensink.html",
    "foundation.js"
  ], "client");

  api.addFiles([
    "_foundation.scss",
    "_settings.scss",
    "scss/foundation.scss",
    "scss/normalize.scss",
    "scss/foundation/_functions.scss",
    "scss/foundation/_settings.scss",
    "scss/foundation/components/_accordion.scss",
    "scss/foundation/components/_alert-boxes.scss",
    "scss/foundation/components/_block-grid.scss",
    "scss/foundation/components/_breadcrumbs.scss",
    "scss/foundation/components/_button-groups.scss",
    "scss/foundation/components/_buttons.scss",
    "scss/foundation/components/_clearing.scss",
    "scss/foundation/components/_dropdown-buttons.scss",
    "scss/foundation/components/_dropdown.scss",
    "scss/foundation/components/_flex-video.scss",
    "scss/foundation/components/_forms.scss",
    "scss/foundation/components/_global.scss",
    "scss/foundation/components/_grid.scss",
    "scss/foundation/components/_icon-bar.scss",
    "scss/foundation/components/_inline-lists.scss",
    "scss/foundation/components/_joyride.scss",
    "scss/foundation/components/_keystrokes.scss",
    "scss/foundation/components/_labels.scss",
    "scss/foundation/components/_magellan.scss",
    "scss/foundation/components/_offcanvas.scss",
    "scss/foundation/components/_orbit.scss",
    "scss/foundation/components/_pagination.scss",
    "scss/foundation/components/_panels.scss",
    "scss/foundation/components/_pricing-tables.scss",
    "scss/foundation/components/_progress-bars.scss",
    "scss/foundation/components/_range-slider.scss",
    "scss/foundation/components/_reveal.scss",
    "scss/foundation/components/_side-nav.scss",
    "scss/foundation/components/_split-buttons.scss",
    "scss/foundation/components/_sub-nav.scss",
    "scss/foundation/components/_switches.scss",
    "scss/foundation/components/_tables.scss",
    "scss/foundation/components/_tabs.scss",
    "scss/foundation/components/_thumbs.scss",
    "scss/foundation/components/_toolbar.scss",
    "scss/foundation/components/_tooltips.scss",
    "scss/foundation/components/_top-bar.scss",
    "scss/foundation/components/_type.scss",
    "scss/foundation/components/_visibility.scss"
  ], "server");
});

Package.onTest(function(api) {
  api.versionsFrom('METEOR@0.9.0');

  api.use("matthew:foundation5-sass@0.1.15");
  api.use(["fourseven:scss@0.9.6", "tinytest@1.0.0", "test-helpers", "templating"]);

  api.addFiles([
      "test.html",
      "test.scss",
      "test.js"
    ], "client");
});
<|endoftext|>


<commit_before>import sortBy from 'lodash/sortBy';
import { validateAssessmentItem } from '../../utils';

function sorted(items) {
  return sortBy(items, ['order']);
}

export function getNodeAssessmentItems(state) {
  return function(contentNodeId) {
    return sorted(Object.values(state.assessmentItemsMap[contentNodeId]));
  };
}

export function getNodeAssessmentItemErrors(state) {
  return function(contentNodeId) {
    return getNodeAssessmentItems(state)(contentNodeId).map(validateAssessmentItem);
  };
}

export function getInvalidNodeAssessmentItemsCount(state) {
  return function(contentNodeId) {
    return getNodeAssessmentItemErrors(state)(contentNodeId).filter(arr => arr.length).length;
  };
}

export function getAssessmentItemsAreValid(state) {
  return function(contentNodeId) {
    return getInvalidNodeAssessmentItemsCount(state)(contentNodeId) === 0;
  };
}
<commit_msg>Use native sort + treat empty data<commit_after>import { validateAssessmentItem } from '../../utils';

export function getNodeAssessmentItems(state) {
  return function(contentNodeId) {
    if (!state.assessmentItemsMap[contentNodeId]) {
      return [];
    }

    const items = Object.values(state.assessmentItemsMap[contentNodeId]);
    return items.sort((item1, item2) => (item1.order > item2.order ? 1 : -1));
  };
}

export function getNodeAssessmentItemErrors(state) {
  return function(contentNodeId) {
    return getNodeAssessmentItems(state)(contentNodeId).map(validateAssessmentItem);
  };
}

export function getInvalidNodeAssessmentItemsCount(state) {
  return function(contentNodeId) {
    return getNodeAssessmentItemErrors(state)(contentNodeId).filter(arr => arr.length).length;
  };
}

export function getAssessmentItemsAreValid(state) {
  return function(contentNodeId) {
    return getInvalidNodeAssessmentItemsCount(state)(contentNodeId) === 0;
  };
}
<|endoftext|>


<commit_before>function room(creatorId, roomId, nowTime){
    //public variable
    this.creator_id = creatorId;//创建者的id
    this.create_time = nowTime; //在创建房间和房间重启的时候更新
    this.room_id = roomId; //房间id，由创建的时候传入
    this.god_id = ''; //上帝的用户id，在发牌的时候确定

    //private variable
    var _total = 0;//创建角色的总人数
    var _count = 0;//保存当前游戏人数

    var _role = new Array(); //角色顺序
    var _group = new Array(); //玩家顺序  userId --> _role index
    var _user = {}; //保存用户信息 userId--> userName

    //在游戏的过程中，只有上帝可以查看各个玩家的角色
    this.list = function(userId){
        console.log('用户' + _user[userId] + '企图查看角色分配列表')
        if(this.god_id == '') return '上帝死了，众神在堕落。（程序出bug了）';
        if(userId != this.god_id) return '只有上帝可以查看角色信息';

        var str = ''
        for(var uid in _user){
            str += _user[uid] + ':' + _role[_group[uid]] + '\n';
        }
        console.log('角色列表：\n' + str)
        return str;
    }

    //打乱角色分配数组
    function mess(arr){
        var _floor = Math.floor, _random = Math.random,
            len = arr.length, i, j, arri,
            n = _floor(len/2)+1;
        while(n--){
            i = _floor(_random()*len);
            j = _floor(_random()*len);
            if( i!==j ){
                arri = arr[i];
                arr[i] = arr[j];
                arr[j] = arri;
            }
        }
        //增加切牌操作
        i = _floor(_random()*len);
        arr.push.apply(arr, arr.splice(0,i));
    }

    //根据角色及各个角色的人数分配角色（上帝是默认添加的）
    this.create = function(role_list, num_list){
        console.log('创建房间解析命令成功，要求的角色有' + role_list);
        console.log('角色的数量分别是:' + num_list);

        var count = 0;
        //创造出角色列表
        for(var i = 0, l = role_list.length; i < l; i++){
            for( var j = 0; j < num_list[i]; j++){
                _role[count++] = role_list[i];
            }
        }
        _role[count] = "上帝";
        _total = count;

        //打乱角色的顺序
        mess(_role);

        console.log('打乱的角色列表为： ' + _role);
        return '房间创建成功，房间号为' + this.room_id;
    }

    this.role = function(userId, userName){
        if(_user[userId] != undefined) return "已经分配了角色";
        if( _count > _total) return "房间已满";
        console.log('用户' + userName + '通过验证，进入房间');
        console.log('用户分配到的角色为：' + _role[_count]);
        if(_role[_count] == "上帝") this.god_id = userId;

        _group[userId] = _count;
        _user[userId] = userName;

        return "成功进入房间，你的角色是" + _role[_count ++];
    }

    this.restart = function(){
        this.create_time = new Date().getTime();
        mess(_role);
    }

    this.regain_role = function(userId){
        if(_user[userId] == undefined) return "你不是这个房间的玩家，不能获得角色";
        var role = _role[_group[userId]];
        if(role == '上帝') this.god_id = userId;
        return role;
    }
}

module.exports = room
<commit_msg>put role ahead of name<commit_after>function room(creatorId, roomId, nowTime){
    //public variable
    this.creator_id = creatorId;//创建者的id
    this.create_time = nowTime; //在创建房间和房间重启的时候更新
    this.room_id = roomId; //房间id，由创建的时候传入
    this.god_id = ''; //上帝的用户id，在发牌的时候确定

    //private variable
    var _total = 0;//创建角色的总人数
    var _count = 0;//保存当前游戏人数

    var _role = new Array(); //角色顺序
    var _group = new Array(); //玩家顺序  userId --> _role index
    var _user = {}; //保存用户信息 userId--> userName

    //在游戏的过程中，只有上帝可以查看各个玩家的角色
    this.list = function(userId){
        console.log('用户' + _user[userId] + '企图查看角色分配列表')
        if(this.god_id == '') return '上帝死了，众神在堕落。（程序出bug了）';
        if(userId != this.god_id) return '只有上帝可以查看角色信息';

        var str = ''
        for(var uid in _user){
            str += _role[_group[uid]] + ' : ' + _user[uid] + '\n';
        }
        console.log('角色列表：\n' + str)
        return str;
    }

    //打乱角色分配数组
    function mess(arr){
        var _floor = Math.floor, _random = Math.random,
            len = arr.length, i, j, arri,
            n = _floor(len/2)+1;
        while(n--){
            i = _floor(_random()*len);
            j = _floor(_random()*len);
            if( i!==j ){
                arri = arr[i];
                arr[i] = arr[j];
                arr[j] = arri;
            }
        }
        //增加切牌操作
        i = _floor(_random()*len);
        arr.push.apply(arr, arr.splice(0,i));
    }

    //根据角色及各个角色的人数分配角色（上帝是默认添加的）
    this.create = function(role_list, num_list){
        console.log('创建房间解析命令成功，要求的角色有' + role_list);
        console.log('角色的数量分别是:' + num_list);

        var count = 0;
        //创造出角色列表
        for(var i = 0, l = role_list.length; i < l; i++){
            for( var j = 0; j < num_list[i]; j++){
                _role[count++] = role_list[i];
            }
        }
        _role[count] = "上帝";
        _total = count;

        //打乱角色的顺序
        mess(_role);

        console.log('打乱的角色列表为： ' + _role);
        return '房间创建成功，房间号为' + this.room_id;
    }

    this.role = function(userId, userName){
        if(_user[userId] != undefined) return "已经分配了角色";
        if( _count > _total) return "房间已满";
        console.log('用户' + userName + '通过验证，进入房间');
        console.log('用户分配到的角色为：' + _role[_count]);
        if(_role[_count] == "上帝") this.god_id = userId;

        _group[userId] = _count;
        _user[userId] = userName;

        return "成功进入房间，你的角色是" + _role[_count ++];
    }

    this.restart = function(){
        this.create_time = new Date().getTime();
        mess(_role);
    }

    this.regain_role = function(userId){
        if(_user[userId] == undefined) return "你不是这个房间的玩家，不能获得角色";
        var role = _role[_group[userId]];
        if(role == '上帝') this.god_id = userId;
        return role;
    }
}

module.exports = room
<|endoftext|>


<commit_before>// --
// Copyright (C) 2001-2016 OTRS AG, http://otrs.com/
// --
// This software comes with ABSOLUTELY NO WARRANTY. For details, see
// the enclosed file COPYING for license information (AGPL). If you
// did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
// --

"use strict";

var Core = Core || {};
Core.UI = Core.UI || {};

/**
 * @namespace Core.UI.Autocomplete
 * @memberof Core.UI
 * @author OTRS AG
 * @description
 *      This namespace contains autocomplete specific functions.
 */
Core.UI.Autocomplete = (function (TargetNS) {
    /**
     * @private
     * @name ConfigFallback
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      The configuration fallback values.
     */
    var ConfigFallback = {
            AutoCompleteActive: 1,
            MinQueryLength: 2,
            QueryDelay: 100,
            MaxResultsDisplayed: 20
        },
    /**
     * @private
     * @name ConfigElements
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      The possible config parameters.
     */
        ConfigElements = ['AutoCompleteActive', 'MinQueryLength', 'QueryDelay', 'MaxResultsDisplayed', 'ButtonText'],
    /**
     * @private
     * @name Config
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      The actual config, after merging the fallback values.
     */
        Config = {},
    /**
     * @private
     * @name AJAXLoaderPrefix
     * @memberof Core.UI.Autocomplete
     * @member {String}
     * @description
     *      AJAXLoaderPrefix
     */
        AJAXLoaderPrefix = 'AJAXLoader';

    /**
     * @private
     * @name InitConfig
     * @memberof Core.UI.Autocomplete
     * @function
     * @return {Object} The autocompletion config.
     * @param {String} Type - Type of config, e.g. "CustomerSearch.
     * @param {String} Options - Autocompletion config options.
     * @description
     *      Gets the needed config options object.
     */
    function InitConfig(Type, Options) {
        var TypeConfig = Core.Config.Get('Autocomplete');

        $.each(ConfigElements, function (ConfigKey, ConfigElement) {
            // Option, Type, Fallback
            if (Options && typeof Options[ConfigElement] !== 'undefined') {
                Config[ConfigElement] = Options[ConfigElement];
            }
            else if (Type && TypeConfig[Type]) {
                Config[ConfigElement] = TypeConfig[Type][ConfigElement];
            }
            else {
                Config[ConfigElement] = ConfigFallback[ConfigElement];
            }
        });

        // make sure, that the value of AutoCompleteActive is casted to int
        Config.AutoCompleteActive = parseInt(Config.AutoCompleteActive, 10);

        // if button should be shown, set minlength to an unreachable value
        if (!Config.AutoCompleteActive) {
            Config.MinQueryLength = 500;
        }

        return Config;
    }

    /**
     * @name GetConfig
     * @memberof Core.UI.Autocomplete
     * @function
     * @return {Object} Config option value.
     * @param {String} Key - The config option name.
     * @description
     *      gets the config value of a specific key.
     */
    TargetNS.GetConfig = function(Key) {
        return Config[Key];
    };

    /**
     * @name SearchButtonClicked
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      Needed for the handling of searches with ActiveAutoComplete = 0.
     */
    TargetNS.SearchButtonClicked = {};

    /**
     * @callback Core.UI.Autocomplete~SourceFunction
     * @returns {Array}  Data collected for autocompletion, every array element is an object with label and value keys.
     * @param {String} Request - The data provided by the autocomplete (e.g. the entered text).
     * @param {Function} Response - The function defined by the autocomplete to call with the selected data.
     */

    /**
     * @callback Core.UI.Autocomplete~SelectFunction
     * @param {EventObject} Event - The original browser event object.
     * @param {Object} UI - The data given from the UI (e.g. UI.item is the selected autocomplete list item).
     */

    /**
     * @name Init
     * @memberof Core.UI.Autocomplete
     * @function
     * @param {jQueryObject} $Element - The element which gets autocomplete infos.
     * @param {Core.UI.Autocomplete~SourceFunction} SourceFunction - Defines the source data for the autocomplete.
     * @param {Core.UI.Autocomplete~SelectFunction} SelectFunction - Is executed, if an entry is selected.
     * @param {String} Type of autocompletion, e.g. "CustomerSearch" etc.
     * @param {Object} Options object data with autocomplete plugin options
     * @description
     *      This function initializes autocomplete on an input element.
     */
    TargetNS.Init = function ($Element, SourceFunction, SelectFunction, Type, Options) {
        var AutocompleteConfig,
            $Loader;

        // Only start autocompletion, if $Element is valid element
        if (!isJQueryObject($Element) || !$Element.length) {
            return;
        }

        AutocompleteConfig = InitConfig(Type, Options);

        $Element.each(function () {
            var $SingleElement = $(this);
            $SingleElement.autocomplete({
                minLength: AutocompleteConfig.MinQueryLength,
                delay: AutocompleteConfig.QueryDelay,
                search: function() {
                    var FieldID = $SingleElement.attr('id'),
                        LoaderHTML = '';

                    $Loader = $('#' + AJAXLoaderPrefix + FieldID);

                    if (!$Loader.length) {
                        $SingleElement.after(LoaderHTML);
                        $Loader = $('#' + AJAXLoaderPrefix + FieldID);
                    }
                    else {
                        $Loader.show();
                    }
                },
                response: function() {
                    // remove loader again
                    $Loader.hide();
                },
                open: function() {
                    // force a higher z-index than the overlay/dialog
                    $SingleElement.autocomplete('widget').addClass('ui-overlay-autocomplete');
                    return false;
                },
                source: function (Request, Response) {
                    // if an old ajax request is already running, stop the old request and start the new one
                    if ($SingleElement.data('AutoCompleteXHR')) {
                        $SingleElement.data('AutoCompleteXHR').abort();
                        $SingleElement.removeData('AutoCompleteXHR');
                        // run the response function to hide the request animation
                        Response({});
                    }

                    if (SourceFunction) {
                        SourceFunction(Request, Response);
                    }

                    /*
                     * Your SourceFunction must return an array of the data you collected.
                     * Every array element is an object with the following keys:
                     * label: the string displayed in the suggestion menu
                     * value: the string to be inserted in the input field
                     * You can add more keys, if you want to transport data to the select function
                     * all keys will be available there via the UI.item object.
                     *
                     * If you use an ajax function inside your source, make sure to
                     * save the XHRObject in a data-value, to control the xhr automatically:
                     * $Element.data('AutoCompleteXHR', YourCallHere());
                     * This makes sure, that we can abort old ajax request, if new searches are triggered.
                     *
                     * The input value can be found in Request.term. Don't forget to send the MaxResult config
                     * to the server in your ajax request.
                     */
                },
                select: function (Event, UI) {
                    if (SelectFunction) {
                        SelectFunction(Event, UI);
                    }

                    Event.preventDefault();
                    return false;
                }
            });
        });

        if (!AutocompleteConfig.AutoCompleteActive) {
            $Element.each(function () {
                var $SelectedElement = $(this);
                $SelectedElement.after('<button id="' + Core.App.EscapeSelector($SelectedElement.attr('id')) + 'Search" type="button">' + Config.ButtonText + '</button>');
                $('#' + Core.App.EscapeSelector($SelectedElement.attr('id')) + 'Search').click(function () {
                    TargetNS.SearchButtonClicked[$SelectedElement.attr('id')] = true;
                    $SelectedElement.autocomplete("option", "minLength", 0);
                    $SelectedElement.autocomplete("search");
                    $SelectedElement.autocomplete("option", "minLength", 500);
                });
            });
        }
    };

    return TargetNS;
}(Core.UI.Autocomplete || {}));
<commit_msg>Fixed autocomplete issues when elements ID would contain colons, thanks to capeit-tto.<commit_after>// --
// Copyright (C) 2001-2016 OTRS AG, http://otrs.com/
// --
// This software comes with ABSOLUTELY NO WARRANTY. For details, see
// the enclosed file COPYING for license information (AGPL). If you
// did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
// --

"use strict";

var Core = Core || {};
Core.UI = Core.UI || {};

/**
 * @namespace Core.UI.Autocomplete
 * @memberof Core.UI
 * @author OTRS AG
 * @description
 *      This namespace contains autocomplete specific functions.
 */
Core.UI.Autocomplete = (function (TargetNS) {
    /**
     * @private
     * @name ConfigFallback
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      The configuration fallback values.
     */
    var ConfigFallback = {
            AutoCompleteActive: 1,
            MinQueryLength: 2,
            QueryDelay: 100,
            MaxResultsDisplayed: 20
        },
    /**
     * @private
     * @name ConfigElements
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      The possible config parameters.
     */
        ConfigElements = ['AutoCompleteActive', 'MinQueryLength', 'QueryDelay', 'MaxResultsDisplayed', 'ButtonText'],
    /**
     * @private
     * @name Config
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      The actual config, after merging the fallback values.
     */
        Config = {},
    /**
     * @private
     * @name AJAXLoaderPrefix
     * @memberof Core.UI.Autocomplete
     * @member {String}
     * @description
     *      AJAXLoaderPrefix
     */
        AJAXLoaderPrefix = 'AJAXLoader';

    /**
     * @private
     * @name InitConfig
     * @memberof Core.UI.Autocomplete
     * @function
     * @return {Object} The autocompletion config.
     * @param {String} Type - Type of config, e.g. "CustomerSearch.
     * @param {String} Options - Autocompletion config options.
     * @description
     *      Gets the needed config options object.
     */
    function InitConfig(Type, Options) {
        var TypeConfig = Core.Config.Get('Autocomplete');

        $.each(ConfigElements, function (ConfigKey, ConfigElement) {
            // Option, Type, Fallback
            if (Options && typeof Options[ConfigElement] !== 'undefined') {
                Config[ConfigElement] = Options[ConfigElement];
            }
            else if (Type && TypeConfig[Type]) {
                Config[ConfigElement] = TypeConfig[Type][ConfigElement];
            }
            else {
                Config[ConfigElement] = ConfigFallback[ConfigElement];
            }
        });

        // make sure, that the value of AutoCompleteActive is casted to int
        Config.AutoCompleteActive = parseInt(Config.AutoCompleteActive, 10);

        // if button should be shown, set minlength to an unreachable value
        if (!Config.AutoCompleteActive) {
            Config.MinQueryLength = 500;
        }

        return Config;
    }

    /**
     * @name GetConfig
     * @memberof Core.UI.Autocomplete
     * @function
     * @return {Object} Config option value.
     * @param {String} Key - The config option name.
     * @description
     *      gets the config value of a specific key.
     */
    TargetNS.GetConfig = function(Key) {
        return Config[Key];
    };

    /**
     * @name SearchButtonClicked
     * @memberof Core.UI.Autocomplete
     * @member {Object}
     * @description
     *      Needed for the handling of searches with ActiveAutoComplete = 0.
     */
    TargetNS.SearchButtonClicked = {};

    /**
     * @callback Core.UI.Autocomplete~SourceFunction
     * @returns {Array}  Data collected for autocompletion, every array element is an object with label and value keys.
     * @param {String} Request - The data provided by the autocomplete (e.g. the entered text).
     * @param {Function} Response - The function defined by the autocomplete to call with the selected data.
     */

    /**
     * @callback Core.UI.Autocomplete~SelectFunction
     * @param {EventObject} Event - The original browser event object.
     * @param {Object} UI - The data given from the UI (e.g. UI.item is the selected autocomplete list item).
     */

    /**
     * @name Init
     * @memberof Core.UI.Autocomplete
     * @function
     * @param {jQueryObject} $Element - The element which gets autocomplete infos.
     * @param {Core.UI.Autocomplete~SourceFunction} SourceFunction - Defines the source data for the autocomplete.
     * @param {Core.UI.Autocomplete~SelectFunction} SelectFunction - Is executed, if an entry is selected.
     * @param {String} Type of autocompletion, e.g. "CustomerSearch" etc.
     * @param {Object} Options object data with autocomplete plugin options
     * @description
     *      This function initializes autocomplete on an input element.
     */
    TargetNS.Init = function ($Element, SourceFunction, SelectFunction, Type, Options) {
        var AutocompleteConfig,
            $Loader;

        // Only start autocompletion, if $Element is valid element
        if (!isJQueryObject($Element) || !$Element.length) {
            return;
        }

        AutocompleteConfig = InitConfig(Type, Options);

        $Element.each(function () {
            var $SingleElement = $(this);
            $SingleElement.autocomplete({
                minLength: AutocompleteConfig.MinQueryLength,
                delay: AutocompleteConfig.QueryDelay,
                search: function() {
                    var FieldID = $SingleElement.attr('id'),
                        LoaderHTML = '';

                    $Loader = $('#' + AJAXLoaderPrefix + Core.App.EscapeSelector(FieldID));

                    if (!$Loader.length) {
                        $SingleElement.after(LoaderHTML);
                        $Loader = $('#' + AJAXLoaderPrefix + Core.App.EscapeSelector(FieldID));
                    }
                    else {
                        $Loader.show();
                    }
                },
                response: function() {
                    // remove loader again
                    $Loader.hide();
                },
                open: function() {
                    // force a higher z-index than the overlay/dialog
                    $SingleElement.autocomplete('widget').addClass('ui-overlay-autocomplete');
                    return false;
                },
                source: function (Request, Response) {
                    // if an old ajax request is already running, stop the old request and start the new one
                    if ($SingleElement.data('AutoCompleteXHR')) {
                        $SingleElement.data('AutoCompleteXHR').abort();
                        $SingleElement.removeData('AutoCompleteXHR');
                        // run the response function to hide the request animation
                        Response({});
                    }

                    if (SourceFunction) {
                        SourceFunction(Request, Response);
                    }

                    /*
                     * Your SourceFunction must return an array of the data you collected.
                     * Every array element is an object with the following keys:
                     * label: the string displayed in the suggestion menu
                     * value: the string to be inserted in the input field
                     * You can add more keys, if you want to transport data to the select function
                     * all keys will be available there via the UI.item object.
                     *
                     * If you use an ajax function inside your source, make sure to
                     * save the XHRObject in a data-value, to control the xhr automatically:
                     * $Element.data('AutoCompleteXHR', YourCallHere());
                     * This makes sure, that we can abort old ajax request, if new searches are triggered.
                     *
                     * The input value can be found in Request.term. Don't forget to send the MaxResult config
                     * to the server in your ajax request.
                     */
                },
                select: function (Event, UI) {
                    if (SelectFunction) {
                        SelectFunction(Event, UI);
                    }

                    Event.preventDefault();
                    return false;
                }
            });
        });

        if (!AutocompleteConfig.AutoCompleteActive) {
            $Element.each(function () {
                var $SelectedElement = $(this);
                $SelectedElement.after('<button id="' + Core.App.EscapeSelector($SelectedElement.attr('id')) + 'Search" type="button">' + Config.ButtonText + '</button>');
                $('#' + Core.App.EscapeSelector($SelectedElement.attr('id')) + 'Search').click(function () {
                    TargetNS.SearchButtonClicked[$SelectedElement.attr('id')] = true;
                    $SelectedElement.autocomplete("option", "minLength", 0);
                    $SelectedElement.autocomplete("search");
                    $SelectedElement.autocomplete("option", "minLength", 500);
                });
            });
        }
    };

    return TargetNS;
}(Core.UI.Autocomplete || {}));
<|endoftext|>