<commit_before>/*
 * html-angular-validate
 * https://github.com/nikestep/html-angular-validate
 *
 * Copyright (c) 2015 Nik Estep
 * Licensed under the MIT license.
 */

'use strict';

// Load our dependencies
var async = require('async');
var colors = require('colors');
var fs = require('fs');
var globule = require('globule');
var Promise = require('promise');
var tmp = require('temporary');
var w3cjs = require('w3cjs');

// Prototype string with an endsWith function
String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

// Set the default options
var default_opts = {
    angular: true,
    customtags: [],
    customattrs: [],
    wrapping: {},
    relaxerror: [],
    tmplext: 'tmpl.html',
    doctype: 'HTML5',
    charset: 'utf-8',
    reportpath: 'html-angular-validate-report.json',
    w3clocal: null,
    w3cproxy: null,
    concurrentjobs: 1,
	maxvalidateattempts: 3
};

var checkRelaxed = function(errmsg, options) {
    for (var i = 0; i < options.relaxerror.length; i += 1) {
        if (errmsg.indexOf(options.relaxerror[i]) !== -1) {
            return true;
        }
    }
    return false;
};

var checkCustomTags = function(errmsg, options) {
    for (var i = 0; i < options.customtags.length; i += 1) {
        var re = new RegExp('^Element (.?)' +
                            options.customtags[i] +
                            '(.?) not allowed as child (.*)');
        if (re.test(errmsg)) {
            return true;
        }
    }
    return false;
};

var checkCustomAttrs = function(errmsg, options) {
    for (var i = 0; i < options.customattrs.length; i += 1) {
        var re = new RegExp('Attribute (.?)' +
                            options.customattrs[i] +
                            '(.?) not allowed on element (.*) at this point.');
        if (re.test(errmsg)) {
            return true;
        }
    }
    return false;
};

var validate = function(file, callback) {
	var options = this;
	var temppath = file.path;

    // If this is a templated file, we need to wrap it as a full
    // document in a temporary file
	var tfile = null;
    if (file.istmpl) {
        // Create a temporary file
        tfile = new tmp.File();

        // Store temp path as one to pass to validator
        temppath = tfile.path;

        // Create a wrapped file to pass to the validator
        var content = fs.readFileSync(file.path, {encoding: 'utf8'}).trim();
        for (var key in options.wrapping) {
            if (options.wrapping.hasOwnProperty(key)) {
                var tag = '^<' + key + '[^>]*>';
                if (content.match(tag)) {
                    content = options.wrapping[key].replace('{0}', content);
                    break;
                }
            }
        }

        // Build temporary file
        fs.writeFileSync(temppath,
                         '<!DOCTYPE html>\n\n<title>Dummy</title>\n\n' +
                         content +
                         '\n\n');
    }

    // Do validation
    var results = w3cjs.validate({
        file: temppath,
        output: 'json',
        doctype: this.doctype,
        charset: this.charset,
        proxy: this.w3cproxy,
        callback: function (res) {
            // Validate result
            if (res === undefined || res.messages === undefined) {
                // Something went wrong
                //   See if we should try again or fail this file and
                //   move on
                if (file.attempts < max_validate_attempts) {
                    // Increment the attempt count and try again
                    file.attempts += 1;
                    validate(file, callback);
                } else {
                    // Fail the file and stop remaining validations
					// Clean up if it is a template file
				    file.seenerrs = true;
				    file.errs = [{
				        line: 0,
				        col: 0,
				        msg: 'Unable to validate file'
				    }];
	                if (tfile !== null) {
	                    tfile.unlink();
	                }
                    callback('Unable to check file', file);
                }
            } else {
                // Handle results
                var errFound = false;
                for (var i = 0; i < res.messages.length; i += 1) {
					// See if this error message is valid
                    if (!checkRelaxed(res.messages[i].message, options) &&
                        !checkCustomTags(res.messages[i].message, options) &&
                        !checkCustomAttrs(res.messages[i].message, options)) {
                        // Store the error message
                        errFound = true;
						file.seenerrs = true;
                        file.errs.push({
					        line: (file.istmpl) ? res.messages[i].lastLine - 4: res.messages[i].lastLine,
					        col: res.messages[i].lastColumn,
					        msg: res.messages[i].message
					    });
                    }
                }

                // Clean up temporary file if needed
                if (tfile !== null) {
                    tfile.unlink();
                }

                // Callback: no halting error, success indicator
                callback(null, file);
            }
        }
    });
};

var finished = function(files, options, fullfill, reject) {
	// Get the failed files
	var failedFiles = files.filter(function(file) {
		return file.seenerrs;
	});

	// Build the result object
	var result = {
        datetime: new Date(),
		allpassed: failedFiles.length == 0,
        fileschecked: files.length,
        filessucceeded: failedFiles.length,
        failed: failedFiles.map(function(file) {
			return {
                filepath: file.path,
                numerrs: file.errs.length,
                errors: file.errs.map(function(err) {
                	var out = { msg: err.msg };
					if (err.line !== undefined) {
						out.line = err.line;
						out.col = err.col;
					}
					return out;
                })
            };
        })
	};

    // Output report if necessary
    if (options.reportpath !== null) {
        // Write the report out
        fs.writeFileSync(options.reportpath, JSON.stringify(result));
    }

	// Send result to promise
	fullfill(result);
};

module.exports = {
	validate: function(fileSrcs, opts) {
		// Wrap inside a promise object
		return new Promise(function(fullfill, reject) {
			// Merge options
			var options = default_opts;
			if (typeof opts !== undefined) {
				for (var key in opts) options[key] = opts[key];
			}

	        // Parse wildcard '*' to RegExp '(.*)'
			['customtags', 'customattrs'].forEach(function(prop) {
	            for (var i = 0; i < options[prop].length; i += 1) {
	                options[prop][i] = options[prop][i].replace(/\*/g, '(.*)');
	            }
	        });

	        // Add attributes to ignore if this is for AngularJS
	        if (options.angular) {
	            options.customtags.push('ng-(.*)');
	            options.customtags.push('ui-(.*)');
	            options.customattrs.push('ng-(.*)');
	            options.customattrs.push('ui-(.*)');
	            options.customattrs.push('on');
	        }

	        // Ignore certain default warnings
	        options.relaxerror.push('The Content-Type was');
	        options.relaxerror.push('The character encoding was not declared');
	        options.relaxerror.push('Using the schema for HTML with');

	        // Delete an exist report if present
	        if (options.reportpath !== null && fs.existsSync(options.reportpath)) {
	            fs.unlinkSync(options.reportpath);
	        }

	        // Pass along local w3c server if set
	        if (options.w3clocal !== null) {
	            w3cjs.setW3cCheckUrl(options.w3clocal);
	        }

			// Get a list of files to validate
			var files = globule.find({
				src: fileSrcs,
				filter: 'isFile'
			}).map(function(file) {
				return {
					path: file,
					istmpl: file.endsWith(options.tmplext),
					attempts: 0,
			        seenerrs: false,
			        errs: []
				}
			});

	        // Check that we got files
	        if (files.length === 0) {
	            reject('No files found to match');
	        }

	        // Start the validation
	        async.mapLimit(
				files,
				options.concurrentjobs,
				validate.bind(options),
	        	function(err, results) {
	            	finished(results, options, fullfill, reject);
	        	});
		});
	},
	tester: function() {
		return new Promise(function(fullfill, reject) {
			reject(true);
		});
	}
};<commit_msg>Remove testing function<commit_after>/*
 * html-angular-validate
 * https://github.com/nikestep/html-angular-validate
 *
 * Copyright (c) 2015 Nik Estep
 * Licensed under the MIT license.
 */

'use strict';

// Load our dependencies
var async = require('async');
var colors = require('colors');
var fs = require('fs');
var globule = require('globule');
var Promise = require('promise');
var tmp = require('temporary');
var w3cjs = require('w3cjs');

// Prototype string with an endsWith function
String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

// Set the default options
var default_opts = {
    angular: true,
    customtags: [],
    customattrs: [],
    wrapping: {},
    relaxerror: [],
    tmplext: 'tmpl.html',
    doctype: 'HTML5',
    charset: 'utf-8',
    reportpath: 'html-angular-validate-report.json',
    w3clocal: null,
    w3cproxy: null,
    concurrentjobs: 1,
	maxvalidateattempts: 3
};

var checkRelaxed = function(errmsg, options) {
    for (var i = 0; i < options.relaxerror.length; i += 1) {
        if (errmsg.indexOf(options.relaxerror[i]) !== -1) {
            return true;
        }
    }
    return false;
};

var checkCustomTags = function(errmsg, options) {
    for (var i = 0; i < options.customtags.length; i += 1) {
        var re = new RegExp('^Element (.?)' +
                            options.customtags[i] +
                            '(.?) not allowed as child (.*)');
        if (re.test(errmsg)) {
            return true;
        }
    }
    return false;
};

var checkCustomAttrs = function(errmsg, options) {
    for (var i = 0; i < options.customattrs.length; i += 1) {
        var re = new RegExp('Attribute (.?)' +
                            options.customattrs[i] +
                            '(.?) not allowed on element (.*) at this point.');
        if (re.test(errmsg)) {
            return true;
        }
    }
    return false;
};

var validate = function(file, callback) {
	var options = this;
	var temppath = file.path;

    // If this is a templated file, we need to wrap it as a full
    // document in a temporary file
	var tfile = null;
    if (file.istmpl) {
        // Create a temporary file
        tfile = new tmp.File();

        // Store temp path as one to pass to validator
        temppath = tfile.path;

        // Create a wrapped file to pass to the validator
        var content = fs.readFileSync(file.path, {encoding: 'utf8'}).trim();
        for (var key in options.wrapping) {
            if (options.wrapping.hasOwnProperty(key)) {
                var tag = '^<' + key + '[^>]*>';
                if (content.match(tag)) {
                    content = options.wrapping[key].replace('{0}', content);
                    break;
                }
            }
        }

        // Build temporary file
        fs.writeFileSync(temppath,
                         '<!DOCTYPE html>\n\n<title>Dummy</title>\n\n' +
                         content +
                         '\n\n');
    }

    // Do validation
    var results = w3cjs.validate({
        file: temppath,
        output: 'json',
        doctype: this.doctype,
        charset: this.charset,
        proxy: this.w3cproxy,
        callback: function (res) {
            // Validate result
            if (res === undefined || res.messages === undefined) {
                // Something went wrong
                //   See if we should try again or fail this file and
                //   move on
                if (file.attempts < max_validate_attempts) {
                    // Increment the attempt count and try again
                    file.attempts += 1;
                    validate(file, callback);
                } else {
                    // Fail the file and stop remaining validations
					// Clean up if it is a template file
				    file.seenerrs = true;
				    file.errs = [{
				        line: 0,
				        col: 0,
				        msg: 'Unable to validate file'
				    }];
	                if (tfile !== null) {
	                    tfile.unlink();
	                }
                    callback('Unable to check file', file);
                }
            } else {
                // Handle results
                var errFound = false;
                for (var i = 0; i < res.messages.length; i += 1) {
					// See if this error message is valid
                    if (!checkRelaxed(res.messages[i].message, options) &&
                        !checkCustomTags(res.messages[i].message, options) &&
                        !checkCustomAttrs(res.messages[i].message, options)) {
                        // Store the error message
                        errFound = true;
						file.seenerrs = true;
                        file.errs.push({
					        line: (file.istmpl) ? res.messages[i].lastLine - 4: res.messages[i].lastLine,
					        col: res.messages[i].lastColumn,
					        msg: res.messages[i].message
					    });
                    }
                }

                // Clean up temporary file if needed
                if (tfile !== null) {
                    tfile.unlink();
                }

                // Callback: no halting error, success indicator
                callback(null, file);
            }
        }
    });
};

var finished = function(files, options, fullfill, reject) {
	// Get the failed files
	var failedFiles = files.filter(function(file) {
		return file.seenerrs;
	});

	// Build the result object
	var result = {
        datetime: new Date(),
		allpassed: failedFiles.length == 0,
        fileschecked: files.length,
        filessucceeded: failedFiles.length,
        failed: failedFiles.map(function(file) {
			return {
                filepath: file.path,
                numerrs: file.errs.length,
                errors: file.errs.map(function(err) {
                	var out = { msg: err.msg };
					if (err.line !== undefined) {
						out.line = err.line;
						out.col = err.col;
					}
					return out;
                })
            };
        })
	};

    // Output report if necessary
    if (options.reportpath !== null) {
        // Write the report out
        fs.writeFileSync(options.reportpath, JSON.stringify(result));
    }

	// Send result to promise
	fullfill(result);
};

module.exports = {
	validate: function(fileSrcs, opts) {
		// Wrap inside a promise object
		return new Promise(function(fullfill, reject) {
			// Merge options
			var options = default_opts;
			if (typeof opts !== undefined) {
				for (var key in opts) options[key] = opts[key];
			}

	        // Parse wildcard '*' to RegExp '(.*)'
			['customtags', 'customattrs'].forEach(function(prop) {
	            for (var i = 0; i < options[prop].length; i += 1) {
	                options[prop][i] = options[prop][i].replace(/\*/g, '(.*)');
	            }
	        });

	        // Add attributes to ignore if this is for AngularJS
	        if (options.angular) {
	            options.customtags.push('ng-(.*)');
	            options.customtags.push('ui-(.*)');
	            options.customattrs.push('ng-(.*)');
	            options.customattrs.push('ui-(.*)');
	            options.customattrs.push('on');
	        }

	        // Ignore certain default warnings
	        options.relaxerror.push('The Content-Type was');
	        options.relaxerror.push('The character encoding was not declared');
	        options.relaxerror.push('Using the schema for HTML with');

	        // Delete an exist report if present
	        if (options.reportpath !== null && fs.existsSync(options.reportpath)) {
	            fs.unlinkSync(options.reportpath);
	        }

	        // Pass along local w3c server if set
	        if (options.w3clocal !== null) {
	            w3cjs.setW3cCheckUrl(options.w3clocal);
	        }

			// Get a list of files to validate
			var files = globule.find({
				src: fileSrcs,
				filter: 'isFile'
			}).map(function(file) {
				return {
					path: file,
					istmpl: file.endsWith(options.tmplext),
					attempts: 0,
			        seenerrs: false,
			        errs: []
				}
			});

	        // Check that we got files
	        if (files.length === 0) {
	            reject('No files found to match');
	        }

	        // Start the validation
	        async.mapLimit(
				files,
				options.concurrentjobs,
				validate.bind(options),
	        	function(err, results) {
	            	finished(results, options, fullfill, reject);
	        	});
		});
	}
};<|endoftext|>


<commit_before>Ext.define('TM.view.plan.Form', {
  extend: 'Ext.form.Panel',
  xtype: 'plan_form',

  //requires: [
    //'Ext.ux.TreeCombo',
  //],

  defaultPlanType: 'yearly',
  defaultBeginToRemind: 0,

  defaults: {
    xtype: 'fieldset',
    margin: '5 10'
  },

  items: [{
    itemId: 'base-info',
    title: '基本信息',
    layout: {
      type: 'table',
      columns: 1
    },
    defaults: {
      xtype: 'textfield',
      labelAlign: 'right',
      margin: '10 0',
      width: 510
    },

    items: [{
      fieldLabel: '计划名称',
      name: 'name',
      allowBlank: false
    }, {
      xtype: 'assignee_treecombo',
      fieldLabel: '计划执行人',
      name: 'assignables_attributes',
      store: Ext.getStore('TM.store.Assignees').toTreeStore()
    }, {
      fieldLabel: '计划类型',
      name: 'plan_type',
      store: 'TM.store.Types',
      editable: false,
      valueField: 'value',
      xtype: 'combo',
      blankText: '请选择计划类型!',
      allowBlank: false
    }, {
      fieldLabel: '横向指标',
      name: 'data.x'
    }, {
      fieldLabel: '纵向指标',
      name: 'data.y'
    }, {
      fieldLabel: '生效时间',
      xtype: 'datefield',
      editable: false,
      anchor: '100%',
      format: 'Y/m/d',
      name: 'enabled_at'
    }, {
      fieldLabel: '完成前几天提醒',
      emptyText: '计划完成前多少天开始提醒，此处为倒计时。',
      name: 'begin_to_remind'
    }, {
      fieldLabel: '是否自动完成',
      xtype: 'checkbox',
      name: 'autocompletable'
    }, {
      fieldLabel: '超时回调',
      xtype: 'callback_checkboxcombo',
      editable: false,
      name: 'callables_attributes',
      store: 'TM.store.Callbacks',
      displayField: 'name',
      valueField: 'id',
      addAllSelector: true,
      allSelector: true,
      allText: '全部'
    }]
  }, {
    xtype: 'fieldset',
    itemId: 'deadline',
    title: '计划完成截至时限',
    layout: {
      type: 'table',
      columns: 2
    },
    defaults: {
      labelAlign: 'right',
    },
    items: [{
      fieldLabel: '月',
      name: 'data.deadline_month',
      xtype: 'combo',
      store: 'TM.store.Months',
      valueField: 'value',
      editable: false
    }, {
      fieldLabel: '日',
      name: 'data.deadline_day',
      store: 'TM.store.Days',
      valueField: 'value',
      xtype: 'combo',
      editable: false
    }, {
      fieldLabel: '时',
      name: 'data.deadline_hour',
      store: 'TM.store.Hours',
      valueField: 'value',
      xtype: 'combo',
      editable: false
    }, {
      fieldLabel: '分',
      name: 'data.deadline_minute',
      store: 'TM.store.Minutes',
      valueField: 'value',
      xtype: 'combo',
      editable: false
    }]
  }],

  buttons: [{
    text: '保存',
    formBind: true,
    action: 'save'
  }, {
    text: '取消',
    action: 'cancel'
  }],

  getValues: function() {
    var values = this.callParent();

    values.data = {};
    ['month', 'day', 'hour', 'minute'].forEach(function(name) {
      values.data['deadline_' + name] = this.getDeadlineCombo('data.deadline_' + name).getValue();
      delete values['data.deadline_' + name];
    }, this);

    ['x', 'y'].forEach(function(name) {
      values.data[name] = this.query('textfield[name="data.' + name + '"]')[0].getValue();
      delete values['data.' + name];
    }, this);

    return values;
  },

  loadRecord: function(record) {
    this.callParent(arguments);

    this.refreshDeadline(record.get('plan_type'));

    ['month', 'day', 'hour', 'minute'].forEach(function(name) {
      this.getDeadlineCombo('data.deadline_' + name).setValue(record.get('data')['deadline_' + name]);
    }, this);

    ['x', 'y'].forEach(function(name) {
      this.query('textfield[name="data.' + name + '"]')[0].setValue(record.get('data')[name]);
    }, this);

    this.checkSelectedAssignees(record.get('assignees'));
  },

  // @protected
  initComponent: function() {
    this.callParent(arguments);

    var planTypeCombo = this.query('fieldset combo[name="plan_type"]')[0];
    planTypeCombo.setValue(this.defaultPlanType);
    planTypeCombo.on('change', this.onPlanTypeChange, this);

    var beginToRemindField = this.query('fieldset textfield[name="begin_to_remind"]')[0];
    beginToRemindField.setValue(this.defaultBeginToRemind);

    this.refreshDeadline(this.defaultPlanType);
  },

  // @private
  checkSelectedAssignees: function(assignees) {
    if(typeof assignees === 'undefined') return;

    var values = [];
    assignees.forEach(function(a) {
      var node = this.getAssigneesTreeCombo().tree.getRootNode().findChildBy(function(node) {
        with(node.raw) {
          return record.get('id') == a.id &&
            record.get('name') == a.name
        }
      }, this, true);

      if(node) {
        values.push({
          assignee_id: node.raw.record.get('id'),
          assignee_type: node.raw.record.get('class_name')
        });
      }
    }, this);

    console.log(values);
    this.getAssigneesTreeCombo().setValue(values);
  },

  //@private
  onPlanTypeChange: function(combo, newValue) {
    this.refreshDeadline(newValue);
  },

  // @private
  refreshDeadline: function(planType) {
    switch(planType) {
      case 'yearly':
        this.showYearlyDeadlineCombos();
        break;
      case 'quarterly':
        this.showQuarterlyDeadlineCombos();
        break;
      case 'monthly':
        this.showMonthlyDeadlineCombos();
        break;
      case 'weekly':
        this.showWeeklyDeadlineCombos();
        break;
      case 'daily':
        this.showDailyDeadlineCombos();
        break;
      default:
        throw 'Invalid plan_type ' + planType;
    }

    ['month', 'day', 'hour', 'minute'].forEach(function(name) {
      this.getDeadlineCombo('data.deadline_' + name).setValue(null);
    }, this);
  },

  // @private
  showYearlyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_month').
      bindStore(Ext.getStore('TM.store.Months'));
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.Days'));

    this.showDeadlineCombos(["month", "day", "hour", "minute"]);
  },

  // @private
  showQuarterlyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_month').
      bindStore(Ext.getStore('TM.store.QuarterlyMonths'));
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.Days'));

    this.showDeadlineCombos(["month", "day", "hour", "minute"]);
  },

  // @private
  showMonthlyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.Days'));

    this.showDeadlineCombos(["day", "hour", "minute"]);
    this.hideDeadlineCombos(["month"]);
  },

  // @private
  showWeeklyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.WeekDays'));

    this.showDeadlineCombos(["day", "hour", "minute"]);
    this.hideDeadlineCombos(["month"]);
  },

  // @private
  showDailyDeadlineCombos: function() {
    this.showDeadlineCombos(["hour", "minute"]);
    this.hideDeadlineCombos(["month", "day"]);
  },

  // @private
  getDeadlineCombo: function(name) {
    return this.query('#deadline combo[name="' + name + '"]')[0];
  },

  // @private
  showDeadlineCombos: function(combos) {
    combos.forEach(function(c) {
      this.getDeadlineCombo('data.deadline_' + c).show();
    }, this);
  },

  // @private
  hideDeadlineCombos: function(combos) {
    combos.forEach(function(c) {
      this.getDeadlineCombo('data.deadline_' + c).hide();
    }, this);
  },

  // @private
  getAssigneesTreeCombo: function() {
    return this.query('assignee_treecombo')[0];
  }
});
<commit_msg>Set callback values when loadrecord<commit_after>Ext.define('TM.view.plan.Form', {
  extend: 'Ext.form.Panel',
  xtype: 'plan_form',

  //requires: [
    //'Ext.ux.TreeCombo',
  //],

  defaultPlanType: 'yearly',
  defaultBeginToRemind: 0,

  defaults: {
    xtype: 'fieldset',
    margin: '5 10'
  },

  items: [{
    itemId: 'base-info',
    title: '基本信息',
    layout: {
      type: 'table',
      columns: 1
    },
    defaults: {
      xtype: 'textfield',
      labelAlign: 'right',
      margin: '10 0',
      width: 510
    },

    items: [{
      fieldLabel: '计划名称',
      name: 'name',
      allowBlank: false
    }, {
      xtype: 'assignee_treecombo',
      fieldLabel: '计划执行人',
      name: 'assignables_attributes',
      store: Ext.getStore('TM.store.Assignees').toTreeStore()
    }, {
      fieldLabel: '计划类型',
      name: 'plan_type',
      store: 'TM.store.Types',
      editable: false,
      valueField: 'value',
      xtype: 'combo',
      blankText: '请选择计划类型!',
      allowBlank: false
    }, {
      fieldLabel: '横向指标',
      name: 'data.x'
    }, {
      fieldLabel: '纵向指标',
      name: 'data.y'
    }, {
      fieldLabel: '生效时间',
      xtype: 'datefield',
      editable: false,
      anchor: '100%',
      format: 'Y/m/d',
      name: 'enabled_at'
    }, {
      fieldLabel: '完成前几天提醒',
      emptyText: '计划完成前多少天开始提醒，此处为倒计时。',
      name: 'begin_to_remind'
    }, {
      fieldLabel: '是否自动完成',
      xtype: 'checkbox',
      name: 'autocompletable'
    }, {
      fieldLabel: '超时回调',
      xtype: 'callback_checkboxcombo',
      editable: false,
      name: 'callables_attributes',
      store: 'TM.store.Callbacks',
      addAllSelector: true,
      allSelector: false,
      allText: '全部',
      displayField: 'name',
      valueField: 'id'
    }]
  }, {
    xtype: 'fieldset',
    itemId: 'deadline',
    title: '计划完成截至时限',
    layout: {
      type: 'table',
      columns: 2
    },
    defaults: {
      labelAlign: 'right',
    },
    items: [{
      fieldLabel: '月',
      name: 'data.deadline_month',
      xtype: 'combo',
      store: 'TM.store.Months',
      valueField: 'value',
      editable: false
    }, {
      fieldLabel: '日',
      name: 'data.deadline_day',
      store: 'TM.store.Days',
      valueField: 'value',
      xtype: 'combo',
      editable: false
    }, {
      fieldLabel: '时',
      name: 'data.deadline_hour',
      store: 'TM.store.Hours',
      valueField: 'value',
      xtype: 'combo',
      editable: false
    }, {
      fieldLabel: '分',
      name: 'data.deadline_minute',
      store: 'TM.store.Minutes',
      valueField: 'value',
      xtype: 'combo',
      editable: false
    }]
  }],

  buttons: [{
    text: '保存',
    formBind: true,
    action: 'save'
  }, {
    text: '取消',
    action: 'cancel'
  }],

  getValues: function() {
    var values = this.callParent();

    values.data = {};
    ['month', 'day', 'hour', 'minute'].forEach(function(name) {
      values.data['deadline_' + name] = this.getDeadlineCombo('data.deadline_' + name).getValue();
      delete values['data.deadline_' + name];
    }, this);

    ['x', 'y'].forEach(function(name) {
      values.data[name] = this.query('textfield[name="data.' + name + '"]')[0].getValue();
      delete values['data.' + name];
    }, this);

    return values;
  },

  loadRecord: function(record) {
    this.callParent(arguments);

    this.refreshDeadline(record.get('plan_type'));

    ['month', 'day', 'hour', 'minute'].forEach(function(name) {
      this.getDeadlineCombo('data.deadline_' + name).setValue(record.get('data')['deadline_' + name]);
    }, this);

    ['x', 'y'].forEach(function(name) {
      this.query('textfield[name="data.' + name + '"]')[0].setValue(record.get('data')[name]);
    }, this);

    this.checkSelectedAssignees(record.get('assignees'));
    this.checkSelectedCallbacks(record.get('callbacks'));
  },

  // @protected
  initComponent: function() {
    this.callParent(arguments);

    var planTypeCombo = this.query('fieldset combo[name="plan_type"]')[0];
    planTypeCombo.setValue(this.defaultPlanType);
    planTypeCombo.on('change', this.onPlanTypeChange, this);

    var beginToRemindField = this.query('fieldset textfield[name="begin_to_remind"]')[0];
    beginToRemindField.setValue(this.defaultBeginToRemind);

    this.refreshDeadline(this.defaultPlanType);
  },

  // @private
  checkSelectedCallbacks: function(callbacks) {
    if (typeof callbacks === 'undefined') return;

    var values = [];
    callbacks.forEach(function(c) {
      values.push(c.id);
    });

    //this.getCallbackCheckCombo().setValue(values.join(', '));
    this.getCallbackCheckCombo().setValue(values);
  },

  // @private
  checkSelectedAssignees: function(assignees) {
    if(typeof assignees === 'undefined') return;

    var values = [];
    assignees.forEach(function(a) {
      var node = this.getAssigneesTreeCombo().tree.getRootNode().findChildBy(function(node) {
        with(node.raw) {
          return record.get('id') == a.id &&
            record.get('name') == a.name
        }
      }, this, true);

      if(node) {
        values.push({
          assignee_id: node.raw.record.get('id'),
          assignee_type: node.raw.record.get('class_name')
        });
      }
    }, this);

    //console.log(values);
    this.getAssigneesTreeCombo().setValue(values);
  },

  //@private
  onPlanTypeChange: function(combo, newValue) {
    this.refreshDeadline(newValue);
  },

  // @private
  refreshDeadline: function(planType) {
    switch(planType) {
      case 'yearly':
        this.showYearlyDeadlineCombos();
        break;
      case 'quarterly':
        this.showQuarterlyDeadlineCombos();
        break;
      case 'monthly':
        this.showMonthlyDeadlineCombos();
        break;
      case 'weekly':
        this.showWeeklyDeadlineCombos();
        break;
      case 'daily':
        this.showDailyDeadlineCombos();
        break;
      default:
        throw 'Invalid plan_type ' + planType;
    }

    ['month', 'day', 'hour', 'minute'].forEach(function(name) {
      this.getDeadlineCombo('data.deadline_' + name).setValue(null);
    }, this);
  },

  // @private
  showYearlyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_month').
      bindStore(Ext.getStore('TM.store.Months'));
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.Days'));

    this.showDeadlineCombos(["month", "day", "hour", "minute"]);
  },

  // @private
  showQuarterlyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_month').
      bindStore(Ext.getStore('TM.store.QuarterlyMonths'));
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.Days'));

    this.showDeadlineCombos(["month", "day", "hour", "minute"]);
  },

  // @private
  showMonthlyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.Days'));

    this.showDeadlineCombos(["day", "hour", "minute"]);
    this.hideDeadlineCombos(["month"]);
  },

  // @private
  showWeeklyDeadlineCombos: function() {
    this.getDeadlineCombo('data.deadline_day').
      bindStore(Ext.getStore('TM.store.WeekDays'));

    this.showDeadlineCombos(["day", "hour", "minute"]);
    this.hideDeadlineCombos(["month"]);
  },

  // @private
  showDailyDeadlineCombos: function() {
    this.showDeadlineCombos(["hour", "minute"]);
    this.hideDeadlineCombos(["month", "day"]);
  },

  // @private
  getDeadlineCombo: function(name) {
    return this.query('#deadline combo[name="' + name + '"]')[0];
  },

  // @private
  showDeadlineCombos: function(combos) {
    combos.forEach(function(c) {
      this.getDeadlineCombo('data.deadline_' + c).show();
    }, this);
  },

  // @private
  hideDeadlineCombos: function(combos) {
    combos.forEach(function(c) {
      this.getDeadlineCombo('data.deadline_' + c).hide();
    }, this);
  },

  // @private
  getAssigneesTreeCombo: function() {
    return this.query('assignee_treecombo')[0];
  },

  // @private
  getCallbackCheckCombo: function() {
    return this.query('callback_checkboxcombo')[0];
  }
});
<|endoftext|>


<commit_before>/* eslint-env node, mocha */
import { Kinetic } from '../../index';
import assert from 'assert';
import net from 'net';
import fs from 'fs';
import util from 'util';
import winston from 'winston';

const logger = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)({ level: 'warn' }),
    ]
});

const dataChunk = fs.readFileSync('./package.json');
const HOST = '127.0.0.1';
let _tmp = undefined;
let _hmacTmp = undefined;

const requestsArr = [
    ['put', 'PUT_RESPONSE'],
    ['get', 'GET_RESPONSE'],
    ['delete', 'DELETE_RESPONSE'],
    ['noop', 'NOOP_RESPONSE'],
    ['flush', 'FLUSHALLDATA_RESPONSE'],
    ['getLog', 'GETLOG_RESPONSE']
];

const kinetic = new Kinetic;
kinetic.setChunk(dataChunk);

function getSlice(obj) {
    return obj.buffer.slice(obj.offset, obj.limit);
}

function checkRequest(request, done) {
    const PORT = 6969;
    const client = new net.Socket();
    client.connect(PORT, HOST, function firstConn() {
        switch (request) {
        case 'put':
            kinetic.put(new Buffer('qwer'), 1,
                new Buffer('1234'), new Buffer('1235'), 12);
            break;
        case 'get':
            kinetic.get('qwer', 1, 1);
            break;
        case 'delete':
            kinetic.delete('qwer', 1, 1);
            break;
        case 'flush':
            kinetic.flush(1, 1);
            break;
        case 'noop':
            kinetic.noOp(1, 1);
            break;
        case 'getLog':
            kinetic.getLog(1, [1, 2, 3, 4], 1);
            break;
        default:
            throw new Error("wrong request");
        }
        kinetic.setHMAC();
        client.write(kinetic.getHMAC());
        kinetic.send(client);
        _tmp = kinetic.getProtobuf();
        let ret = undefined;
        client.on('data', function handleData(data) {
            if (data.length === 20) {
                _hmacTmp = data;
            }else {
                ret = data;
            }
            client.end();
        });

        client.on('end', function requestEnd() {
            kinetic.parse(ret);

            logger.info('=Local================================');
            logger.info(util.inspect(_tmp,
            {showHidden: false, depth: null}));
            logger.info('*Received*****************************');
            logger.info(util.inspect(kinetic.getProtobuf(),
            {showHidden: false, depth: null}));

            const protobuf = kinetic.getProtobuf();
            kinetic.setHMAC();

            if (_hmacTmp) {
                assert.deepEqual(kinetic.hmacIntegrity(_hmacTmp), true);
            } else {
                assert.deepEqual(kinetic.hmacIntegrity(_hmacTmp),
                    kinetic.errors.HMAC_FAILURE);
            }
            assert.deepEqual(dataChunk, kinetic.getChunk());
            assert.deepEqual(_tmp.header.messageType,
                    protobuf.header.messageType);
            assert.deepEqual(_tmp.header.sequence,
                    protobuf.header.sequence);
            assert.deepEqual(_tmp.header.clusterVersion,
                    protobuf.header.clusterVersion);

            if (request !== 'noop' &&
                    request !== 'flush' &&
                    request !== 'getLog') {
                assert.deepEqual(_tmp.body.keyValue.key.buffer,
                        getSlice(protobuf.body.keyValue.key));
            }
            if (request === 'put') {
                assert.deepEqual(_tmp.body.keyValue.dbVersion.buffer,
                        getSlice(protobuf.body.keyValue.dbVersion));

                assert.deepEqual(_tmp.body.keyValue.newVersion.buffer,
                        getSlice(protobuf.body.keyValue.newVersion));
            }
            if (request === 'getLog') {
                assert.deepEqual(_tmp.body.getLog.types,
                        protobuf.body.getLog.types);
            }
            _hmacTmp = undefined;
            done();
        });
    });
}

function checkResponse(request, response, done) {
    const PORT = 6970;
    let ret = undefined;
    const client = new net.Socket();
    const errorMessage = new Buffer('qwerty');

    const message = new kinetic.build.Command({
        "header": {
            "messageType": response,
            "ackSequence": 1,
        },
        "body": {
            "keyValue": {},
        },
        "status": {
            "code": 1,
            "detailedMessage": errorMessage,
        },
    });
    client.connect(PORT, HOST, function conn() {
        switch (request) {
        case 'put':
            kinetic.put('qwer', 1, new Buffer('234'), new Buffer('1235'), 12);
            break;
        case 'get':
            kinetic.get('qwer', 1, 1);
            break;
        case 'delete':
            kinetic.delete('qwer', 1, 1);
            break;
        case 'flush':
            kinetic.flush(1, 1);
            break;
        case 'noop':
            kinetic.noOp(1, 1);
            break;
        case 'getLog':
            kinetic.getLog(1, [1, 2, 3, 4, 5, 6], 1);
            break;
        default:
            throw new Error("wrong request");
        }
        kinetic.send(client);

        client.on('data', function handle(data) {
            ret = data;
            client.end();
        });
        client.on('end', function responseEnd() {
            kinetic.parse(ret);
            const protobuf = kinetic.getProtobuf();

            logger.info('=Local================================');
            logger.info(util.inspect(message,
            {showHidden: false, depth: null}));
            logger.info('*Received*****************************');
            logger.info(util.inspect(protobuf,
            {showHidden: false, depth: null}));

            const detail = message.status.detailedMessage;
            const objDetail = protobuf.status.detailedMessage;
            assert.deepEqual(detail.buffer, getSlice(objDetail));
            assert.deepEqual(message.header.messageType,
                    protobuf.header.messageType);

            done();
        });
    });
}

function checkIntegrity(requestArr) {
    const request = requestArr[0];
    const response = requestArr[1];
    describe(`Assess ${request} and its response ${response}`, () => {
        it(`Chunk and ${request} protobufMessage should be preserved`,
                (done) => { checkRequest(request, done); });
        it(`Assess ${response} Type`, (done) => {
            checkResponse(request, response, done);
        });
    });
}

requestsArr.forEach(checkIntegrity);
<commit_msg>Coding style: Fix error causing linter to fail<commit_after>/* eslint-env node, mocha */
import { Kinetic } from '../../index';
import assert from 'assert';
import net from 'net';
import fs from 'fs';
import util from 'util';
import winston from 'winston';

const logger = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)({ level: 'warn' }),
    ]
});

const dataChunk = fs.readFileSync('./package.json');
const HOST = '127.0.0.1';
let _tmp = undefined;
let _hmacTmp = undefined;

const requestsArr = [
    ['put', 'PUT_RESPONSE'],
    ['get', 'GET_RESPONSE'],
    ['delete', 'DELETE_RESPONSE'],
    ['noop', 'NOOP_RESPONSE'],
    ['flush', 'FLUSHALLDATA_RESPONSE'],
    ['getLog', 'GETLOG_RESPONSE']
];

const kinetic = new Kinetic;
kinetic.setChunk(dataChunk);

function getSlice(obj) {
    return obj.buffer.slice(obj.offset, obj.limit);
}

function checkRequest(request, done) {
    const PORT = 6969;
    const client = new net.Socket();
    client.connect(PORT, HOST, function firstConn() {
        switch (request) {
        case 'put':
            kinetic.put(new Buffer('qwer'), 1,
                new Buffer('1234'), new Buffer('1235'), 12);
            break;
        case 'get':
            kinetic.get('qwer', 1, 1);
            break;
        case 'delete':
            kinetic.delete('qwer', 1, 1);
            break;
        case 'flush':
            kinetic.flush(1, 1);
            break;
        case 'noop':
            kinetic.noOp(1, 1);
            break;
        case 'getLog':
            kinetic.getLog(1, [1, 2, 3, 4], 1);
            break;
        default:
            throw new Error("wrong request");
        }
        kinetic.setHMAC();
        client.write(kinetic.getHMAC());
        kinetic.send(client);
        _tmp = kinetic.getProtobuf();
        let ret = undefined;
        client.on('data', function handleData(data) {
            if (data.length === 20) {
                _hmacTmp = data;
            } else {
                ret = data;
            }
            client.end();
        });

        client.on('end', function requestEnd() {
            kinetic.parse(ret);

            logger.info('=Local================================');
            logger.info(util.inspect(_tmp,
            {showHidden: false, depth: null}));
            logger.info('*Received*****************************');
            logger.info(util.inspect(kinetic.getProtobuf(),
            {showHidden: false, depth: null}));

            const protobuf = kinetic.getProtobuf();
            kinetic.setHMAC();

            if (_hmacTmp) {
                assert.deepEqual(kinetic.hmacIntegrity(_hmacTmp), true);
            } else {
                assert.deepEqual(kinetic.hmacIntegrity(_hmacTmp),
                    kinetic.errors.HMAC_FAILURE);
            }
            assert.deepEqual(dataChunk, kinetic.getChunk());
            assert.deepEqual(_tmp.header.messageType,
                    protobuf.header.messageType);
            assert.deepEqual(_tmp.header.sequence,
                    protobuf.header.sequence);
            assert.deepEqual(_tmp.header.clusterVersion,
                    protobuf.header.clusterVersion);

            if (request !== 'noop' &&
                    request !== 'flush' &&
                    request !== 'getLog') {
                assert.deepEqual(_tmp.body.keyValue.key.buffer,
                        getSlice(protobuf.body.keyValue.key));
            }
            if (request === 'put') {
                assert.deepEqual(_tmp.body.keyValue.dbVersion.buffer,
                        getSlice(protobuf.body.keyValue.dbVersion));

                assert.deepEqual(_tmp.body.keyValue.newVersion.buffer,
                        getSlice(protobuf.body.keyValue.newVersion));
            }
            if (request === 'getLog') {
                assert.deepEqual(_tmp.body.getLog.types,
                        protobuf.body.getLog.types);
            }
            _hmacTmp = undefined;
            done();
        });
    });
}

function checkResponse(request, response, done) {
    const PORT = 6970;
    let ret = undefined;
    const client = new net.Socket();
    const errorMessage = new Buffer('qwerty');

    const message = new kinetic.build.Command({
        "header": {
            "messageType": response,
            "ackSequence": 1,
        },
        "body": {
            "keyValue": {},
        },
        "status": {
            "code": 1,
            "detailedMessage": errorMessage,
        },
    });
    client.connect(PORT, HOST, function conn() {
        switch (request) {
        case 'put':
            kinetic.put('qwer', 1, new Buffer('234'), new Buffer('1235'), 12);
            break;
        case 'get':
            kinetic.get('qwer', 1, 1);
            break;
        case 'delete':
            kinetic.delete('qwer', 1, 1);
            break;
        case 'flush':
            kinetic.flush(1, 1);
            break;
        case 'noop':
            kinetic.noOp(1, 1);
            break;
        case 'getLog':
            kinetic.getLog(1, [1, 2, 3, 4, 5, 6], 1);
            break;
        default:
            throw new Error("wrong request");
        }
        kinetic.send(client);

        client.on('data', function handle(data) {
            ret = data;
            client.end();
        });
        client.on('end', function responseEnd() {
            kinetic.parse(ret);
            const protobuf = kinetic.getProtobuf();

            logger.info('=Local================================');
            logger.info(util.inspect(message,
            {showHidden: false, depth: null}));
            logger.info('*Received*****************************');
            logger.info(util.inspect(protobuf,
            {showHidden: false, depth: null}));

            const detail = message.status.detailedMessage;
            const objDetail = protobuf.status.detailedMessage;
            assert.deepEqual(detail.buffer, getSlice(objDetail));
            assert.deepEqual(message.header.messageType,
                    protobuf.header.messageType);

            done();
        });
    });
}

function checkIntegrity(requestArr) {
    const request = requestArr[0];
    const response = requestArr[1];
    describe(`Assess ${request} and its response ${response}`, () => {
        it(`Chunk and ${request} protobufMessage should be preserved`,
                (done) => { checkRequest(request, done); });
        it(`Assess ${response} Type`, (done) => {
            checkResponse(request, response, done);
        });
    });
}

requestsArr.forEach(checkIntegrity);
<|endoftext|>


<commit_before>import assert from 'assert';

export default {
    cssClass(element, className) {
        const cn = element.className;

        assert(cn.split(' ').indexOf(className) >= 0, `"${className}" not found in "${cn}"`);
    },

    noCssClass(element, className) {
        const cn = element.className;

        assert(cn.split(' ').indexOf(className) === -1, `Unexpected "${className}" in "${cn}"`);
    },

    contains(haystack, needle) {
        assert(haystack.indexOf(needle) >= 0, `"${needle}" not found in "${haystack}"`);
    }
};
<commit_msg>Add massert.floatEqual<commit_after>import assert from 'assert';

export default {
    cssClass(element, className) {
        const cn = element.className;

        assert(cn.split(' ').indexOf(className) >= 0, `"${className}" not found in "${cn}"`);
    },

    noCssClass(element, className) {
        const cn = element.className;

        assert(cn.split(' ').indexOf(className) === -1, `Unexpected "${className}" in "${cn}"`);
    },

    contains(haystack, needle) {
        assert(haystack.indexOf(needle) >= 0, `"${needle}" not found in "${haystack}"`);
    },

    floatEqual(x, y) {
        assert(Math.abs(x - y) < 0.0000001, `${x} !≈ ${y}`);
    }
};
<|endoftext|>


<commit_before>ko.bindingHandlers.progressBar = {
    init: function(element) {
        return { controlsDescendantBindings: true };
    },
    update : function(element, valueAccessor, bindingContext) {
        var options = ko.unwrap(valueAccessor());

        var value = options.value();

        var width = value + "%";

        $(element).addClass("progressBar");

        ko.applyBindingsToNode(element, {
            html : '

'
        });

        ko.applyBindingsToDescendants(bindingContext, element);
    }
};

//arrays helpers
function shuffle(array) {
    var m = array.length, t, i;
    while (m) {
        i = Math.floor(Math.random() * m--);
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }
    return array;
}

function random(min, max){
    return Math.floor(Math.random() * (max - min)) + min;
}

function randomElement(arr){
    return arr[random(0, arr.length)];
}

//params parser
function parseParams(){
    var params = {};
    if (location.search) {
        var parts = location.search.substring(1).split('&');

        for (var i = 0; i < parts.length; i++) {
            var nv = parts[i].split('=');
            if (!nv[0]) continue;
            params[nv[0]] = nv[1] || true;
        }
    }
    return params;
}

//moment.js helpers
function toUTC(date){
    return date ? date.utc() : null;
}

function format(date){
    return date ? date.format("MM/DD/YYYY hh:mm A") : null;
}

function multiply(time, n){
    return time.add(time.millisecond() * n, 'milliseconds')
}

//elements helpers
function collapsible(name, action){
    $(name).collapse(action);
}

function removeTags(name){
    $(name).tagsinput('removeAll');
}

function addTags(name, tags){
    $(name).tagsinput('add', tags);
}
function setTags(name, tags){
    removeTags(name);
    addTags(name, tags);
}

//Knockout
var randogramViewModel = new function RandogramViewModel() {
    var self = this;
    /////////////////////////////////////////////////////accordion//////////////////////////////////////////////////////
    self.basicCollapsibleHandler = function(){
        collapsible('#basicCollapsible', 'show');
        collapsible('#advancedCollapsible', 'hide');
    };
    self.advancedCollapsibleHandler = function(){
        collapsible('#basicCollapsible', 'hide');
        collapsible('#advancedCollapsible', 'show');
    };
    /////////////////////////////////////////////////////tags///////////////////////////////////////////////////////////
    //tags
    self.tags = ko.observable("griddynamics");

    //tags helpers
    self.areTagsInvalid = ko.computed (function () {
        return self.tags().length == 0;
    });

    //tagsinput fields handler (so bad!)
    self.tagsFix = ko.observable(true);
    self.checkedFix = ko.observable(0);
    self.tagsHandler = ko.pureComputed({
        read: function () {
            return self.tags();
        },
        write: function (value) {
            self.tags(value);

            //мне очень стыдно за этот костыль
            //защита от срабатывания при загрузке страницы
            if(self.checkedFix() < 2){
                self.checkedFix(self.checkedFix()+1);
                return;
            }
            //защита от зацикливания
            if(self.tagsFix()){
                self.tagsFix(false);
                setTags('#tags1', self.tags());
                setTags('#tags2', self.tags());
                setTimeout(function(){self.tagsFix(true)}, 100);
            }
        },
        owner: this
    });

    /////////////////////////////////////////////////////dates//////////////////////////////////////////////////////////
    //date filter type
    self.dateFilterSelected = ko.observable("Today");
    self.dateFilterPresetsBasic = [
        { statusName: "Today" },
        { statusName: "Specify day" },
        { statusName: "All time" }
    ];
    self.dateFilterPresetsAdvanced = [
        { statusName: "Today" },
        { statusName: "Last week" },
        { statusName: "Last month" },
        { statusName: "All time" },
        { statusName: "Specify day" },
        { statusName: "Specify interval" }
    ];
    self.dateFilterClickHandler = function(){
        self.dateFilterSelected(this.statusName);
        switch(self.dateFilterSelected()){
            case "Specify day":
                collapsible('#basicDateFrom-collapsible', 'show');
                collapsible('#advancedDateFrom-collapsible', 'show');
                collapsible('#advancedDateTo-collapsible', 'hide');
                break;
            case "Specify interval":
                collapsible('#advancedDateFrom-collapsible', 'show');
                collapsible('#advancedDateTo-collapsible', 'show');
                break;
            default:
                collapsible('#basicDateFrom-collapsible', 'hide');
                collapsible('#advancedDateFrom-collapsible', 'hide');
                collapsible('#advancedDateTo-collapsible', 'hide');
        }
    };

    //date fields
    self.dateFrom = ko.observable(moment().format("MM/DD/YYYY"));
    self.dateTo = ko.observable(moment().format("MM/DD/YYYY"));

    self.calculateDateFrom = function(){
        switch(self.dateFilterSelected()){
            case "Today":
                return moment().startOf('day');
            case "Last week":
                return moment().startOf('week');
            case "Last month":
                return moment().startOf('month');
            case "Specify day":
            case "Specify interval":
                return moment(self.dateFrom() ? self.dateFrom() : moment()).startOf('day');
            default:
                return null;
        }
    };
    self.calculateDateTo = function(){
        switch(self.dateFilterSelected()){
            case "Specify day":
                return moment(self.dateFrom() ? self.dateFrom() : moment()).endOf('day');
            case "Specify interval":
                return moment(self.dateTo() ? self.dateTo() : moment()).endOf('day');
            case "All time":
                return null;
            default:
                return moment();
        }
    };

    //unixTimestamp -> "... ago"
    self.getMoment = function(unixTime){
        return moment(unixTime, "X").fromNow();
    };

    /////////////////////////////////////////////////////observables////////////////////////////////////////////////////
    //arrays
    self.usersAndPosts = ko.observableArray([]);
    self.images = ko.observableArray([]);
    self.preview = ko.observableArray();

    //statements
    self.isSearchDone = ko.observable(false);
    self.isLoading = ko.observable(false);
    self.isFollowing = ko.observable(false);

    self.isLuckyButtonEnabled = ko.computed (function () {
        return !self.isLoading() && self.images().length>0;
    });

    self.isSearchButtonEnabled = ko.computed (function () {
        return !self.areTagsInvalid() && !self.isLoading();
    });

    /////////////////////////////////////////////////////arrays helpers/////////////////////////////////////////////////
    self.setPreview = function() {
        if (self.isLoading()) {
            return;
        }
        self.preview([this]);
    };

    var pushImages = function (images) {
        self.images(self.images().concat(images));
    };

    var setUsersAndPosts = function(){
        var users = new Set(self.images().map(function(image){return image.user.username}));
        var usersArray = Array.from(users);

        var usersPairs = usersArray.map(function(x){return {username: x, posts: []}});
        usersPairs.forEach(function(pair){
            pair.posts = self.images().filter(function(image){return image.user.username == pair.username;});
        });

        self.usersAndPosts(usersPairs);
    };

    /////////////////////////////////////////////////////winners////////////////////////////////////////////////////////

    self.winners = ko.observableArray([]);
    self.winnersSelectionType = ko.observable("posts");
    self.winnersAmount = ko.observable(1);
    self.winnersAmountMax = function(){
        return self.winnersSelectionType() === "users" ? self.usersAndPosts().length : self.images().length;
    };

    self.winnersAmountHandler = ko.pureComputed({
        read: function () {
            return self.winnersAmount();
        },
        write: function (value) {
            if(value > self.winnersAmountMax()){
                self.winnersAmount(self.winnersAmountMax());
            }else{
                self.winnersAmount(value);
            }
        },
        owner: this
    });
    //winnersAmount +/- buttons
    self.winnersAmountPlus = function () {
        if(self.winnersAmount() < self.winnersAmountMax()){
            self.winnersAmount(self.winnersAmount()+1);
        }else if(self.winnersAmountMax() != 0){
            self.winnersAmount(self.winnersAmountMax());
        }
    };
    self.winnersAmountMinus = function () {
        if(self.winnersAmount() > 1){
            self.winnersAmount(self.winnersAmount()-1);
        }else{
            self.winnersAmount(1);
        }
    };
    self.searchInfo = ko.computed (function () {
        if(self.images().length == 0){
            return "Sorry, we didn't find anything. Check your query."
        }
        return "We found " + self.images().length + " posts from " + self.usersAndPosts().length + " users!";
    });

    /////////////////////////////////////////////////////actions////////////////////////////////////////////////////////
    //search
    self.startTime = ko.observable(moment());
    self.endTime = ko.observable(moment());
    self.progress = function(){
        var timeBetweenStartAndEnd = (self.endTime().toDate() - self.startTime().toDate());
        var timeBetweenStartAndToday = (moment().toDate() - self.startTime().toDate());
        var p = timeBetweenStartAndToday / timeBetweenStartAndEnd;
        return p;
    };
    self.searchAction = function () {

        self.isLoading(true);

        collapsible('#basicCollapsible', 'hide');
        collapsible('#advancedCollapsible', 'hide');
        collapsible('#chooseLucky-collapsible', 'hide');
        collapsible('#search-info-collapsible', 'hide');
        collapsible('#winners-content-collapsible', 'hide');
        collapsible('#content-collapsible', 'hide');

        //get tag info
        var willBeLoaded = 100;
        $.ajax({
            url: "getTagAmount",
            data: {
                tags: self.tags()
            },
            dataType: "json",
            success: function (data) {
                willBeLoaded = data;
                if(data > 1000){
                    alert("Only first 1000 of "+data+" photos will be loaded");
                    willBeLoaded = 1000;
                }
            },
            error: function () {
                alert("getTagAmount error");
            }
        });

        //get first 40 photos
        $.ajax({
            url: "getFirstImages",
            data: {
                accesToken: self.accesToken(),
                tags: self.tags(),
                amount: 1
            },
            dataType: "json",
            beforeSend: function(){
                self.startTime(moment());
            },
            success: function (data) {
                self.endTime(moment().add((willBeLoaded*0.9)/20, 'seconds'));
            },
            error: function () {
                alert("getImages error");
                self.isLoading(false);

            },
        });

        //get images
        $.ajax({
            url: "getImages",
            data: {
                accesToken: self.accesToken(),
                tags: self.tags(),
                following: self.isFollowing(),
                dateTimeFrom: format(toUTC(self.calculateDateFrom())),
                dateTimeTo: format(toUTC(self.calculateDateTo()))
            },
            dataType: "json",
            success: function (data) {
                self.images([]);
                pushImages(data);
                setUsersAndPosts();

                self.isLoading(false);
                self.isSearchDone(true);
                self.winnersAmount(1);

                if(self.images().length > 0){
                    collapsible('#chooseLucky-collapsible', 'show');
                    collapsible('#content-collapsible', 'show');
                }
                collapsible('#search-info-collapsible', 'show');
            },
            error: function () {
                alert("getImages error");
                self.isLoading(false);
                l.ladda('stop');
            },
            timeout: 200000
        });
    };

    //select winners action
    self.selectAction = function () {
        if(self.winnersSelectionType() === "users"){
            var luckyUsers = shuffle(self.usersAndPosts()).slice(0, self.winnersAmount());
            var winnerPosts = luckyUsers.map(function(x){return randomElement(x.posts)});
            self.winners(winnerPosts);
        }else{
            var luckyPosts = shuffle(self.images()).slice(0, self.winnersAmount());
            self.winners(luckyPosts);
        }
        collapsible('#winners-content-collapsible', 'show');
    };

    //acces token
    self.accesToken = ko.observable();
    self.handleToken = ko.computed (function(){
        var params = parseParams();

        if(!params.accesToken){
            window.location = "/";
        }else{
            self.accesToken(params.accesToken);
        }
    });
};

ko.applyBindings(randogramViewModel);

//Activate datetimepickers and make them linked to each other
//$('#dateTimeFrom').datetimepicker();
$('#basicDateFrom').datetimepicker();
$('#advancedDateFrom').datetimepicker();
$('#advancedDateTo').datetimepicker();

//$(document).ready(function() {
//    var viewModel = function() {
//        self = this;
//
//        self.percentage = ko.observable(0);
//
//        self.percentage.subscribe(function () {
//            if (self.percentage() === 100) {
//                clearTimeout(timer);
//            }
//        });
//    };
//
//    var timer = setInterval(function() { viewModelObj.percentage(viewModelObj.percentage() + 1); }, 50);
//});<commit_msg>progressbar<commit_after>//arrays helpers
function shuffle(array) {
    var m = array.length, t, i;
    while (m) {
        i = Math.floor(Math.random() * m--);
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }
    return array;
}

function random(min, max){
    return Math.floor(Math.random() * (max - min)) + min;
}

function randomElement(arr){
    return arr[random(0, arr.length)];
}

//params parser
function parseParams(){
    var params = {};
    if (location.search) {
        var parts = location.search.substring(1).split('&');

        for (var i = 0; i < parts.length; i++) {
            var nv = parts[i].split('=');
            if (!nv[0]) continue;
            params[nv[0]] = nv[1] || true;
        }
    }
    return params;
}

//moment.js helpers
function toUTC(date){
    return date ? date.utc() : null;
}

function format(date){
    return date ? date.format("MM/DD/YYYY hh:mm A") : null;
}

function multiply(time, n){
    return time.add(time.millisecond() * n, 'milliseconds')
}

//elements helpers
function collapsible(name, action){
    $(name).collapse(action);
}

function removeTags(name){
    $(name).tagsinput('removeAll');
}

function addTags(name, tags){
    $(name).tagsinput('add', tags);
}
function setTags(name, tags){
    removeTags(name);
    addTags(name, tags);
}

//Knockout
var randogramViewModel = new function RandogramViewModel() {
    var self = this;
    /////////////////////////////////////////////////////accordion//////////////////////////////////////////////////////
    self.basicCollapsibleHandler = function(){
        collapsible('#basicCollapsible', 'show');
        collapsible('#advancedCollapsible', 'hide');
    };
    self.advancedCollapsibleHandler = function(){
        collapsible('#basicCollapsible', 'hide');
        collapsible('#advancedCollapsible', 'show');
    };
    /////////////////////////////////////////////////////tags///////////////////////////////////////////////////////////
    //tags
    self.tags = ko.observable("griddynamics");

    //tags helpers
    self.areTagsInvalid = ko.computed (function () {
        return self.tags().length == 0;
    });

    //tagsinput fields handler (so bad!)
    self.tagsFix = ko.observable(true);
    self.checkedFix = ko.observable(0);
    self.tagsHandler = ko.pureComputed({
        read: function () {
            return self.tags();
        },
        write: function (value) {
            self.tags(value);

            //мне очень стыдно за этот костыль
            //защита от срабатывания при загрузке страницы
            if(self.checkedFix() < 2){
                self.checkedFix(self.checkedFix()+1);
                return;
            }
            //защита от зацикливания
            if(self.tagsFix()){
                self.tagsFix(false);
                setTags('#tags1', self.tags());
                setTags('#tags2', self.tags());
                setTimeout(function(){self.tagsFix(true)}, 100);
            }
        },
        owner: this
    });

    /////////////////////////////////////////////////////dates//////////////////////////////////////////////////////////
    //date filter type
    self.dateFilterSelected = ko.observable("Today");
    self.dateFilterPresetsBasic = [
        { statusName: "Today" },
        { statusName: "Specify day" },
        { statusName: "All time" }
    ];
    self.dateFilterPresetsAdvanced = [
        { statusName: "Today" },
        { statusName: "Last week" },
        { statusName: "Last month" },
        { statusName: "All time" },
        { statusName: "Specify day" },
        { statusName: "Specify interval" }
    ];
    self.dateFilterClickHandler = function(){
        self.dateFilterSelected(this.statusName);
        switch(self.dateFilterSelected()){
            case "Specify day":
                collapsible('#basicDateFrom-collapsible', 'show');
                collapsible('#advancedDateFrom-collapsible', 'show');
                collapsible('#advancedDateTo-collapsible', 'hide');
                break;
            case "Specify interval":
                collapsible('#advancedDateFrom-collapsible', 'show');
                collapsible('#advancedDateTo-collapsible', 'show');
                break;
            default:
                collapsible('#basicDateFrom-collapsible', 'hide');
                collapsible('#advancedDateFrom-collapsible', 'hide');
                collapsible('#advancedDateTo-collapsible', 'hide');
        }
    };

    //date fields
    self.dateFrom = ko.observable(moment().format("MM/DD/YYYY"));
    self.dateTo = ko.observable(moment().format("MM/DD/YYYY"));

    self.calculateDateFrom = function(){
        switch(self.dateFilterSelected()){
            case "Today":
                return moment().startOf('day');
            case "Last week":
                return moment().startOf('week');
            case "Last month":
                return moment().startOf('month');
            case "Specify day":
            case "Specify interval":
                return moment(self.dateFrom() ? self.dateFrom() : moment()).startOf('day');
            default:
                return null;
        }
    };
    self.calculateDateTo = function(){
        switch(self.dateFilterSelected()){
            case "Specify day":
                return moment(self.dateFrom() ? self.dateFrom() : moment()).endOf('day');
            case "Specify interval":
                return moment(self.dateTo() ? self.dateTo() : moment()).endOf('day');
            case "All time":
                return null;
            default:
                return moment();
        }
    };

    //unixTimestamp -> "... ago"
    self.getMoment = function(unixTime){
        return moment(unixTime, "X").fromNow();
    };

    /////////////////////////////////////////////////////observables////////////////////////////////////////////////////
    //arrays
    self.usersAndPosts = ko.observableArray([]);
    self.images = ko.observableArray([]);
    self.preview = ko.observableArray();

    //statements
    self.isSearchDone = ko.observable(false);
    self.isLoading = ko.observable(false);
    self.isFollowing = ko.observable(false);

    self.isLuckyButtonEnabled = ko.computed (function () {
        return !self.isLoading() && self.images().length>0;
    });

    self.isSearchButtonEnabled = ko.computed (function () {
        return !self.areTagsInvalid() && !self.isLoading();
    });

    /////////////////////////////////////////////////////arrays helpers/////////////////////////////////////////////////
    self.setPreview = function() {
        if (self.isLoading()) {
            return;
        }
        self.preview([this]);
    };

    var setUsersAndPosts = function(){
        var users = new Set(self.images().map(function(image){return image.user.username}));
        var usersArray = Array.from(users);

        var usersPairs = usersArray.map(function(x){return {username: x, posts: []}});
        usersPairs.forEach(function(pair){
            pair.posts = self.images().filter(function(image){return image.user.username == pair.username;});
        });

        self.usersAndPosts(usersPairs);
    };

    /////////////////////////////////////////////////////winners////////////////////////////////////////////////////////

    self.winners = ko.observableArray([]);
    self.winnersSelectionType = ko.observable("posts");
    self.winnersAmount = ko.observable(1);
    self.winnersAmountMax = function(){
        return self.winnersSelectionType() === "users" ? self.usersAndPosts().length : self.images().length;
    };

    self.winnersAmountHandler = ko.pureComputed({
        read: function () {
            return self.winnersAmount();
        },
        write: function (value) {
            if(value > self.winnersAmountMax()){
                self.winnersAmount(self.winnersAmountMax());
            }else{
                self.winnersAmount(value);
            }
        },
        owner: this
    });
    //winnersAmount +/- buttons
    self.winnersAmountPlus = function () {
        if(self.winnersAmount() < self.winnersAmountMax()){
            self.winnersAmount(self.winnersAmount()+1);
        }else if(self.winnersAmountMax() != 0){
            self.winnersAmount(self.winnersAmountMax());
        }
    };
    self.winnersAmountMinus = function () {
        if(self.winnersAmount() > 1){
            self.winnersAmount(self.winnersAmount()-1);
        }else{
            self.winnersAmount(1);
        }
    };
    self.searchInfo = ko.computed (function () {
        if(self.images().length == 0){
            return "Sorry, we didn't find anything. Check your query."
        }
        return "We found " + self.images().length + " posts from " + self.usersAndPosts().length + " users!";
    });

    /////////////////////////////////////////////////////actions////////////////////////////////////////////////////////
    //search
    self.startTime = ko.observable(moment());
    self.endTime = ko.observable(moment());
    self.progress = function(){
        if(!self.isLoading()){return 1}
        var timeBetweenStartAndEnd = (self.endTime().toDate() - self.startTime().toDate());
        var timeBetweenStartAndToday = (moment().toDate() - self.startTime().toDate());
        var p = timeBetweenStartAndToday / timeBetweenStartAndEnd;
        return p;
    };
    self.searchAction = function () {
        self.images([]);
        self.isLoading(true);

        collapsible('#basicCollapsible', 'hide');
        collapsible('#advancedCollapsible', 'hide');
        collapsible('#chooseLucky-collapsible', 'hide');
        collapsible('#search-info-collapsible', 'hide');
        collapsible('#winners-content-collapsible', 'hide');
        collapsible('#content-collapsible', 'hide');

        //get tag info
        var willBeLoaded = 100;
        $.ajax({
            url: "getTagAmount",
            data: {
                tags: self.tags()
            },
            dataType: "json",
            success: function (data) {
                willBeLoaded = data;
                if(data > 1000){
                    alert("Only first 1000 of "+data+" photos will be loaded");
                    willBeLoaded = 1000;
                }
            },
            error: function () {
                alert("getTagAmount error");
            }
        });

        //get first 40 photos
        $.ajax({
            url: "getFirstImages",
            data: {
                accesToken: self.accesToken(),
                tags: self.tags(),
                amount: 2
            },
            dataType: "json",
            beforeSend: function(){
                self.startTime(moment());
            },
            success: function (data) {
                var m = moment();
                var interval = m.diff(self.startTime(), 'milliseconds');
                //magic numbers!
                self.endTime(m.add(((interval/90.0)*(willBeLoaded-data.length))^1.2), 'milliseconds');
            },
            error: function () {
                alert("getImages error");
                self.isLoading(false);
            }
        });

        //get images
        $.ajax({
            url: "getImages",
            data: {
                accesToken: self.accesToken(),
                tags: self.tags(),
                following: self.isFollowing(),
                dateTimeFrom: format(toUTC(self.calculateDateFrom())),
                dateTimeTo: format(toUTC(self.calculateDateTo()))
            },
            dataType: "json",
            success: function (data) {
                self.images(data);
                setUsersAndPosts();

                self.isLoading(false);
                self.isSearchDone(true);
                self.winnersAmount(1);

                if(self.images().length > 0){
                    collapsible('#chooseLucky-collapsible', 'show');
                    collapsible('#content-collapsible', 'show');
                }
                collapsible('#search-info-collapsible', 'show');
            },
            error: function () {
                alert("getImages error");
                self.isLoading(false);
                l.ladda('stop');
            },
            timeout: 200000
        });
    };

    //select winners action
    self.selectAction = function () {
        if(self.winnersSelectionType() === "users"){
            var luckyUsers = shuffle(self.usersAndPosts()).slice(0, self.winnersAmount());
            var winnerPosts = luckyUsers.map(function(x){return randomElement(x.posts)});
            self.winners(winnerPosts);
        }else{
            var luckyPosts = shuffle(self.images()).slice(0, self.winnersAmount());
            self.winners(luckyPosts);
        }
        collapsible('#winners-content-collapsible', 'show');
    };

    //acces token
    self.accesToken = ko.observable();
    self.handleToken = ko.computed (function(){
        var params = parseParams();

        if(!params.accesToken){
            window.location = "/";
        }else{
            self.accesToken(params.accesToken);
        }
    });
};

ko.applyBindings(randogramViewModel);

//Activate datetimepickers and make them linked to each other
//$('#dateTimeFrom').datetimepicker();
$('#basicDateFrom').datetimepicker();
$('#advancedDateFrom').datetimepicker();
$('#advancedDateTo').datetimepicker();

//$(document).ready(function() {
//    var viewModel = function() {
//        self = this;
//
//        self.percentage = ko.observable(0);
//
//        self.percentage.subscribe(function () {
//            if (self.percentage() === 100) {
//                clearTimeout(timer);
//            }
//        });
//    };
//
//    var timer = setInterval(function() { viewModelObj.percentage(viewModelObj.percentage() + 1); }, 50);
//});

Ladda.bind( '#srch-btn', {
    callback: function( instance ) {
        var progress = 0;
        var interval = setInterval( function() {
            progress = randogramViewModel.progress();
            instance.setProgress( progress );
            if( progress === 1 ) {
                instance.stop();
                clearInterval( interval );
            }
        }, 200 );
    }
} );<|endoftext|>


<commit_before>/*global angular*/
/*global _*/
/*global moment*/
/*global $U*/
angular.module('service-app-basic-crud', []).service('appBasicCrud', ['$rootScope', '$log', 'appUtils', 'appSettings', 'fileUpload', 'appApi', 'appGui', 'appRouter', 'appSession', function($rootScope, $log, appUtils, appSettings, fileUpload, appApi, appGui, appRouter, appSession) {
    const TEXT = {
        DATA_SAVED: 'Saved',
        GENERIC_ERROR: '',
        WARNING_ERROR: ''
    };
    var self = function(settings) {
        var s = settings.scope;
        s.isBasicCrud = true;
        s.data = {};
        s.save = function() {
            //if (!s.data.address) return appGui.warningMessage(MESSAGE.ADDRESS_REQUIRED);
            appApi.saveCollection(settings.collectionName, s.data).then(function(result) {
                appGui.infoMessage(TEXT.DATA_SAVED);
            }).error(function(res) {
                appGui.errorMessage(TEXT.GENERIC_ERROR);
            }).on('validate', function(msg) {
                appGui.warningMessage(TEXT.WARNING_ERROR || msg);
            });
        };
        s.isEdit = () => {
            return s.data && s.data._id;
        };
        s.isDetailView = () => s._isDetailView || false;
        s.isAdmin = () => appSession.hasRole('admin');
        s.showSave = () => {
            return settings.actions && settings.actions.save;
        };
        s.isNew = () => s.data && !s.data._id;

        function get_id() {
            var params = appRouter.params();
            if (params.item && params.item._id) {
                return params.item._id;
            }
            else {
                return settings.$routeParams && settings.$routeParams.id;
            }
        }

        function onFetchSuccess(result) {
            s.data = result;
            appRouter.clearItem();
        }

        var _id = get_id();
        if (_id && _id.toString() != '-1' && _id.toString() != 'new') {
            var payload = Object.assign({}, settings.payloads && settings.payloads.get || {});
            if (!settings.get || !settings.get.field) {
                appApi.getById(settings.collectionName, _id, payload).then(onFetchSuccess);
            }
            else {
                payload[settings.get.field] = _id;
                appApi.ctrl(settings.collectionName, 'get', payload).then(onFetchSuccess);
            }
            s._isDetailView = true;
            s.$emit('basic-crud-loaded');
        }
        else {

            if (_id.toString() == 'new') {
                s._isDetailView = true;
            }
            else {
                s._isDetailView = false;
            }
            s.$emit('basic-crud-loaded');

        }
    };
    $rootScope._basicCrud = self;
    return self;

}]);
<commit_msg>common-xxx-angular-basic-crud-srv-improved<commit_after>/*global angular*/
/*global _*/
/*global moment*/
/*global $U*/
angular.module('service-app-basic-crud', []).service('appBasicCrud', ['$rootScope', '$log', 'appUtils', 'appSettings', 'fileUpload', 'appApi', 'appGui', 'appRouter', 'appSession', function($rootScope, $log, appUtils, appSettings, fileUpload, appApi, appGui, appRouter, appSession) {
    const TEXT = {
        DATA_SAVED: 'Saved',
        GENERIC_ERROR: '',
        WARNING_ERROR: ''
    };
    var self = function(settings) {
        var s = settings.scope;
        s.isBasicCrud = true;
        s.data = {};
        s.save = function() {

            if (settings && settings.validate && settings.validate.save) {
                settings.validate.save(s.data, () => {
                    _save();
                });
            }
            else {
                $log.warn('no-validate', settings);
                _save();
            }

            function _save() {
                //if (!s.data.address) return appGui.warningMessage(MESSAGE.ADDRESS_REQUIRED);
                appApi.saveCollection(settings.collectionName, s.data).then(function(result) {
                    s.data = result;
                    appGui.infoMessage(TEXT.DATA_SAVED);
                }).error(function(res) {
                    appGui.errorMessage(TEXT.GENERIC_ERROR);
                }).on('validate', function(msg) {
                    appGui.warningMessage(TEXT.WARNING_ERROR || msg);
                });
            }
        };
        s.isEdit = () => {
            return s.data && s.data._id;
        };
        s.isDetailView = () => s._isDetailView || false;
        s.isAdmin = () => appSession.hasRole('admin');
        s.showSave = () => {
            return settings.actions && settings.actions.save;
        };
        s.isNew = () => s.data && !s.data._id;

        function get_id() {
            var params = appRouter.params();
            if (params.item && params.item._id) {
                return params.item._id;
            }
            else {
                return settings.$routeParams && settings.$routeParams.id;
            }
        }

        function onFetchSuccess(result) {
            s.data = result;
            appRouter.clearItem();
        }

        var _id = get_id();
        if (_id && _id.toString() != '-1' && _id.toString() != 'new') {
            var payload = Object.assign({}, settings.payloads && settings.payloads.get || {});
            if (!settings.get || !settings.get.field) {
                appApi.getById(settings.collectionName, _id, payload).then(onFetchSuccess);
            }
            else {
                payload[settings.get.field] = _id;
                appApi.ctrl(settings.collectionName, 'get', payload).then(onFetchSuccess);
            }
            s._isDetailView = true;
            s.$emit('basic-crud-loaded');
        }
        else {

            if (_id.toString() == 'new') {
                s._isDetailView = true;
            }
            else {
                s._isDetailView = false;
            }
            s.$emit('basic-crud-loaded');

        }
    };
    $rootScope._basicCrud = self;
    return self;

}]);
<|endoftext|>


<commit_before>"use strict";

const array = require("retsu"),
	defer = require("tiny-defer"),
	lru = require("tiny-lru"),
	path = require("path"),
	http = require("http"),
	mmh3 = require("murmurhash3js").x86.hash32,
	utility = require(path.join(__dirname, "utility.js")),
	regex = require(path.join(__dirname, "regex.js")),
	all = "all",
	verbs = ["DELETE", "GET", "POST", "PUT", "PATCH"];

class Woodland {
	constructor (defaultHost, defaultHeaders, cacheSize, seed) {
		this.blacklisted = new Set();
		this.cache = lru(cacheSize);
		this.defaultHost = defaultHost;
		this.defaultHeaders = Object.keys(defaultHeaders).map(key => [key, defaultHeaders[key]]);
		this.hosts = new Map();
		this.permissions = lru(cacheSize);
		this.middleware = new Map();
		this.onclose = () => {};
		this.onerror = (req, res, err) => {
			const numeric = !isNaN(err.message),
				status = numeric ? Number(err.message) : 500,
				body = numeric ? http.STATUS_CODES[status] : err.message;

			res.writeHead(status);
			res.end(body);
		};
		this.onfinish = () => {};
		this.seed = seed;
	}

	allowed (method, uri, host, override = false) {
		return this.routes(uri, host, method, override).filter(i => !this.blacklisted.has(i.hash || this.hash(i))).length > 0;
	}

	allows (uri, host, override = false) {
		let result = !override ? this.permissions.get(host + "_" + uri) : undefined;

		if (override || !result) {
			result = verbs.filter(i => this.allowed(i, uri, host, override)).join(", ").replace("GET", "GET, HEAD, OPTIONS");
			this.permissions.set(host + "_" + uri, result);
		}

		return result;
	}

	blacklist (fn) {
		let hfn;

		if (fn.hash) {
			hfn = fn.hash;
		} else {
			hfn = fn.hash = this.hash(fn.toString());
		}

		if (!this.blacklisted.has(hfn)) {
			this.blacklisted.add(hfn);
		}

		return hfn;
	}

	decorate (req, res) {
		let parsed = utility.parse(this.url(req));

		// Decorating useful hints
		req.body = "";
		req.ip = req.headers["x-forwarded-for"] ? array.last(req.headers["x-forwarded-for"].split(/\s*,\s*/g)) : req.connection.remoteAddress;
		req.parsed = parsed;
		req.query = parsed.query;
		req.host = this.host(parsed.hostname);
		req.allow = this.allows(req.parsed.pathname, req.host);

		// Express interop
		res.header = res.setHeader;
		res.locals = {};

		// Setting headers
		this.defaultHeaders.forEach(header => res.header(header[0], header[1]));
		res.header("Allow", req.allow);
	}

	hash (arg) {
		return mmh3(arg, this.seed);
	}

	host (arg) {
		let result = "";

		this.hosts.forEach((reg, host) => {
			if (!result && reg.test(arg)) {
				result = host;
			}
		});

		return result || this.defaultHost;
	}

	route (req, res) {
		let deferred = defer(),
			byRef = [req, res],
			method = regex.head.test(req.method) ? "GET" : req.method,
			middleware;

		this.decorate(byRef[0], byRef[1]);
		middleware = array.iterator(this.routes(req.parsed.pathname, req.host, method));

		function last (err) {
			let errorCode, status;

			if (!err) {
				deferred.reject(req.allow.indexOf("GET") > -1 ? new Error(405) : new Error(404));
			} else {
				errorCode = !isNaN(err.message) ? err.message : http.STATUS_CODES[err.message || err] || 500;
				status = res.statusCode >= 400 ? res.statusCode : errorCode;
				deferred.reject(new Error(status));
			}
		}

		let next = err => {
			process.nextTick(() => {
				let arity = 3,
					step = middleware.next();

				if (!res._header && !step.done) {
					if (err) {
						arity = utility.getArity(step.value);
						do {
							arity = utility.getArity(step.value);
						} while (arity < 4 && (step = middleware.next()) && !step.done);
					}

					if (!step.done) {
						if (err) {
							if (arity === 4) {
								try {
									step.value(err, req, res, next);
								} catch (e) {
									next(e);
								}
							} else {
								last(err);
							}
						} else {
							try {
								step.value(req, res, next);
							} catch (e) {
								next(e);
							}
						}
					} else {
						last(err);
					}
				} else if (!res._header) {
					last(err);
				}
			});
		};

		res.on("close", () => {
			this.onclose(req, res);
			deferred.reject(new Error("Connection closed before response was flushed"));
		});

		res.on("finish", () => {
			deferred.resolve();
		});

		next();

		return deferred.promise.then(() => {
			this.onfinish(req, res);

			return [req, res];
		}, err => {
			this.onerror(req, res, err);

			throw err;
		});
	}

	routes (uri, host, method, override = false) {
		let id = method + ":" + host + ":" + uri,
			cached = !override ? this.cache.get(id) : undefined,
			allMap, hostMap, result;

		if (cached) {
			result = cached;
		} else {
			allMap = this.middleware.get(all) || new Map();
			hostMap = this.middleware.get(host) || new Map();
			result = [];

			[allMap.get(all), allMap.get(method), hostMap.get(all), hostMap.get(method)].forEach(map => {
				if (map) {
					Array.from(map.keys()).filter(route => {
						let valid;

						try {
							valid = new RegExp("^" + route + "$", "i").test(uri);
						} catch (e) {
							valid = new RegExp("^" + utility.escape(route) + "$", "i").test(uri);
						}

						return valid;
					}).forEach(route => {
						result = result.concat(map.get(route));
					});
				}
			});

			this.cache.set(id, result);
		}

		return result;
	}

	setHost (arg) {
		if (!this.hosts.has(arg)) {
			this.hosts.set(arg, new RegExp("^" + arg.replace(/\*/g, ".*") + "$"));
		}

		return this;
	}

	use (rpath, fn, method, host) {
		let lpath = rpath,
			lfn = fn,
			lmethod = method,
			lhost = host,
			mhost, mmethod;

		if (typeof lpath !== "string") {
			lmethod = lfn;
			lfn = lpath;
			lpath = "/.*";
		}

		lmethod = lmethod ? lmethod.toUpperCase() : "GET";
		lhost = lhost || all;

		if (typeof lfn !== "function" && (lfn && typeof lfn.handle !== "function")) {
			throw new Error("Invalid middleware");
		}

		if (!this.middleware.has(lhost)) {
			this.middleware.set(lhost, new Map());
		}

		mhost = this.middleware.get(lhost);

		if (!mhost.has(lmethod)) {
			mhost.set(lmethod, new Map());
		}

		mmethod = mhost.get(lmethod);

		if (!mmethod.has(lpath)) {
			mmethod.set(lpath, []);
		}

		if (lfn.handle) {
			lfn = lfn.handle;
		}

		lfn.hash = this.hash(lfn.toString());
		mmethod.get(lpath).push(lfn);

		return this;
	}

	url (req) {
		let header = req.headers.authorization || "",
			auth = "",
			token;

		if (!utility.isEmpty(header)) {
			token = header.split(regex.space).pop() || "";
			auth = new Buffer(token, "base64").toString();

			if (!utility.isEmpty(auth)) {
				auth += "@";
			}
		}

		return "http" + /*(this.config.ssl.cert ? "s" : "") +*/ "://" + auth + req.headers.host + req.url;
	}
}

module.exports = Woodland;
<commit_msg>Tweaking `url()`<commit_after>"use strict";

const array = require("retsu"),
	defer = require("tiny-defer"),
	lru = require("tiny-lru"),
	path = require("path"),
	http = require("http"),
	mmh3 = require("murmurhash3js").x86.hash32,
	utility = require(path.join(__dirname, "utility.js")),
	regex = require(path.join(__dirname, "regex.js")),
	all = "all",
	verbs = ["DELETE", "GET", "POST", "PUT", "PATCH"];

class Woodland {
	constructor (defaultHost, defaultHeaders, cacheSize, seed) {
		this.blacklisted = new Set();
		this.cache = lru(cacheSize);
		this.defaultHost = defaultHost;
		this.defaultHeaders = Object.keys(defaultHeaders).map(key => [key, defaultHeaders[key]]);
		this.hosts = new Map();
		this.permissions = lru(cacheSize);
		this.middleware = new Map();
		this.onclose = () => {};
		this.onerror = (req, res, err) => {
			const numeric = !isNaN(err.message),
				status = numeric ? Number(err.message) : 500,
				body = numeric ? http.STATUS_CODES[status] : err.message;

			res.writeHead(status);
			res.end(body);
		};
		this.onfinish = () => {};
		this.seed = seed;
	}

	allowed (method, uri, host, override = false) {
		return this.routes(uri, host, method, override).filter(i => !this.blacklisted.has(i.hash || this.hash(i))).length > 0;
	}

	allows (uri, host, override = false) {
		let result = !override ? this.permissions.get(host + "_" + uri) : undefined;

		if (override || !result) {
			result = verbs.filter(i => this.allowed(i, uri, host, override)).join(", ").replace("GET", "GET, HEAD, OPTIONS");
			this.permissions.set(host + "_" + uri, result);
		}

		return result;
	}

	blacklist (fn) {
		let hfn;

		if (fn.hash) {
			hfn = fn.hash;
		} else {
			hfn = fn.hash = this.hash(fn.toString());
		}

		if (!this.blacklisted.has(hfn)) {
			this.blacklisted.add(hfn);
		}

		return hfn;
	}

	decorate (req, res) {
		let parsed = utility.parse(this.url(req));

		// Decorating useful hints
		req.body = "";
		req.ip = req.headers["x-forwarded-for"] ? array.last(req.headers["x-forwarded-for"].split(/\s*,\s*/g)) : req.connection.remoteAddress;
		req.parsed = parsed;
		req.query = parsed.query;
		req.host = this.host(parsed.hostname);
		req.allow = this.allows(req.parsed.pathname, req.host);

		// Express interop
		res.header = res.setHeader;
		res.locals = {};

		// Setting headers
		this.defaultHeaders.forEach(header => res.header(header[0], header[1]));
		res.header("Allow", req.allow);
	}

	hash (arg) {
		return mmh3(arg, this.seed);
	}

	host (arg) {
		let result = "";

		this.hosts.forEach((reg, host) => {
			if (!result && reg.test(arg)) {
				result = host;
			}
		});

		return result || this.defaultHost;
	}

	route (req, res) {
		let deferred = defer(),
			byRef = [req, res],
			method = regex.head.test(req.method) ? "GET" : req.method,
			middleware;

		this.decorate(byRef[0], byRef[1]);
		middleware = array.iterator(this.routes(req.parsed.pathname, req.host, method));

		function last (err) {
			let errorCode, status;

			if (!err) {
				deferred.reject(req.allow.indexOf("GET") > -1 ? new Error(405) : new Error(404));
			} else {
				errorCode = !isNaN(err.message) ? err.message : http.STATUS_CODES[err.message || err] || 500;
				status = res.statusCode >= 400 ? res.statusCode : errorCode;
				deferred.reject(new Error(status));
			}
		}

		let next = err => {
			process.nextTick(() => {
				let arity = 3,
					step = middleware.next();

				if (!res._header && !step.done) {
					if (err) {
						arity = utility.getArity(step.value);
						do {
							arity = utility.getArity(step.value);
						} while (arity < 4 && (step = middleware.next()) && !step.done);
					}

					if (!step.done) {
						if (err) {
							if (arity === 4) {
								try {
									step.value(err, req, res, next);
								} catch (e) {
									next(e);
								}
							} else {
								last(err);
							}
						} else {
							try {
								step.value(req, res, next);
							} catch (e) {
								next(e);
							}
						}
					} else {
						last(err);
					}
				} else if (!res._header) {
					last(err);
				}
			});
		};

		res.on("close", () => {
			this.onclose(req, res);
			deferred.reject(new Error("Connection closed before response was flushed"));
		});

		res.on("finish", () => {
			deferred.resolve();
		});

		next();

		return deferred.promise.then(() => {
			this.onfinish(req, res);

			return [req, res];
		}, err => {
			this.onerror(req, res, err);

			throw err;
		});
	}

	routes (uri, host, method, override = false) {
		let id = method + ":" + host + ":" + uri,
			cached = !override ? this.cache.get(id) : undefined,
			allMap, hostMap, result;

		if (cached) {
			result = cached;
		} else {
			allMap = this.middleware.get(all) || new Map();
			hostMap = this.middleware.get(host) || new Map();
			result = [];

			[allMap.get(all), allMap.get(method), hostMap.get(all), hostMap.get(method)].forEach(map => {
				if (map) {
					Array.from(map.keys()).filter(route => {
						let valid;

						try {
							valid = new RegExp("^" + route + "$", "i").test(uri);
						} catch (e) {
							valid = new RegExp("^" + utility.escape(route) + "$", "i").test(uri);
						}

						return valid;
					}).forEach(route => {
						result = result.concat(map.get(route));
					});
				}
			});

			this.cache.set(id, result);
		}

		return result;
	}

	setHost (arg) {
		if (!this.hosts.has(arg)) {
			this.hosts.set(arg, new RegExp("^" + arg.replace(/\*/g, ".*") + "$"));
		}

		return this;
	}

	use (rpath, fn, method, host) {
		let lpath = rpath,
			lfn = fn,
			lmethod = method,
			lhost = host,
			mhost, mmethod;

		if (typeof lpath !== "string") {
			lmethod = lfn;
			lfn = lpath;
			lpath = "/.*";
		}

		lmethod = lmethod ? lmethod.toUpperCase() : "GET";
		lhost = lhost || all;

		if (typeof lfn !== "function" && (lfn && typeof lfn.handle !== "function")) {
			throw new Error("Invalid middleware");
		}

		if (!this.middleware.has(lhost)) {
			this.middleware.set(lhost, new Map());
		}

		mhost = this.middleware.get(lhost);

		if (!mhost.has(lmethod)) {
			mhost.set(lmethod, new Map());
		}

		mmethod = mhost.get(lmethod);

		if (!mmethod.has(lpath)) {
			mmethod.set(lpath, []);
		}

		if (lfn.handle) {
			lfn = lfn.handle;
		}

		lfn.hash = this.hash(lfn.toString());
		mmethod.get(lpath).push(lfn);

		return this;
	}

	url (req) {
		let header = req.headers.authorization || "",
			auth = "",
			token;

		if (!utility.isEmpty(header)) {
			token = header.split(regex.space).pop() || "";
			auth = new Buffer(token, "base64").toString();

			if (!utility.isEmpty(auth)) {
				auth += "@";
			}
		}

		return "http://" + auth + req.headers.host + req.url;
	}
}

module.exports = Woodland;
<|endoftext|>