<commit_before>'use strict';

/**
 * @module ServiceRequest
 * @name ServiceRequest
 * @description An issue(or service request) reported by civilian
 *              e.g Water Leakage occur at a particular area
 *
 * @author lally elias <lallyelias87@mail.com>
 * @since 0.1.0
 * @version 0.1.0
 * @public
 */

//TODO make service request to support call log in a call center
//TODO migrate location to use GeoJSON schema
//TODO obtain geo-data from jurisdiction if not available(or set)
//TODO add service group

//dependencies
const path = require('path');
const _ = require('lodash');
const async = require('async');
const mongoose = require('mongoose');
const shortid = require('shortid');
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;
const MediaSchema = require(path.join(__dirname, 'schemas', 'media_schema'));

/**
 * @name ServiceRequestSchema
 * @type {Schema}
 * @since 0.1.0
 * @version 0.1.0
 * @private
 */
const ServiceRequestSchema = new Schema({

  /**
   * @name jurisdiction
   * @description A jurisdiction responsible in handling service
   *              request(issue)
   *
   * @type {Object}
   * @see {@link Jurisdiction}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  jurisdiction: {
    type: ObjectId,
    ref: 'Jurisdiction',
    autoset: true,
    required: true,
    index: true,
    exists: true,
    autopopulate: {
      select: 'code name domain'
    }
  },

  /**
   * @name service
   * @description A service undewhich request(issue) belongs to
   * @type {Object}
   * @see {@link Service}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  service: {
    type: ObjectId,
    ref: 'Service',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'code name color group'
    }
  },

  /**
   * @name call
   * @description log operator call details at a call center
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  call: {
    /**
     * @name startedAt
     * @description time when a call received at the call center
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    startedAt: {
      type: Date,
      index: true
    },

    /**
     * @name endedAt
     * @description time when a call center operator end the call
     *              and release a reporter
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    endedAt: {
      type: Date,
      index: true
    }
  }

  /**
   * @name reporter
   * @description A party i.e civilian, customer etc which reported an
   *              issue(service request)
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  reporter: {
    /**
     * @name name
     * @description Full name name of the reporter.
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    name: {
      type: String,
      index: true,
      searchable: true
    },

    /**
     * @name phone
     * @description A mobile phone number of the reporter.
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    phone: {
      type: String,
      index: true,
      searchable: true
    },

    /**
     * @name email
     * @description An email address of the reporter.
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    email: {
      type: String,
      index: true,
      searchable: true
    },

    /**
     * @name account
     * @description A jurisdiction internal associated account id of the
     *              party submitting the request(issue).
     *
     *              This help a jurisdiction to link a reporter with the
     *              internal CRM.
     *
     *              When account id is available a reporter will be treated as
     *              a customer and not a normal civilian.
     *
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    account: {
      type: String,
      index: true,
      searchable: true
    }
  },

  /**
   * @name operator
   * @description A party oversee the work on the service request(issue).
   *
   *              It also a party that is answerable for the progress and
   *              status of the service request(issue) to a reporter.
   *
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  operator: {
    type: ObjectId,
    ref: 'Party',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name assignee
   * @description A party assigned to work on the service request(issue).
   *
   *              It also a party that is answerable for the progress and
   *              status of the service request(issue).
   *
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  assignee: {
    type: ObjectId,
    ref: 'Party',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name code
   * @description A unique human readable identifier of the
   *              service request(issue).
   *
   *              It mainly used by reporter to query for status and
   *              progress of the reported issue
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  code: {
    type: String,
    unique: true,
    required: true,
    trim: true,
    uppercase: true,
    searchable: true
  },

  /**
   * @name description
   * @description A detailed human readable explanation about the
   *              service request(issue)
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  description: {
    type: String,
    index: true,
    trim: true,
    required: true,
    searchable: true
  },

  /**
   * @name address
   * @description A human entered address or description of location
   *              where service request(issue) happened.
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  address: {
    type: String,
    trim: true,
    index: true,
    searchable: true
  },

  /**
   * @name location
   * @description A longitude and latitude pair of the location of a
   *              service request(issue).
   *
   *             The order of adding longitude and latitude in the array must
   *             be <longitude> , <latitude> and not otherwise.
   *
   *
   * @type {Object}
   * @see  {@link https://docs.mongodb.com/manual/applications/geospatial-indexes/}
   * @see {@link https://docs.mongodb.com/manual/reference/operator/query-geospatial/}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  location: {
    type: [Number],
    index: '2dsphere'
  },

  /**
   * @name status
   * @description A current status of the service request(issue)
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  status: {
    type: ObjectId,
    ref: 'Status',
    autoset: true,
    exists: true,
    index: true,
    autopopulate: true
  },

  /**
   * @name priority
   * @description A priority of the service request(issue).
   *
   *              It used to weight a service request(issue) relative
   *              to other(s).
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  priority: {
    type: ObjectId,
    ref: 'Priority',
    autoset: true,
    exists: true,
    index: true,
    autopopulate: true
  },

  /**
   * @name attachments
   * @description Associated file(s) with service request(issue)
   * @type {Array}
   * @see {@link Media}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  attachments: {
    type: [MediaSchema],
    index: true
  },

  /**
   * @name comments
   * @description Associated comment(s) with service request(issue)
   * @type {Array}
   * @see {@link Comment}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */

  /**
   * @name resolvedAt
   * @description A time when the issue was resolved
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  resolvedAt: {
    type: Date,
    index: true
  }

}, { timestamps: true, emitIndexErrors: true });

//-----------------------------------------------------------------------------
// ServiceRequestSchema Virtuals
//-----------------------------------------------------------------------------

/**
 * @name longitude
 * @description obtain service request(issue) longitude
 * @type {Number}
 * @since 0.1.0
 * @version 0.1.0
 */
ServiceRequestSchema.virtual('longitude').get(function () {
  return this.location ? this.location[0] : null;
});

/**
 * @name latitude
 * @description obtain service request(issue) latitude
 * @type {Number}
 * @since 0.1.0
 * @version 0.1.0
 */
ServiceRequestSchema.virtual('latitude').get(function () {
  return this.location ? this.location[1] : null;
});

//-----------------------------------------------------------------------------
// ServiceRequestSchema Hooks
//-----------------------------------------------------------------------------

ServiceRequestSchema.pre('validate', function (next) {

  //set service request code
  //TODO update code algorithm to use daily rotate increments
  if (_.isEmpty(this.code)) {
    this.code = [
        shortid.generate(),
        shortid.generate()
      ].join('')
      .replace(/-|_/g, '')
      .substr(0, 8)
      .toUpperCase();
  }

  //ensure jurisdiction from service
  const jurisdiction = _.get(this.service, 'jurisdiction');
  if (!this.jurisdiction && _.get(this.service, 'jurisdiction')) {
    this.jurisdiction = jurisdiction;
  }

  //set default status & priority if not set
  if (!this.status || !this.priority) {
    async.parallel({
      status: function findDefaultStatus(then) {
        const Status = mongoose.model('Status');
        Status.findDefault(then);
      },
      priority: function findDefaultPriority(then) {
        const Priority = mongoose.model('Priority');
        Priority.findDefault(then);
      }
    }, function (error, result) {
      if (error) {
        next(error);
      } else {
        this.status = (this.status || result.status || undefined);
        this.priority = (this.priority || result.priority || undefined);
        next();
      }
    }.bind(this));

  }

  //continue
  else {
    next();
  }

});

ServiceRequestSchema.post('save', function (doc, next) {
  //TODO notify CRM to update details based on the account id
  //TODO send(queue) notification
  //TODO send service request code to reporte(sms or email)
  next();
});

//-----------------------------------------------------------------------------
// ServiceRequestSchema Static Properties & Methods
//-----------------------------------------------------------------------------

//TODO use aggregation
//TODO use status and priority model
ServiceRequestSchema.statics.summary = function (done) {

  //references
  const Service = mongoose.model('Service');
  const Status = mongoose.model('Status');
  const ServiceRequest = mongoose.model('ServiceRequest');

  //TODO use aggregation

  async.parallel({
    services: function (next) {
      Service
        .find({})
        .exec(function (error, services) {
          if (error) {
            done(null, {});
          } else {
            const works = {};
            _.forEach(services, function (service) {
              works[service._id] = function (then) {
                ServiceRequest
                  .count({ service: service._id }, then);
              };
            });
            async.parallel(works, next);
          }
        });
    },

    statuses: function (next) {
      Status
        .find({})
        .exec(function (error, statuses) {
          if (error) {
            done(null, {});
          } else {
            const works = {};
            _.forEach(statuses, function (status) {
              works[status._id] = function (then) {
                ServiceRequest
                  .count({ status: status._id }, then);
              };
            });
            async.parallel(works, next);
          }
        });
    }
  }, done);

};

/**
 * @name ServiceRequest
 * @description register ServiceRequestSchema and initialize ServiceRequest
 *              model
 * @type {Model}
 * @since 0.1.0
 * @version 0.1.0
 * @public
 */
module.exports = mongoose.model('ServiceRequest', ServiceRequestSchema);
<commit_msg>add communication method into service request<commit_after>'use strict';

/**
 * @module ServiceRequest
 * @name ServiceRequest
 * @description An issue(or service request) reported by civilian
 *              e.g Water Leakage occur at a particular area
 *
 * @author lally elias <lallyelias87@mail.com>
 * @since 0.1.0
 * @version 0.1.0
 * @public
 */

//TODO make service request to support call log in a call center
//TODO migrate location to use GeoJSON schema
//TODO obtain geo-data from jurisdiction if not available(or set)
//TODO add service group

//dependencies
const path = require('path');
const _ = require('lodash');
const async = require('async');
const mongoose = require('mongoose');
const shortid = require('shortid');
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;
const MediaSchema = require(path.join(__dirname, 'schemas', 'media_schema'));

//contact methods
const CONTACT_METHOD_PHONE = 'Phone';
const CONTACT_METHOD_EMAIL = 'Email';
const CONTACT_METHOD_SMS = 'SMS';
const CONTACT_METHOD_USSD = 'USSD';
const CONTACT_METHOD_VISIT = 'Visit';
const CONTACT_METHOD_LETTER = 'Letter';
const CONTACT_METHOD_FAX = 'Fax';

const CONTACT_METHODS = [
  CONTACT_METHOD_PHONE, CONTACT_METHOD_EMAIL,
  CONTACT_METHOD_SMS, CONTACT_METHOD_USSD, CONTACT_METHOD_VISIT,
  CONTACT_METHOD_LETTER, CONTACT_METHOD_FAX
];

/**
 * @name ServiceRequestSchema
 * @type {Schema}
 * @since 0.1.0
 * @version 0.1.0
 * @private
 */
const ServiceRequestSchema = new Schema({

  /**
   * @name jurisdiction
   * @description A jurisdiction responsible in handling service
   *              request(issue)
   *
   * @type {Object}
   * @see {@link Jurisdiction}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  jurisdiction: {
    type: ObjectId,
    ref: 'Jurisdiction',
    autoset: true,
    required: true,
    index: true,
    exists: true,
    autopopulate: {
      select: 'code name domain'
    }
  },

  /**
   * @name service
   * @description A service undewhich request(issue) belongs to
   * @type {Object}
   * @see {@link Service}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  service: {
    type: ObjectId,
    ref: 'Service',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'code name color group'
    }
  },

  /**
   * @name call
   * @description log operator call details at a call center
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  call: {
    /**
     * @name startedAt
     * @description time when a call received at the call center
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    startedAt: {
      type: Date,
      index: true
    },

    /**
     * @name endedAt
     * @description time when a call center operator end the call
     *              and release a reporter
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    endedAt: {
      type: Date,
      index: true
    }
  },

  /**
   * @name reporter
   * @description A party i.e civilian, customer etc which reported an
   *              issue(service request)
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  reporter: {
    /**
     * @name name
     * @description Full name name of the reporter.
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    name: {
      type: String,
      index: true,
      searchable: true
    },

    /**
     * @name phone
     * @description A mobile phone number of the reporter.
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    phone: {
      type: String,
      index: true,
      searchable: true
    },

    /**
     * @name email
     * @description An email address of the reporter.
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    email: {
      type: String,
      index: true,
      searchable: true
    },

    /**
     * @name account
     * @description A jurisdiction internal associated account id of the
     *              party submitting the request(issue).
     *
     *              This help a jurisdiction to link a reporter with the
     *              internal CRM.
     *
     *              When account id is available a reporter will be treated as
     *              a customer and not a normal civilian.
     *
     * @type {Object}
     * @private
     * @since 0.1.0
     * @version 0.1.0
     */
    account: {
      type: String,
      index: true,
      searchable: true
    }
  },

  /**
   * @name operator
   * @description A party oversee the work on the service request(issue).
   *
   *              It also a party that is answerable for the progress and
   *              status of the service request(issue) to a reporter.
   *
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  operator: {
    type: ObjectId,
    ref: 'Party',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name assignee
   * @description A party assigned to work on the service request(issue).
   *
   *              It also a party that is answerable for the progress and
   *              status of the service request(issue).
   *
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  assignee: {
    type: ObjectId,
    ref: 'Party',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name code
   * @description A unique human readable identifier of the
   *              service request(issue).
   *
   *              It mainly used by reporter to query for status and
   *              progress of the reported issue
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  code: {
    type: String,
    unique: true,
    required: true,
    trim: true,
    uppercase: true,
    searchable: true
  },

  /**
   * @name description
   * @description A detailed human readable explanation about the
   *              service request(issue)
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  description: {
    type: String,
    index: true,
    trim: true,
    required: true,
    searchable: true
  },

  /**
   * @name address
   * @description A human entered address or description of location
   *              where service request(issue) happened.
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  address: {
    type: String,
    trim: true,
    index: true,
    searchable: true
  },

  /**
   * @name method
   * @description A communication(contact) method(mechanism) used by a reporter
   *              to report the issue
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  method: {
    type: String,
    enum: CONTACT_METHODS,
    default: CONTACT_METHOD_PHONE,
    index: true
  },

  /**
   * @name location
   * @description A longitude and latitude pair of the location of a
   *              service request(issue).
   *
   *             The order of adding longitude and latitude in the array must
   *             be <longitude> , <latitude> and not otherwise.
   *
   *
   * @type {Object}
   * @see  {@link https://docs.mongodb.com/manual/applications/geospatial-indexes/}
   * @see {@link https://docs.mongodb.com/manual/reference/operator/query-geospatial/}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  location: {
    type: [Number],
    index: '2dsphere'
  },

  /**
   * @name status
   * @description A current status of the service request(issue)
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  status: {
    type: ObjectId,
    ref: 'Status',
    autoset: true,
    exists: true,
    index: true,
    autopopulate: true
  },

  /**
   * @name priority
   * @description A priority of the service request(issue).
   *
   *              It used to weight a service request(issue) relative
   *              to other(s).
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  priority: {
    type: ObjectId,
    ref: 'Priority',
    autoset: true,
    exists: true,
    index: true,
    autopopulate: true
  },

  /**
   * @name attachments
   * @description Associated file(s) with service request(issue)
   * @type {Array}
   * @see {@link Media}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  attachments: {
    type: [MediaSchema],
    index: true
  },

  /**
   * @name comments
   * @description Associated comment(s) with service request(issue)
   * @type {Array}
   * @see {@link Comment}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */

  /**
   * @name resolvedAt
   * @description A time when the issue was resolved
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  resolvedAt: {
    type: Date,
    index: true
  }

}, { timestamps: true, emitIndexErrors: true });

//-----------------------------------------------------------------------------
// ServiceRequestSchema Virtuals
//-----------------------------------------------------------------------------

/**
 * @name longitude
 * @description obtain service request(issue) longitude
 * @type {Number}
 * @since 0.1.0
 * @version 0.1.0
 */
ServiceRequestSchema.virtual('longitude').get(function () {
  return this.location ? this.location[0] : null;
});

/**
 * @name latitude
 * @description obtain service request(issue) latitude
 * @type {Number}
 * @since 0.1.0
 * @version 0.1.0
 */
ServiceRequestSchema.virtual('latitude').get(function () {
  return this.location ? this.location[1] : null;
});

//-----------------------------------------------------------------------------
// ServiceRequestSchema Hooks
//-----------------------------------------------------------------------------

ServiceRequestSchema.pre('validate', function (next) {

  //set service request code
  //TODO update code algorithm to use daily rotate increments
  if (_.isEmpty(this.code)) {
    this.code = [
        shortid.generate(),
        shortid.generate()
      ].join('')
      .replace(/-|_/g, '')
      .substr(0, 8)
      .toUpperCase();
  }

  //ensure jurisdiction from service
  const jurisdiction = _.get(this.service, 'jurisdiction');
  if (!this.jurisdiction && _.get(this.service, 'jurisdiction')) {
    this.jurisdiction = jurisdiction;
  }

  //set default status & priority if not set
  if (!this.status || !this.priority) {
    async.parallel({
      status: function findDefaultStatus(then) {
        const Status = mongoose.model('Status');
        Status.findDefault(then);
      },
      priority: function findDefaultPriority(then) {
        const Priority = mongoose.model('Priority');
        Priority.findDefault(then);
      }
    }, function (error, result) {
      if (error) {
        next(error);
      } else {
        this.status = (this.status || result.status || undefined);
        this.priority = (this.priority || result.priority || undefined);
        next();
      }
    }.bind(this));

  }

  //continue
  else {
    next();
  }

});

ServiceRequestSchema.post('save', function (doc, next) {
  //TODO notify customer details(DRM) to update details based on the account id
  //TODO send(queue) notification
  //TODO send service request code to reporte(sms or email)
  next();
});

//-----------------------------------------------------------------------------
// ServiceRequestSchema Static Properties & Methods
//-----------------------------------------------------------------------------

//contact methods constants
ServiceRequestSchema.statics.CONTACT_METHOD_PHONE = CONTACT_METHOD_PHONE;
ServiceRequestSchema.statics.CONTACT_METHOD_FAX = CONTACT_METHOD_FAX;
ServiceRequestSchema.statics.CONTACT_METHOD_LETTER = CONTACT_METHOD_LETTER;
ServiceRequestSchema.statics.CONTACT_METHOD_VISIT = CONTACT_METHOD_VISIT;
ServiceRequestSchema.statics.CONTACT_METHOD_SMS = CONTACT_METHOD_SMS;
ServiceRequestSchema.statics.CONTACT_METHOD_USSD = CONTACT_METHOD_USSD;
ServiceRequestSchema.statics.CONTACT_METHOD_EMAIL = CONTACT_METHOD_EMAIL;
ServiceRequestSchema.statics.CONTACT_METHODS = CONTACT_METHODS;

//TODO use aggregation
//TODO use status and priority model
ServiceRequestSchema.statics.summary = function (done) {

  //references
  const Service = mongoose.model('Service');
  const Status = mongoose.model('Status');
  const ServiceRequest = mongoose.model('ServiceRequest');

  //TODO use aggregation

  async.parallel({
    services: function (next) {
      Service
        .find({})
        .exec(function (error, services) {
          if (error) {
            done(null, {});
          } else {
            const works = {};
            _.forEach(services, function (service) {
              works[service._id] = function (then) {
                ServiceRequest
                  .count({ service: service._id }, then);
              };
            });
            async.parallel(works, next);
          }
        });
    },

    statuses: function (next) {
      Status
        .find({})
        .exec(function (error, statuses) {
          if (error) {
            done(null, {});
          } else {
            const works = {};
            _.forEach(statuses, function (status) {
              works[status._id] = function (then) {
                ServiceRequest
                  .count({ status: status._id }, then);
              };
            });
            async.parallel(works, next);
          }
        });
    }
  }, done);

};

/**
 * @name ServiceRequest
 * @description register ServiceRequestSchema and initialize ServiceRequest
 *              model
 * @type {Model}
 * @since 0.1.0
 * @version 0.1.0
 * @public
 */
module.exports = mongoose.model('ServiceRequest', ServiceRequestSchema);
<|endoftext|>


<commit_before>var jQuery = mimic(jQuery);

Screw.Unit(function() {
	describe('jquery', function() {
		it('should assert against selector', function() {
			when.	jQuery('.enqueued');
			then.	jQuery().usingSelector('.enqueued');
		});

		it('should fail to assert against selector', function() {
			given.	jQuery('.inqueued');
			when.	jQuery().usingSelector('.enqueued');
			then.	it.should.say('The selector ".enqueued" was expected but was not used!');
		});

		it('should allow assertions of a selector never being used', function() {
			when.	jQuery('.enqueued');
			then.	jQuery().usingSelector('.it').neverHappens();
		});

		it('should allow a mimic version of jquery to return a basic object', function() {
			when.	jQuery('.it')[1].value;
		});

		it('should fail as the a selector was used when it was expected to not be used', function() {
			given.	jQuery('.enqueued');
			when.	jQuery().usingSelector('.enqueued').neverHappens();
			then.	it.should.say('The selector ".enqueued" was expected to never be used, however it was!');
		});

		it('should allow for simple assertions', function() {
			when.	jQuery('.enqueued').show();
			then.	jQuery().usingSelector('.enqueued').should('show');
		});

		it('should fail as assertion is wrong', function() {
			given.	jQuery('.enqueued').show();
			when.	jQuery().usingSelector('.enqueued').should('show2');
			then.	it.should.say('The function "show2" was expected but did not get called!');
		});

		it('should allow for multiple assertions in one should', function() {
			when.	jQuery('.enqueued').show().hide();
			then.	jQuery().usingSelector('.enqueued').should('show').and('hide');
		});

		it('should fail when allowing for multiple assertions in one should', function() {
			given.	jQuery('.enqueued').show().hide();
			when.	jQuery().usingSelector('.enqueued').should('show').and('hide2');
			then.	it.should.say('The function "hide2" was expected but did not get called!');
		});

		it('should fail when doing multiple assertions in multiple shoulds', function() {
			given.	jQuery('.enqueued').show().hide();
			when.	jQuery().usingSelector('.enqueued').should('show')
			and.	jQuery().usingSelector('.enqueued').should('hide2');
			then.	it.should.say('The function "hide2" was expected but did not get called!');
		});

		it('should allow for multiple assersions in multiple shoulds', function() {
			when.	jQuery('.enqueued').show().hide();
			then.	jQuery().usingSelector('.enqueued').should('show')
			and.	jQuery().usingSelector('.enqueued').should('hide');
		});

		it('should allow for a single assertion across multiple jquery calls', function() {
			when.	jQuery('.enqueued').show();
			and.	jQuery('.enqueued').hide();
			then.	jQuery().usingSelector('.enqueued').should('hide')
			and.	jQuery().usingSelector('.enqueued').should('show');
		});

		it('should fail for a single assertion across multiple jquery calls', function() {
			given.	jQuery('.enqueued').show();
			and.	jQuery('.enqueued').hide();
			when.	jQuery().usingSelector('.enqueued').should('show2')
			and.	jQuery().usingSelector('.enqueued').should('hide');
			then.	it.should.say('The function "show2" was expected but did not get called!');
		});

		it('should allow for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').show('speed');
			then.	jQuery().usingSelector('.enqueued').should('show').using('speed');
		});

		it('should fail for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').show('sp33d');
			when.	jQuery().usingSelector('.enqueued').should('show').using('speed');
			then.	it.should.say('The function "show" was expected to be called with ("speed") but was called with ("sp33d")');
		});

		it('should allow for an assertion of multiple functions with parameters', function() {
			given.	jQuery('.enqueued').show().tabs('select', 1);
			then.	jQuery().usingSelector('.enqueued').should('show').and('tabs').using('select', 1);
		});

		it('should fail for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').show().tabs('select', 1);
			when.	jQuery().usingSelector('.enqueued').should('show').and('tabz').using('select', 1);
			then.	it.should.say('The function "tabz" was expected but did not get called!');
		});

		it('should allow for an assertion of a function with multiple parameters', function() {
			given.	jQuery('.enqueued').attr({'key':'value'}, 'theName', [1,2,3,4]);
			then.	jQuery().usingSelector('.enqueued').should('attr').using({'key':'value'}, 'theName', [1,2,3,4]);
		});

		it('should fail for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').attr({'k3y':'valu3'}, 'theNam3', [1,2,3,'4']);
			when.	jQuery().usingSelector('.enqueued').should('attr').using({'key':'value'}, 'theName', [1,2,3,'4']);
			then.	it.should.say('The function "attr" was expected to be called with ({"key": "value"}, "theName", [1, 2, 3, "4"]) but was called with ({"k3y": "valu3"}, "theNam3", [1, 2, 3, "4"])');
		});

		it('should allow calls to jquery objects with up to four parameters', function() {
			when.	jQuery('.enqueued').addClass('passed', 1);
			then.	jQuery().usingSelector('.enqueued').should('addClass').using('passed', 1);
		});
	});
});<commit_msg>added a comment in my branch<commit_after>var jQuery = mimic(jQuery);

Screw.Unit(function() {
	describe('jquery', function() {
		it('should assert against selector', function() {
			when.	jQuery('.enqueued');
			then.	jQuery().usingSelector('.enqueued');
		});

		it('should fail to assert against selector', function() {
			given.	jQuery('.inqueued');
			when.	jQuery().usingSelector('.enqueued');
			then.	it.should.say('The selector ".enqueued" was expected but was not used!');
		});

		it('should allow assertions of a selector never being used', function() {
			when.	jQuery('.enqueued');
			then.	jQuery().usingSelector('.it').neverHappens();
		});

		it('should allow a mimic version of jquery to return a basic object', function() {
			when.	jQuery('.it')[1].value;
		});

		it('should fail as the a selector was used when it was expected to not be used', function() {
			given.	jQuery('.enqueued');
			when.	jQuery().usingSelector('.enqueued').neverHappens();
			then.	it.should.say('The selector ".enqueued" was expected to never be used, however it was!');
		});

		it('should allow for simple assertions', function() {
			when.	jQuery('.enqueued').show();
			then.	jQuery().usingSelector('.enqueued').should('show');
		});

		it('should fail as assertion is wrong', function() {
			given.	jQuery('.enqueued').show();
			when.	jQuery().usingSelector('.enqueued').should('show2');
			then.	it.should.say('The function "show2" was expected but did not get called!');
		});

		it('should allow for multiple assertions in one should', function() {
			when.	jQuery('.enqueued').show().hide();
			then.	jQuery().usingSelector('.enqueued').should('show').and('hide');
			//a change
		});

		it('should fail when allowing for multiple assertions in one should', function() {
			given.	jQuery('.enqueued').show().hide();
			when.	jQuery().usingSelector('.enqueued').should('show').and('hide2');
			then.	it.should.say('The function "hide2" was expected but did not get called!');
		});

		it('should fail when doing multiple assertions in multiple shoulds', function() {
			given.	jQuery('.enqueued').show().hide();
			when.	jQuery().usingSelector('.enqueued').should('show')
			and.	jQuery().usingSelector('.enqueued').should('hide2');
			then.	it.should.say('The function "hide2" was expected but did not get called!');
		});

		it('should allow for multiple assersions in multiple shoulds', function() {
			when.	jQuery('.enqueued').show().hide();
			then.	jQuery().usingSelector('.enqueued').should('show')
			and.	jQuery().usingSelector('.enqueued').should('hide');
		});

		it('should allow for a single assertion across multiple jquery calls', function() {
			when.	jQuery('.enqueued').show();
			and.	jQuery('.enqueued').hide();
			then.	jQuery().usingSelector('.enqueued').should('hide')
			and.	jQuery().usingSelector('.enqueued').should('show');
		});

		it('should fail for a single assertion across multiple jquery calls', function() {
			given.	jQuery('.enqueued').show();
			and.	jQuery('.enqueued').hide();
			when.	jQuery().usingSelector('.enqueued').should('show2')
			and.	jQuery().usingSelector('.enqueued').should('hide');
			then.	it.should.say('The function "show2" was expected but did not get called!');
		});

		it('should allow for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').show('speed');
			then.	jQuery().usingSelector('.enqueued').should('show').using('speed');
		});

		it('should fail for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').show('sp33d');
			when.	jQuery().usingSelector('.enqueued').should('show').using('speed');
			then.	it.should.say('The function "show" was expected to be called with ("speed") but was called with ("sp33d")');
		});

		it('should allow for an assertion of multiple functions with parameters', function() {
			given.	jQuery('.enqueued').show().tabs('select', 1);
			then.	jQuery().usingSelector('.enqueued').should('show').and('tabs').using('select', 1);
		});

		it('should fail for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').show().tabs('select', 1);
			when.	jQuery().usingSelector('.enqueued').should('show').and('tabz').using('select', 1);
			then.	it.should.say('The function "tabz" was expected but did not get called!');
		});

		it('should allow for an assertion of a function with multiple parameters', function() {
			given.	jQuery('.enqueued').attr({'key':'value'}, 'theName', [1,2,3,4]);
			then.	jQuery().usingSelector('.enqueued').should('attr').using({'key':'value'}, 'theName', [1,2,3,4]);
		});

		it('should fail for an assertion of a function with a parameter', function() {
			given.	jQuery('.enqueued').attr({'k3y':'valu3'}, 'theNam3', [1,2,3,'4']);
			when.	jQuery().usingSelector('.enqueued').should('attr').using({'key':'value'}, 'theName', [1,2,3,'4']);
			then.	it.should.say('The function "attr" was expected to be called with ({"key": "value"}, "theName", [1, 2, 3, "4"]) but was called with ({"k3y": "valu3"}, "theNam3", [1, 2, 3, "4"])');
		});

		it('should allow calls to jquery objects with up to four parameters', function() {
			when.	jQuery('.enqueued').addClass('passed', 1);
			then.	jQuery().usingSelector('.enqueued').should('addClass').using('passed', 1);
		});
	});
});<|endoftext|>


<commit_before>'use strict';

function uuid() {
  const array = new Uint8Array(2);
  crypto.getRandomValues(array);
  return array.join('-')
}

function create(id) {
  return new crdt.Discrete(id, {});
}

function snapshot(text) {
  return new crdt.Text(
    text.order.next(),
    text.ordersIndex,
    text.operationsIndex
  );
}

function shiftCursorPositionRelativeTo(text, position) {
  return text.reduce(({shiftBy, position}, operation) => {
    if (operation instanceof crdt.Insert) {
      if (operation.at <= position) {
        shiftBy += operation.value.length;
        position += operation.value.length;
      }
    } else if (operation instanceof crdt.Delete) {
      if (operation.at < position) {
        shiftBy -= operation.length;
      }
    }

    return {shiftBy, position};
  }, {shiftBy: 0, position}).shiftBy;
}

function serialise(text) {
  const operations = text.operationsIndex[text.index]
    .reduce((result, operation) => {
      let value = operation instanceof crdt.Insert
        ? {type: 'insert', args: [operation.at, operation.value]}
        : {type: 'delete', args: [operation.at, operation.length]}
      ;

      result.operations.push(value);

      return result;
    }, {
      operations: [],
      order: {
        id: text.order.id,
        vector: text.order.vector,
      }
    });

  return JSON.stringify(operations);
}

function deserialise(string) {
  const {order, operations} = JSON.parse(string);
  const {id, vector} = order;

  return operations.reduce((text, {type, args}) => {
    const operation = (type === 'insert')
      ? new crdt.Insert(args[0], args[1])
      : new crdt.Delete(args[0], args[1]);

    text.apply(operation)
    return text
  }, new crdt.Text(new crdt.Discrete(id, vector)));
}

let editorElement = document.getElementById('editor');
let keyup = new jef.stream(function(onValue){
  editorElement.addEventListener('keydown', e => {onValue(e);});
  editorElement.addEventListener('keyup', e => {onValue(e);});
  editorElement.addEventListener('keypress', e => {onValue(e);});
  editorElement.addEventListener('paste', e => {onValue(e);});
  editorElement.addEventListener('cut', e => {onValue(e);});
});

let host = window.document.location.host.replace(/:.*/, '');
let ws = new WebSocket('ws://' + host + ':8080');

let messages = new jef.stream(function(onValue) {
  ws.onmessage = onValue;
});

let database = new crdt.Text(create(uuid()));

const BACKSPACE = 8;
const DELETE = 46;
const ENTER = 13;

keyup
  .filter(e => {
    switch(e.type) {
      case 'keydown':
        return e.keyCode === BACKSPACE || e.keyCode === DELETE;
      case 'keypress':
        return true;
      case 'cut':
      case 'paste':
        return true;
      default:
        return false;
    }
  })
  .map(e => {
    return {
      key: (e.type === 'paste') ? e.clipboardData.getData('text/plain') : e.key,
      code: e.keyCode || e.type,
      pos: e.target.selectionStart,
      selection: e.target.selectionEnd - e.target.selectionStart
    };
  })
  .flatMap(({key, code, pos, selection}) => {
    if (code === ENTER) {
      key = '\n';
    }

    if (code === 'cut') {
      return jef.stream.fromValue(
          new crdt.Delete(pos, selection)
      );
    }

    if (code === BACKSPACE) {
      return jef.stream.fromValue(
        selection
          ? new crdt.Delete(pos, selection)
          : new crdt.Delete(pos-1, 1)
      );
    }

    if (code === DELETE) {
      return jef.stream.fromValue(
        selection
          ? new crdt.Delete(pos, selection)
          : new crdt.Delete(pos, 1)
      );
    }

    if (selection) {
      return jef.stream.fromArray([
        new crdt.Delete(pos, selection),
        new crdt.Insert(pos, key),
      ]);
    }

    return jef.stream.fromValue(new crdt.Insert(pos, key))
  })
  .map(op => database.apply(op))
  .timeout(600)
  .on(_ => {
    const data = serialise(database);
    database = snapshot(database);
    ws.send(data);
  })
;

messages
  .map(e => e.data)
  .map(deserialise)
  .on(e => {
    database = database.merge(e);
  })
  .debounce(16)
  .on(e => {
    const start = editorElement.selectionStart,
          end   = editorElement.selectionEnd;

    const shiftBy = shiftCursorPositionRelativeTo(e, start);

    editorElement.value = database.toString();
    editorElement.setSelectionRange(start + shiftBy, end + shiftBy);
  })
;
<commit_msg>make cursor stable on sych<commit_after>'use strict';

function uuid() {
  const array = new Uint8Array(2);
  crypto.getRandomValues(array);
  return array.join('-')
}

function create(id) {
  return new crdt.Discrete(id, {});
}

function snapshot(text) {
  return new crdt.Text(
    text.order.next(),
    text.ordersIndex,
    text.operationsIndex
  );
}

function shiftCursorPositionRelativeTo(text, position) {
  return text.reduce(({shiftBy, position}, operation) => {
    if (operation instanceof crdt.Insert) {
      if (operation.at < position) {
        shiftBy += operation.value.length;
        position += operation.value.length;
      }
    } else if (operation instanceof crdt.Delete) {
      if (operation.at < position) {
        shiftBy -= operation.length;
      }
    }

    return {shiftBy, position};
  }, {shiftBy: 0, position}).shiftBy;
}

function serialise(text) {
  const operations = text.operationsIndex[text.index]
    .reduce((result, operation) => {
      let value = operation instanceof crdt.Insert
        ? {type: 'insert', args: [operation.at, operation.value]}
        : {type: 'delete', args: [operation.at, operation.length]}
      ;

      result.operations.push(value);

      return result;
    }, {
      operations: [],
      order: {
        id: text.order.id,
        vector: text.order.vector,
      }
    });

  return JSON.stringify(operations);
}

function deserialise(string) {
  const {order, operations} = JSON.parse(string);
  const {id, vector} = order;

  return operations.reduce((text, {type, args}) => {
    const operation = (type === 'insert')
      ? new crdt.Insert(args[0], args[1])
      : new crdt.Delete(args[0], args[1]);

    text.apply(operation)
    return text
  }, new crdt.Text(new crdt.Discrete(id, vector)));
}

let editorElement = document.getElementById('editor');
let keyup = new jef.stream(function(onValue){
  editorElement.addEventListener('keydown', e => {onValue(e);});
  editorElement.addEventListener('keyup', e => {onValue(e);});
  editorElement.addEventListener('keypress', e => {onValue(e);});
  editorElement.addEventListener('paste', e => {onValue(e);});
  editorElement.addEventListener('cut', e => {onValue(e);});
});

let host = window.document.location.host.replace(/:.*/, '');
let ws = new WebSocket('ws://' + host + ':8080');

let messages = new jef.stream(function(onValue) {
  ws.onmessage = onValue;
});

let database = new crdt.Text(create(uuid()));

const BACKSPACE = 8;
const DELETE = 46;
const ENTER = 13;

keyup
  .filter(e => {
    switch(e.type) {
      case 'keydown':
        return e.keyCode === BACKSPACE || e.keyCode === DELETE;
      case 'keypress':
        return true;
      case 'cut':
      case 'paste':
        return true;
      default:
        return false;
    }
  })
  .map(e => {
    return {
      key: (e.type === 'paste') ? e.clipboardData.getData('text/plain') : e.key,
      code: e.keyCode || e.type,
      pos: e.target.selectionStart,
      selection: e.target.selectionEnd - e.target.selectionStart
    };
  })
  .flatMap(({key, code, pos, selection}) => {
    if (code === ENTER) {
      key = '\n';
    }

    if (code === 'cut') {
      return jef.stream.fromValue(
          new crdt.Delete(pos, selection)
      );
    }

    if (code === BACKSPACE) {
      return jef.stream.fromValue(
        selection
          ? new crdt.Delete(pos, selection)
          : new crdt.Delete(pos-1, 1)
      );
    }

    if (code === DELETE) {
      return jef.stream.fromValue(
        selection
          ? new crdt.Delete(pos, selection)
          : new crdt.Delete(pos, 1)
      );
    }

    if (selection) {
      return jef.stream.fromArray([
        new crdt.Delete(pos, selection),
        new crdt.Insert(pos, key),
      ]);
    }

    return jef.stream.fromValue(new crdt.Insert(pos, key))
  })
  .map(op => database.apply(op))
  .timeout(600)
  .on(_ => {
    const data = serialise(database);
    database = snapshot(database);
    ws.send(data);
  })
;

messages
  .map(e => e.data)
  .map(deserialise)
  .on(e => {
    database = database.merge(e);
  })
  .debounce(16)
  .on(e => {
    const start = editorElement.selectionStart,
          end   = editorElement.selectionEnd;

    const shiftBy = shiftCursorPositionRelativeTo(e, start);

    editorElement.value = database.toString();
    editorElement.setSelectionRange(start + shiftBy, end + shiftBy);
  })
;
<|endoftext|>


<commit_before>(function(){
  'use strict'

  angular.module('ToDo')
  .controller('ToDoController',ToDoController);

  ToDoController.$inject = ['$q','firebaseService','profileService'];
  function ToDoController($q,firebaseService,profileService){
    var vm = this;
    /*====================== Delegation Variables =========================== */
    vm.addItem = addItem;
    vm.addItemButton = addItemButton;
    vm.editItem = editItem;
    vm.editModeButton = editModeButton;
    vm.exitEditMode = exitEditMode;
    vm.saveButton = saveButton;
    vm.signInButton = signInButton;
    vm.signOutButton = signOutButton;
    vm.signUpButton = signUpButton;
    vm.removeItem = removeItem;
    /*====================== public Variables =============================== */
    vm.displayList = [{value:" "},{value:" "}];
    vm.inputData = "";
    vm.list = [{value:" "},{value:" "}];
    vm.tab = {name:"testList",colour:""};
    //vm.logedIn = false;
    //<!> move to profile.controler
    vm.profileMode = "signIn";//<!> temp
    //vm.user;
    //vm.userEmail = "";//<!> add encryption
    //vm.userPassword = ""///<!> add encryption
    //</!> move to profile.controler
    vm.pageSize = 25;
    /*====================== private Variables ============================== */
    /*====================== Services ======================================= */
    var fbSvc = firebaseService;
    var pSvc = profileService;
    /*====================== Public Methods ================================= */
    function addItem(index,item){
        vm.list.splice(index,0,item);
        vm.inputData = "";
        addItemToDisplayList(index,item);
        saveButton();
    }
    function addItemButton($event){
        if($event.code === 'Enter'){
          var item = {value:vm.inputData, editMode: false};
          addItem(vm.list.length,item)
        }
    }
    function editItem(index, content){
      vm.list[index].value = content;
      vm.displayList[index].value = content;
      saveButton();
    }
    function editModeButton($index){
      if(vm.displayList[$index].editMode){
        //console.log(vm.list[$index].value);
        editItem($index,vm.displayList[$index].value);
        //console.log(vm.list[$index].value);
      }
      vm.displayList[$index].editMode = !vm.displayList[$index].editMode;
    }
    function exitEditMode($event,$index){
      if($event.code === 'Enter'){
        editModeButton($index);
      }
    }
    function removeItem(index){
      vm.list.splice(index,1);
      clearDisplay();
      loadList();
      saveButton();
    }
    function saveButton(){
      //set up save list
      //to get rid of angular hash key and keys used only client side
      var list_ = []
      for(let i =0, l =vm.list.length; i < l; i++){
        list_.push({value:vm.list[i].value});
      }
      saveList(list_);
    }
    function signInButton(){
      if(pSvc.profileMode == "signIn"){
        //console.log(pSvc.profileMode);
        //console.log(pSvc.userEmail);
        fbSvc.signInUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(userData){
          //console.log("success!");
          //console.log(userData);
          if(!userData.emailVerified){
            //console.log("not verified");
            alert("user not verified");
            let resend = confirm("resend verification?")
            if(confirm != null ||confirm != "" ){
              //call fbSvc.emailConfirm
              //console.log("confirming email");
              fbSvc.emailConfirm(userData);
            }
            signOutButton();
          }else{
            userDataCheck(userData);//<!> replace to profile controler call
            //<!>move to load list data function
            loadListData(userData.uid);
            pSvc.profileMode = "profile";
            vm.profileMode = "profile";
          }
        });
      }
    }
    function signOutButton(){
      fbSvc.signOutUser()
      .then(function(user){
        pSvc.profileMode = "signIn";
        vm.profileMode = "signIn";
        clearDisplay();
        pSvc.ClearUserData();
      });
    }
    function signUpButton(){
      if(pSvc.profileMode == "signIn"){
        fbSvc.signUpUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(user){
          //console.log(userData);
          alert("please verify user via the recived email, and then try login in, thank you! :) /n no need to refresh either.")
          //pSvc.profileMode = "profile";
        });
      }
    }
    function userDataCheck(_user){
      pSvc.user = _user;
      if(pSvc.user.displayName == "" || pSvc.user.displayName == null){
        var displayName = pSvc.user.email.split('@')[0];
        displayName = prompt("Enter your desired display name",displayName);
        pSvc.user.updateProfile({
          displayName: displayName,
          photoURL: ""
        }).then(function() {
          // Profile updated successfully!
          // "Jane Q. User"
           displayName = pSvc.user.displayName;
           //photoURL = user.photoURL;
        }, function(error) {
          // An error happened.
          console.error("display name could not be updated please contact support");
        });
      }else{
        console.log(pSvc.user.displayName);
      }
    }
    function saveList(_list){
    //  let promise = new Promise((resolve, reject) => {
      //  if (/* some async task is all good */) {
      //    resolve('Success!');
      //  } else {
      //    reject('Oops... something went wrong');
      //  }
      //});
      /* ^ default promise
       Q/promise notes
       as promiseVar.then(resolutionFunction(),RegectionFunction(error))
       both results are q/promises
       promises are native to JS since 2015, as well as angulars Q
      */
      var defer = $q.defer();
      fbSvc.writeData(pSvc.user.uid,"lists/",vm.tab.name,_list)
      .then(function(){
        //console.log("saved");
      },function(rejected){
        console.log(rejected);
      });
    }
    /*====================== Private Methods ================================ */
    function addItemToDisplayList(index, item){//clunky way of getting around my lack of html finise ;)
      vm.displayList[index] = {value:item.value, editMode: false};
    }
    function clearDisplay(){
      vm.displayList = createEmptyList(vm.pageSize);
    }
    function createEmptyList(_size){
      //create empty list at variable size!
      var list_ = [];//out going list
      for(let i =0, l = _size; i<l; i++){
        list_.push({value:" ",empty:true, editMode: false});
      }
      return list_
    }
    function init(){
      vm.displayList = createEmptyList(vm.pageSize);
      vm.list = [];
      fbSvc.initializeFireBase();
      fbSvc.checkUserSession().then(function(user){
        pSvc.user = user;
        userDataCheck(user);
        loadListData(user.uid);
        pSvc.profileMode = "profile";
        vm.profileMode = "profile";
      },function(){

      });
      console.log();
    }
    function loadListData(_uid){
      clearDisplay();
      fbSvc.readDataOnce(_uid,"lists/",vm.tab.name).then(function(_list){
        //console.log(vm.list);
        vm.list = _list;
        loadList();
      });
      //</!>
    }
    function loadList(){
      for(let i=0,l=vm.list.length;i<l;i++){
        addItemToDisplayList(i,vm.list[i]);
      }
    }
    /*====================== Actions ======================================== */
    init();
  }
})();
<commit_msg>updated vm.tab to contain tag data for future implimentation<commit_after>(function(){
  'use strict'

  angular.module('ToDo')
  .controller('ToDoController',ToDoController);

  ToDoController.$inject = ['$q','firebaseService','profileService'];
  function ToDoController($q,firebaseService,profileService){
    var vm = this;
    /*====================== Delegation Variables =========================== */
    vm.addItem = addItem;
    vm.addItemButton = addItemButton;
    vm.editItem = editItem;
    vm.editModeButton = editModeButton;
    vm.exitEditMode = exitEditMode;
    vm.saveButton = saveButton;
    vm.signInButton = signInButton;
    vm.signOutButton = signOutButton;
    vm.signUpButton = signUpButton;
    vm.removeItem = removeItem;
    /*====================== public Variables =============================== */
    vm.displayList = [{value:" "},{value:" "}];
    vm.inputData = "";
    vm.list = [{value:" "},{value:" "}];
    vm.tab = {name:"testList",colour:"",tags:["test","tasks"]};
    //vm.logedIn = false;
    //<!> move to profile.controler
    vm.profileMode = "signIn";//<!> temp
    //vm.user;
    //vm.userEmail = "";//<!> add encryption
    //vm.userPassword = ""///<!> add encryption
    //</!> move to profile.controler
    vm.pageSize = 25;
    /*====================== private Variables ============================== */
    /*====================== Services ======================================= */
    var fbSvc = firebaseService;
    var pSvc = profileService;
    /*====================== Public Methods ================================= */
    function addItem(index,item){
        vm.list.splice(index,0,item);
        vm.inputData = "";
        addItemToDisplayList(index,item);
        saveButton();
    }
    function addItemButton($event){
        if($event.code === 'Enter'){
          var item = {value:vm.inputData, editMode: false};
          addItem(vm.list.length,item)
        }
    }
    function editItem(index, content){
      vm.list[index].value = content;
      vm.displayList[index].value = content;
      saveButton();
    }
    function editModeButton($index){
      if(vm.displayList[$index].editMode){
        //console.log(vm.list[$index].value);
        editItem($index,vm.displayList[$index].value);
        //console.log(vm.list[$index].value);
      }
      vm.displayList[$index].editMode = !vm.displayList[$index].editMode;
    }
    function exitEditMode($event,$index){
      if($event.code === 'Enter'){
        editModeButton($index);
      }
    }
    function removeItem(index){
      vm.list.splice(index,1);
      clearDisplay();
      loadList();
      saveButton();
    }
    function saveButton(){
      //set up save list
      //to get rid of angular hash key and keys used only client side
      var list_ = []
      for(let i =0, l =vm.list.length; i < l; i++){
        list_.push({value:vm.list[i].value});
      }
      saveList(list_);
    }
    function signInButton(){
      if(pSvc.profileMode == "signIn"){
        //console.log(pSvc.profileMode);
        //console.log(pSvc.userEmail);
        fbSvc.signInUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(userData){
          //console.log("success!");
          //console.log(userData);
          if(!userData.emailVerified){
            //console.log("not verified");
            alert("user not verified");
            let resend = confirm("resend verification?")
            if(confirm != null ||confirm != "" ){
              //call fbSvc.emailConfirm
              //console.log("confirming email");
              fbSvc.emailConfirm(userData);
            }
            signOutButton();
          }else{
            userDataCheck(userData);//<!> replace to profile controler call
            //<!>move to load list data function
            loadListData(userData.uid);
            pSvc.profileMode = "profile";
            vm.profileMode = "profile";
          }
        });
      }
    }
    function signOutButton(){
      fbSvc.signOutUser()
      .then(function(user){
        pSvc.profileMode = "signIn";
        vm.profileMode = "signIn";
        clearDisplay();
        pSvc.ClearUserData();
      });
    }
    function signUpButton(){
      if(pSvc.profileMode == "signIn"){
        fbSvc.signUpUser(pSvc.userEmail,pSvc.userPassword)
        .then(function(user){
          //console.log(userData);
          alert("please verify user via the recived email, and then try login in, thank you! :) /n no need to refresh either.")
          //pSvc.profileMode = "profile";
        });
      }
    }
    function userDataCheck(_user){
      pSvc.user = _user;
      if(pSvc.user.displayName == "" || pSvc.user.displayName == null){
        var displayName = pSvc.user.email.split('@')[0];
        displayName = prompt("Enter your desired display name",displayName);
        pSvc.user.updateProfile({
          displayName: displayName,
          photoURL: ""
        }).then(function() {
          // Profile updated successfully!
          // "Jane Q. User"
           displayName = pSvc.user.displayName;
           //photoURL = user.photoURL;
        }, function(error) {
          // An error happened.
          console.error("display name could not be updated please contact support");
        });
      }else{
        console.log(pSvc.user.displayName);
      }
    }
    function saveList(_list){
    //  let promise = new Promise((resolve, reject) => {
      //  if (/* some async task is all good */) {
      //    resolve('Success!');
      //  } else {
      //    reject('Oops... something went wrong');
      //  }
      //});
      /* ^ default promise
       Q/promise notes
       as promiseVar.then(resolutionFunction(),RegectionFunction(error))
       both results are q/promises
       promises are native to JS since 2015, as well as angulars Q
      */
      var defer = $q.defer();
      fbSvc.writeData(pSvc.user.uid,"lists/",vm.tab.name,_list)
      .then(function(){
        //console.log("saved");
      },function(rejected){
        console.log(rejected);
      });
    }
    /*====================== Private Methods ================================ */
    function addItemToDisplayList(index, item){//clunky way of getting around my lack of html finise ;)
      vm.displayList[index] = {value:item.value, editMode: false};
    }
    function clearDisplay(){
      vm.displayList = createEmptyList(vm.pageSize);
    }
    function createEmptyList(_size){
      //create empty list at variable size!
      var list_ = [];//out going list
      for(let i =0, l = _size; i<l; i++){
        list_.push({value:" ",empty:true, editMode: false});
      }
      return list_
    }
    function init(){
      vm.displayList = createEmptyList(vm.pageSize);
      vm.list = [];
      fbSvc.initializeFireBase();
      fbSvc.checkUserSession().then(function(user){
        pSvc.user = user;
        userDataCheck(user);
        loadListData(user.uid);
        pSvc.profileMode = "profile";
        vm.profileMode = "profile";
      },function(){

      });
      console.log();
    }
    function loadListData(_uid){
      clearDisplay();
      fbSvc.readDataOnce(_uid,"lists/",vm.tab.name).then(function(_list){
        //console.log(vm.list);
        vm.list = _list;
        loadList();
      });
      //</!>
    }
    function loadList(){
      for(let i=0,l=vm.list.length;i<l;i++){
        addItemToDisplayList(i,vm.list[i]);
      }
    }
    /*====================== Actions ======================================== */
    init();
  }
})();
<|endoftext|>


<commit_before>/**
 * @class LabelView
 * @augments ControlView
 * @mixes editorBaseViewMixin
 */
var LabelView = ControlView.extend(_.extend({}, editorBaseViewMixin, /** @lends LabelView.prototype */{
    className: 'pl-label',

    template: InfinniUI.Template["new/controls/label/template/label.tpl.html"],

    UI: _.extend({}, editorBaseViewMixin.UI, {
        control: '.label-control'
    }),

    initialize: function () {
        ControlView.prototype.initialize.apply(this);

        //this.initHorizontalTextAlignment();
        //this.initUpdateLineCount();
        //this.initTextWrapping();
        //this.initForeground();
        //this.initBackground();
        //this.initTextStyle();
    },

    initHandlersForProperties: function(){
        ControlView.prototype.initHandlersForProperties.call(this);
        editorBaseViewMixin.initHandlersForProperties.call(this);

        this.listenTo(this.model, 'change:displayFormat', this.updateDisplayFormat);
        this.listenTo(this.model, 'change:textWrapping', this.updateTextWrapping);
        this.listenTo(this.model, 'change:textTrimming', this.updateTextTrimming);
        this.listenTo(this.model, 'change:lineCount', this.updateLineCount);
    },

    updateProperties: function(){
        ControlView.prototype.updateProperties.call(this);
        editorBaseViewMixin.updateProperties.call(this);
    },

    updateValue: function(){
        var textForLabel = this.getLabelText();
        this.ui.control
            .text(textForLabel)
            .attr('title', textForLabel);
    },

    updateDisplayFormat: function(){
        this.updateValue();
    },

    updateTextWrapping: function(){
        var textWrapping = this.model.get('textWrapping');
        this.ui.control.toggleClass('pl-text-wrapping', textWrapping);
    },

    updateTextTrimming: function(){
        var textTrimming = this.model.get('textTrimming');
        this.ui.control.toggleClass('pl-text-trimming', textTrimming);
    },

    updateText: function () {
        this.updateValue();
    },

    updateLineCount: function(){

    },

    getData: function () {
        return _.extend(
            {},
            ControlView.prototype.getData.call(this),
            editorBaseViewMixin.getData.call(this),
            {
                text: this.getLabelText()
            }
        );
    },

    render: function () {
        var model = this.model;

        this.prerenderingActions();
        this.renderTemplate(this.template);

        this.updateProperties();

        this.trigger('render');
        this.postrenderingActions();
        return this;
    },

    getLabelText: function () {
        var model = this.model;
        var value = model.get('value');
        var text;
        var format = model.get('displayFormat');

        if (typeof value !== 'undefined' && value !== null) {
            text = typeof format === 'function' ? format(null, {value: value}) : value;
        }else{
            text = this.model.get('text');
            if (typeof text === 'undefined' || text == null) {
                text = '';
            }
        }

        return text;
    }

}));

//_.extend(LabelView.prototype,
//    horizontalTextAlignmentPropertyMixin,
//    foregroundPropertyMixin,
//    backgroundPropertyMixin,
//    textStylePropertyMixin,
//    lineCountPropertyMixin,
//    textWrappingPropertyMixin
//);<commit_msg>minor<commit_after>/**
 * @class LabelView
 * @augments ControlView
 * @mixes editorBaseViewMixin
 */
var LabelView = ControlView.extend(_.extend({}, editorBaseViewMixin, /** @lends LabelView.prototype */{
    className: 'pl-label',

    template: InfinniUI.Template["new/controls/label/template/label.tpl.html"],

    UI: _.extend({}, editorBaseViewMixin.UI, {
        control: '.label-control'
    }),

    initialize: function () {
        ControlView.prototype.initialize.apply(this);
    },

    initHandlersForProperties: function(){
        ControlView.prototype.initHandlersForProperties.call(this);
        editorBaseViewMixin.initHandlersForProperties.call(this);

        this.listenTo(this.model, 'change:displayFormat', this.updateDisplayFormat);
        this.listenTo(this.model, 'change:textWrapping', this.updateTextWrapping);
        this.listenTo(this.model, 'change:textTrimming', this.updateTextTrimming);
        this.listenTo(this.model, 'change:lineCount', this.updateLineCount);
    },

    updateProperties: function(){
        ControlView.prototype.updateProperties.call(this);
        editorBaseViewMixin.updateProperties.call(this);
    },

    updateValue: function(){
        var textForLabel = this.getLabelText();
        this.ui.control
            .text(textForLabel)
            .attr('title', textForLabel);
    },

    updateDisplayFormat: function(){
        this.updateValue();
    },

    updateTextWrapping: function(){
        var textWrapping = this.model.get('textWrapping');
        this.ui.control.toggleClass('pl-text-wrapping', textWrapping);
    },

    updateTextTrimming: function(){
        var textTrimming = this.model.get('textTrimming');
        this.ui.control.toggleClass('pl-text-trimming', textTrimming);
    },

    updateText: function () {
        this.updateValue();
    },

    updateLineCount: function(){

    },

    getData: function () {
        return _.extend(
            {},
            ControlView.prototype.getData.call(this),
            editorBaseViewMixin.getData.call(this),
            {
                text: this.getLabelText()
            }
        );
    },

    render: function () {
        var model = this.model;

        this.prerenderingActions();
        this.renderTemplate(this.template);

        this.updateProperties();

        this.trigger('render');
        this.postrenderingActions();
        return this;
    },

    getLabelText: function () {
        var model = this.model;
        var value = model.get('value');
        var text;
        var format = model.get('displayFormat');

        if (typeof value !== 'undefined' && value !== null) {
            text = typeof format === 'function' ? format(null, {value: value}) : value;
        }else{
            text = this.model.get('text');
            if (typeof text === 'undefined' || text == null) {
                text = '';
            }
        }

        return text;
    }

}));<|endoftext|>


<commit_before>var dj = window.location.hostname.split('.')[0];
var url = 'http://' + window.location.host + '/sub?id=' + dj;
var sub = new NchanSubscriber(url=url, opt={subscriber:'websocket'});

function blink(el) {
    for(i=0;i<5;i++) {
        $(el).fadeTo('slow', 0.1).fadeTo('slow', 1.0);
    }
}

sub.on("message", function(message, message_metadata) {
  var m = JSON.parse(message)
  var newstat = null

  if ('new_request_status' in m) {
      var newstat = m.new_request_status;
      if (newstat == 'played' || newstat == 'delete' || newstat == 'ignored') {
          $('#rr_'+m.request_id).remove();
      }
  }

  if ('listeners' in m) {
    $('#listeners').html( m.listeners);
    blink($('#listeners'));
  }

  if ('maxlisteners' in m) {
    $('#maxlisteners').html(m.maxlisteners);
    blink($('#maxlisteners'));
  }

  if ('requestbutton' in m) {
    $('#requestbutton').html(m.requestbutton);
    blink($('#requestbutton'));
  }
  if ('request_row' in m) {
      if (newstat == null) {
        $('#request-table tr:last').after(m.request_row);
        blink($('#request-table tr:last'));
      } else {
        $('#rr_'+m.request_id).replaceWith(m.request_row);
        blink($('#rr'+m.request_id));
      }
  }
  if ('lastplay' in m) {
      $('#lastplay tr:first').after(m.lastplay);
      blink($('#lastplay td:first').parent());
  }
  if ('request_id' in m) {
      $('#r_'+m.request_id).attr('disabled', 'disabled');
  }

});

sub.start();
<commit_msg>Changed websocktes to use https<commit_after>var dj = window.location.hostname.split('.')[0];
var url = 'https://' + window.location.host + '/sub?id=' + dj;
var sub = new NchanSubscriber(url=url, opt={subscriber:'websocket'});

function blink(el) {
    for(i=0;i<5;i++) {
        $(el).fadeTo('slow', 0.1).fadeTo('slow', 1.0);
    }
}

sub.on("message", function(message, message_metadata) {
  var m = JSON.parse(message)
  var newstat = null

  if ('new_request_status' in m) {
      var newstat = m.new_request_status;
      if (newstat == 'played' || newstat == 'delete' || newstat == 'ignored') {
          $('#rr_'+m.request_id).remove();
      }
  }

  if ('listeners' in m) {
    $('#listeners').html( m.listeners);
    blink($('#listeners'));
  }

  if ('maxlisteners' in m) {
    $('#maxlisteners').html(m.maxlisteners);
    blink($('#maxlisteners'));
  }

  if ('requestbutton' in m) {
    $('#requestbutton').html(m.requestbutton);
    blink($('#requestbutton'));
  }
  if ('request_row' in m) {
      if (newstat == null) {
        $('#request-table tr:last').after(m.request_row);
        blink($('#request-table tr:last'));
      } else {
        $('#rr_'+m.request_id).replaceWith(m.request_row);
        blink($('#rr'+m.request_id));
      }
  }
  if ('lastplay' in m) {
      $('#lastplay tr:first').after(m.lastplay);
      blink($('#lastplay td:first').parent());
  }
  if ('request_id' in m) {
      $('#r_'+m.request_id).attr('disabled', 'disabled');
  }

});

sub.start();
<|endoftext|>