<commit_before>var logger = (require('../logging/vip-winston')).Logger;
var authService = require("../authentication/services");
var config = require('../config');
var nodemailer = require('nodemailer');
var sesTransport = require('nodemailer-ses-transport');
var dataTestingMessageContent = require('./data-testing/content');
var feedProcessingMessageContent = require('./feed-processing/content');
var pg = require('pg');
var slack = require('./slack');

var transporter = nodemailer.createTransport(sesTransport({
  accessKeyId: config.aws.accessKey,
  secretAccessKey: config.aws.secretKey,
  rateLimit: config.email.rateLimit,
  region: config.aws.region
}));

var dataCentralizationOnly = function(user) {
  return user.app_metadata.roles &&
         user.app_metadata.roles.length == 1 &&
         user.app_metadata.roles[0] == 'data-centralization';
};

var messageOptions = {
  // data-testing message options
  testingComplete: function(message, recipient) {
    return {
      from: config.email.fromAddress,
      to: recipient.email,
      subject: "A batch address test has completed",
      html: dataTestingMessageContent.testingComplete(message)
    }
  },
  errorDuringTesting: function(message, recipient) {
    return {
      from: config.email.fromAddress,
      to: recipient.email,
      subject: "A batch address test has failed",
      html: dataTestingMessageContent.errorDuringTesting(message)
    }
  },

  // feed-processing message options
  approveFeed: function(message, recipient, fipsCode) {
    if (dataCentralizationOnly(recipient)) {
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: "A Feed has been Approved",
        html: feedProcessingMessageContent.approveFeed(message, recipient, fipsCode)
      }
    }
  },
  processedFeed: function(message, recipient, fipsCode) {
    if (dataCentralizationOnly(recipient)) {
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: 'Your Feed Has Been Processed',
        html: feedProcessingMessageContent.processedFeed(message, recipient, fipsCode)
      };
    }
  },
  v5processedFeed: function(message, recipient, fipsCode) {
    if (dataCentralizationOnly(recipient)){
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: 'Your Feed Has Been Processed',
        html: feedProcessingMessageContent.v5processedFeed(message, recipient, fipsCode)
      };
    }
  },
  errorDuringProcessing: function(message, recipient) {
    if (dataCentralizationOnly(recipient)) {
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: 'Something Went Wrong with a Feed',
        text: feedProcessingMessageContent.errorDuringProcessing(message)
      };
    }
  }
};

var sendMessage = function(messageContent) {
  transporter.sendMail(messageContent, function(error, info) {
    if (error) {
      logger.info('Sending error: ' + error);
      logger.info('Message: ' + JSON.stringify(messageContent));
    }
  });
};

var badFips = function(fips) {
  if ((typeof fips != "string") ||
       (fips.length < 2) ||
       (fips.length > 5)) {
    return true;
  } else {
    return false;
  }
}

var sendEmail = function(message, fips, contentFn) {
  authService.getUsersByFips(fips, function (users) {
    for (var i = 0; i < users.length; i++) {
      var recipient = users[i];
      var messageContent = contentFn(message, recipient, fips);

      if (messageContent != null) {
        sendMessage(messageContent);
        logger.info("Sending a message to: " + messageContent.to + " with this subject: " + messageContent.subject);
      }
    };
  });
};

var loadFeed = function(publicId, callback) {
  var vip_id_query = "SELECT vip_id, spec_version, election_date, extract(epoch from (end_time - start_time)) as duration \
                      FROM results \
                      WHERE public_id = $1";

  pg.connect(process.env.DATABASE_URL, function(err, client, done) {
    if (err) return logger.error('Could not connect to PostgreSQL. Error fetching client from pool: ', err);

    client.query(vip_id_query, [publicId], function(err, result) {
      done();

      if (err || result.rows.length == 0) {
        logger.error('No feed found or connection issue.');
        slack.message("ERROR: No feed found matching public_id in database (public_id follows):\n" + publicId);
      } else {
        callback(result);
      }
    });
  });
}

module.exports = {
  sendUploadNotifications: function(message) {
    logger.info("sending Slack upload message: " + message);
    if (message.uploaded == "true") {
      slack.message("UPLOAD SUCCESS: file " + message.filename + " uploaded to " + message.bucket);
    } else {
      slack.message("UPLOAD FAILURE: file " + message.filename + " failed to upload to " + message.bucket);
    }
  },
  sendFeedProcessingSuccessNotifications: function(message, messageType) {
    loadFeed(message.publicId, (result) => {
      var fips = result.rows[0]['vip_id'];
      var spec_version = new String(result.rows[0]['spec_version']);
      if (badFips(fips)) {
        slack.message("ERROR: Feed processed but FIPS was bad, no notifications sent: " + fips);
      } else {
        var stateName = feedProcessingMessageContent.codeToDescription(fips.slice(0,2));
        var electionDate = result.rows[0]['election_date'] || "Not available";
        var duration = result.rows[0]['duration'] || "Not available";

        var reportSuffix = "/xml/errors/report";
        if (spec_version == "3.0") {
          reportSuffix = "/errors/report";
        }

        var checksum = "";
        if (message.checksum) {
          checksum = "\nChecksum: " + message.checksum
        }

        slack.message("SUCCESS: Feed processed for FIPS " + fips +
                      "\nState Name " + stateName +
                      "\nElection Date " + electionDate +
                      "\nVIP Spec Version " + spec_version +
                      checksum +
                      "\nFull Error Report https://" +
                        process.env.BASE_URI + "/db/feeds/" + message.publicId + reportSuffix +
                      "\nProcessing-Time (sec) " + duration);
        if (fips && spec_version[0] == '5'  && messageType === 'processedFeed') {
          sendEmail(message, fips, messageOptions['v5processedFeed']);
        } else {
          sendEmail(message, fips, messageOptions[messageType]);
        }}});
  },
  sendFeedProcessingFailureNotifications: function(message, messageType) {
    var publicId = message.publicId;

    if (message.stop) {
      logger.info('Feed processing stopped.');
      slack.message("STOPPED: Processing of " + message.filename + " stopped.");
    }

    if (!publicId) {
      logger.error('No Public ID listed.');
      slack.message("ERROR: Feed processed but no public id found (message follows):\n" +
                    (message.stop || JSON.stringify(message)));
    } else {
      loadFeed(publicId, (result) => {
        var fips = result.rows[0]['vip_id'];
        var spec_version = new String(result.rows[0]['spec_version']);
        if (badFips(fips)) {
          slack.message("ERROR: Feed processed but FIPS was bad, no notifications sent: " + fips);
        } else {
          var stateName = feedProcessingMessageContent.codeToDescription(fips.slice(0,2));
          var electionDate = result.rows[0]['election_date'] || "Not available";
          slack.message("EXCEPTION: Feed processed with errors for FIPS " + fips +
                        "\nState Name " + stateName +
                        "\nElection Date " + electionDate +
                        "\nVIP Spec Version " + spec_version +
                        "\nProcessed Message " + JSON.stringify(message));
        }
        if (fips && spec_version[0] == '5'  && messageType === 'processedFeed') {
          sendEmail(message, fips, messageOptions['v5processedFeed']);
        } else {
          sendEmail(message, fips, messageOptions[messageType]);
        }
      });
    }
  },
  sendAddressTestSuccessNotifications: function(message) {
    var fipsCode = message.fipsCode;
    var slackMessage = "";
    if(fipsCode == "undefined") {
      slackMessage += "SUCCESS: Batch Address file processed for an admin, available at: " + message["url"];
    } else {
      slackMessage += "SUCCESS: Batch Address file processed for fips " + fipsCode + ", available at: " + message["url"];
    }
    if(message.stats) {
      slackMessage += "\nMatch Breakdown:";
      var statuses = ["Match", "Possible Mismatch", "Mismatch", "No Result"];
      statuses.map( (key) => { if (message.stats.hasOwnProperty(key)) {
                                 slackMessage += "\n" + key + ": " + message.stats[key];
                               } else {
                                 slackMessage += "\n" + key + ": 0";
                               } });
    }
    slack.message(slackMessage);
    sendEmail(message, fipsCode, messageOptions['testingComplete']);
  },
  sendAddressTestFailureNotifications: function(message) {
    var fipsCode = message.fipsCode;
    if (fipsCode === undefined) {
      logger.warning("No fips code in batch-address.file.complete message.  Can't send batch address testing finished email notification.");
      slack.message("ERROR: Batch Address sent a message we don't understand: " +
                    JSON.stringify(message));
    } else if (fipsCode === "undefined") {
      slack.message("ERROR: Admin submitted Batch Address file FAILED (message follows):\n" +
                    JSON.stringify(message));
    } else if (badFips(fipsCode)) {
      slack.message("ERROR: Batch Address file processed but fips was bad, no emails sent (message follows)\n" +
                    JSON.stringify(message));
    } else {
      slack.message("ERROR: Batch Address file failed (message follows)\n" +
                    JSON.stringify(message));
      sendEmail(message, fipsCode, messageOptions['errorDuringTesting']);
    }
  }
};
<commit_msg>upload Slack notification specifies feed or file<commit_after>var logger = (require('../logging/vip-winston')).Logger;
var authService = require("../authentication/services");
var config = require('../config');
var nodemailer = require('nodemailer');
var sesTransport = require('nodemailer-ses-transport');
var dataTestingMessageContent = require('./data-testing/content');
var feedProcessingMessageContent = require('./feed-processing/content');
var pg = require('pg');
var slack = require('./slack');

var transporter = nodemailer.createTransport(sesTransport({
  accessKeyId: config.aws.accessKey,
  secretAccessKey: config.aws.secretKey,
  rateLimit: config.email.rateLimit,
  region: config.aws.region
}));

var dataCentralizationOnly = function(user) {
  return user.app_metadata.roles &&
         user.app_metadata.roles.length == 1 &&
         user.app_metadata.roles[0] == 'data-centralization';
};

var messageOptions = {
  // data-testing message options
  testingComplete: function(message, recipient) {
    return {
      from: config.email.fromAddress,
      to: recipient.email,
      subject: "A batch address test has completed",
      html: dataTestingMessageContent.testingComplete(message)
    }
  },
  errorDuringTesting: function(message, recipient) {
    return {
      from: config.email.fromAddress,
      to: recipient.email,
      subject: "A batch address test has failed",
      html: dataTestingMessageContent.errorDuringTesting(message)
    }
  },

  // feed-processing message options
  approveFeed: function(message, recipient, fipsCode) {
    if (dataCentralizationOnly(recipient)) {
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: "A Feed has been Approved",
        html: feedProcessingMessageContent.approveFeed(message, recipient, fipsCode)
      }
    }
  },
  processedFeed: function(message, recipient, fipsCode) {
    if (dataCentralizationOnly(recipient)) {
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: 'Your Feed Has Been Processed',
        html: feedProcessingMessageContent.processedFeed(message, recipient, fipsCode)
      };
    }
  },
  v5processedFeed: function(message, recipient, fipsCode) {
    if (dataCentralizationOnly(recipient)){
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: 'Your Feed Has Been Processed',
        html: feedProcessingMessageContent.v5processedFeed(message, recipient, fipsCode)
      };
    }
  },
  errorDuringProcessing: function(message, recipient) {
    if (dataCentralizationOnly(recipient)) {
      return null;
    } else {
      return {
        from: config.email.fromAddress,
        to: recipient.email,
        subject: 'Something Went Wrong with a Feed',
        text: feedProcessingMessageContent.errorDuringProcessing(message)
      };
    }
  }
};

var sendMessage = function(messageContent) {
  transporter.sendMail(messageContent, function(error, info) {
    if (error) {
      logger.info('Sending error: ' + error);
      logger.info('Message: ' + JSON.stringify(messageContent));
    }
  });
};

var badFips = function(fips) {
  if ((typeof fips != "string") ||
       (fips.length < 2) ||
       (fips.length > 5)) {
    return true;
  } else {
    return false;
  }
}

var sendEmail = function(message, fips, contentFn) {
  authService.getUsersByFips(fips, function (users) {
    for (var i = 0; i < users.length; i++) {
      var recipient = users[i];
      var messageContent = contentFn(message, recipient, fips);

      if (messageContent != null) {
        sendMessage(messageContent);
        logger.info("Sending a message to: " + messageContent.to + " with this subject: " + messageContent.subject);
      }
    };
  });
};

var loadFeed = function(publicId, callback) {
  var vip_id_query = "SELECT vip_id, spec_version, election_date, extract(epoch from (end_time - start_time)) as duration \
                      FROM results \
                      WHERE public_id = $1";

  pg.connect(process.env.DATABASE_URL, function(err, client, done) {
    if (err) return logger.error('Could not connect to PostgreSQL. Error fetching client from pool: ', err);

    client.query(vip_id_query, [publicId], function(err, result) {
      done();

      if (err || result.rows.length == 0) {
        logger.error('No feed found or connection issue.');
        slack.message("ERROR: No feed found matching public_id in database (public_id follows):\n" + publicId);
      } else {
        callback(result);
      }
    });
  });
}

module.exports = {
  sendUploadNotifications: function(message) {
    logger.info("sending Slack upload message: " + message);
    if (message.uploaded == "true") {
      slack.message((message.isFeed ? "FEED " : "FILE ") + "UPLOAD SUCCESS: " + message.filename + " uploaded to " + message.bucket);
    } else {
      slack.message((message.isFeed ? "FEED " : "FILE ") + "UPLOAD FAILURE: " + message.filename + " failed to upload to " + message.bucket);
    }
  },
  sendFeedProcessingSuccessNotifications: function(message, messageType) {
    loadFeed(message.publicId, (result) => {
      var fips = result.rows[0]['vip_id'];
      var spec_version = new String(result.rows[0]['spec_version']);
      if (badFips(fips)) {
        slack.message("ERROR: Feed processed but FIPS was bad, no notifications sent: " + fips);
      } else {
        var stateName = feedProcessingMessageContent.codeToDescription(fips.slice(0,2));
        var electionDate = result.rows[0]['election_date'] || "Not available";
        var duration = result.rows[0]['duration'] || "Not available";

        var reportSuffix = "/xml/errors/report";
        if (spec_version == "3.0") {
          reportSuffix = "/errors/report";
        }

        var checksum = "";
        if (message.checksum) {
          checksum = "\nChecksum: " + message.checksum
        }

        slack.message("SUCCESS: Feed processed for FIPS " + fips +
                      "\nState Name " + stateName +
                      "\nElection Date " + electionDate +
                      "\nVIP Spec Version " + spec_version +
                      checksum +
                      "\nFull Error Report https://" +
                        process.env.BASE_URI + "/db/feeds/" + message.publicId + reportSuffix +
                      "\nProcessing-Time (sec) " + duration);
        if (fips && spec_version[0] == '5'  && messageType === 'processedFeed') {
          sendEmail(message, fips, messageOptions['v5processedFeed']);
        } else {
          sendEmail(message, fips, messageOptions[messageType]);
        }}});
  },
  sendFeedProcessingFailureNotifications: function(message, messageType) {
    var publicId = message.publicId;

    if (message.stop) {
      logger.info('Feed processing stopped.');
      slack.message("STOPPED: Processing of " + message.filename + " stopped.");
    }

    if (!publicId) {
      logger.error('No Public ID listed.');
      slack.message("ERROR: Feed processed but no public id found (message follows):\n" +
                    (message.stop || JSON.stringify(message)));
    } else {
      loadFeed(publicId, (result) => {
        var fips = result.rows[0]['vip_id'];
        var spec_version = new String(result.rows[0]['spec_version']);
        if (badFips(fips)) {
          slack.message("ERROR: Feed processed but FIPS was bad, no notifications sent: " + fips);
        } else {
          var stateName = feedProcessingMessageContent.codeToDescription(fips.slice(0,2));
          var electionDate = result.rows[0]['election_date'] || "Not available";
          slack.message("EXCEPTION: Feed processed with errors for FIPS " + fips +
                        "\nState Name " + stateName +
                        "\nElection Date " + electionDate +
                        "\nVIP Spec Version " + spec_version +
                        "\nProcessed Message " + JSON.stringify(message));
        }
        if (fips && spec_version[0] == '5'  && messageType === 'processedFeed') {
          sendEmail(message, fips, messageOptions['v5processedFeed']);
        } else {
          sendEmail(message, fips, messageOptions[messageType]);
        }
      });
    }
  },
  sendAddressTestSuccessNotifications: function(message) {
    var fipsCode = message.fipsCode;
    var slackMessage = "";
    if(fipsCode == "undefined") {
      slackMessage += "SUCCESS: Batch Address file processed for an admin, available at: " + message["url"];
    } else {
      slackMessage += "SUCCESS: Batch Address file processed for fips " + fipsCode + ", available at: " + message["url"];
    }
    if(message.stats) {
      slackMessage += "\nMatch Breakdown:";
      var statuses = ["Match", "Possible Mismatch", "Mismatch", "No Result"];
      statuses.map( (key) => { if (message.stats.hasOwnProperty(key)) {
                                 slackMessage += "\n" + key + ": " + message.stats[key];
                               } else {
                                 slackMessage += "\n" + key + ": 0";
                               } });
    }
    slack.message(slackMessage);
    sendEmail(message, fipsCode, messageOptions['testingComplete']);
  },
  sendAddressTestFailureNotifications: function(message) {
    var fipsCode = message.fipsCode;
    if (fipsCode === undefined) {
      logger.warning("No fips code in batch-address.file.complete message.  Can't send batch address testing finished email notification.");
      slack.message("ERROR: Batch Address sent a message we don't understand: " +
                    JSON.stringify(message));
    } else if (fipsCode === "undefined") {
      slack.message("ERROR: Admin submitted Batch Address file FAILED (message follows):\n" +
                    JSON.stringify(message));
    } else if (badFips(fipsCode)) {
      slack.message("ERROR: Batch Address file processed but fips was bad, no emails sent (message follows)\n" +
                    JSON.stringify(message));
    } else {
      slack.message("ERROR: Batch Address file failed (message follows)\n" +
                    JSON.stringify(message));
      sendEmail(message, fipsCode, messageOptions['errorDuringTesting']);
    }
  }
};
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var EventEmitter = require('events').EventEmitter;

var _ = require('lodash');
var log = require('./log');

function SerialTrigger(port) {
	this.port = port;
	this.triggers = {};
}
util.inherits(SerialTrigger, EventEmitter);

SerialTrigger.prototype.addTrigger = function(prompt, next) {
	if (!prompt) {
		throw new Error('prompt must be specified');
	}
	this.triggers[prompt] = next;
};

SerialTrigger.prototype.start = function(noLogs) {
	var serialDataCallback = function (data) {
		data = data.toString();
		var self = this;
		var triggerFn = _.find(this.triggers, function (fn, prompt) {
			return data.indexOf(prompt) >= 0;
		});

		if (triggerFn) {
			triggerFn(function (response, cb) {
				if (response) {
					self.port.flush(function () {
						self.port.write(response, function () {
							self.port.drain(function () {
								if (!noLogs) {
									log.serialInput(response);
								}
								if (cb) {
									cb();
								}
							});
						});
					});
				}
			});
		}
	};
	this.dataCallback = serialDataCallback.bind(this);
	this.port.on('data', this.dataCallback);
};

SerialTrigger.prototype.stop = function() {
	if (this.dataCallback) {
		this.port.removeListener('data', this.dataCallback);
		this.dataCallback = null;
	}
};

module.exports = SerialTrigger;
<commit_msg>update the trigger to allow data to be delivered incrementally. It looks for a trigger that has a prefix matching the current data. if no prefix exists, one character is discarded and the test repeated until a match is found or the data exhausted.<commit_after>'use strict';

var util = require('util');
var EventEmitter = require('events').EventEmitter;

var _ = require('lodash');
var log = require('./log');

function SerialTrigger(port) {
	this.port = port;
	this.triggers = {};
}
util.inherits(SerialTrigger, EventEmitter);

SerialTrigger.prototype.addTrigger = function(prompt, next) {
	if (!prompt) {
		throw new Error('prompt must be specified');
	}
	this.triggers[prompt] = next;
	this.data = '';
};

/**
 * There is no guarantee that 'data' events contain all of the data emitted by the device
 * in one block, so we have to match on substrings.
 * @param noLogs
 */
SerialTrigger.prototype.start = function(noLogs) {

	var serialDataCallback = function (data) {
		var self = this;
		this.data += data.toString();
		var substring = this.data;
		var substringMatch = '';
		var matchPrompt = '';

		while (!matchPrompt && substring) {
			(function(substring) {
				_.forOwn(self.triggers, function (fn, prompt) {
					if (substring.length > prompt.length) {
						if (substring.startsWith(prompt)) {
							matchPrompt = prompt;
							return false;   // quit iteration
						}
					} else {
						if (prompt.startsWith(substring)) {
							matchPrompt = prompt;
							return false;
						}
					}
				});
			})(substring);

			if (!matchPrompt) {
				substring = substring.substring(1);
			}
		}

		this.data = substring;

		if (matchPrompt && substring.length >= matchPrompt.length) {
			this.data = substring.substring(matchPrompt.length);

			var triggerFn = this.triggers[matchPrompt];
			if (triggerFn) {
				triggerFn(function (response, cb) {
					if (response) {
						self.port.flush(function () {
							self.port.write(response, function () {
								self.port.drain(function () {
									if (!noLogs) {
										log.serialInput(response);
									}
									if (cb) {
										cb();
									}
								});
							});
						});
					}
				});
			}
		}
	};
	this.dataCallback = serialDataCallback.bind(this);
	this.port.on('data', this.dataCallback);
};

SerialTrigger.prototype.stop = function() {
	if (this.dataCallback) {
		this.port.removeListener('data', this.dataCallback);
		this.dataCallback = null;
	}
};

module.exports = SerialTrigger;
<|endoftext|>


<commit_before>var isInScrollBar = function(canvas, context, x, y){
	var height = 400;
	var width = 30;
	var distanceFromTop = 100;

	return x > canvas.width - width && y > distanceFromTop && y < distanceFromTop + height;
}

var getScrollPositionFromScrollBar = function(canvas, context, y, maxScroll){
	var height = 400;
	var width = 20;
	var distanceFromTop = 100;

	return (y - distanceFromTop) * maxScroll / height;
}

var drawScrollBar = function(canvas, context, scrollPosition, maxScroll){
	var height = 400;
	var width = 30;
	var distanceFromTop = 100;

	context.strokeStyle=staveColour;
	context.rect(canvas.width - width, distanceFromTop, width, height);
	context.stroke();

	context.beginPath();
	context.strokeStyle=noteColour;
	context.lineWidth =4;
	context.moveTo(canvas.width - width, scrollPosition * height / maxScroll + distanceFromTop);
	context.lineTo(canvas.width, scrollPosition * height / maxScroll + distanceFromTop);
	context.stroke();
	context.lineWidth = 1;
}

function getCurrentLine(y, lines){
	for(var i = 0; i < lines.length; i++){
		if(lines[i].y > y)
		return lines[i].barNumber;
	}
	return false;
}

var drawScrollPreview = function(canvas, context, y, lines){
	var rightMargin = 30;
	var width = 100;
	var height = 100;
	var farLeft = canvas.width - (rightMargin + width) - 15;

	context.beginPath();
	context.moveTo(farLeft, y);
	context.lineTo(farLeft + width + 10, y);
	context.lineTo(farLeft + width, y + 5)
	context.lineTo(farLeft + width, y + height);
	context.lineTo(farLeft, y + height);
	context.lineTo(farLeft, y);
	context.strokeStyle = "black";
	context.lineWidth = 4;
	context.stroke();
	context.fillStyle="white";
	context.fill();
	context.lineWidth = 1;

	var tempCurrentLine = getCurrentLine(y, lines);
	if(tempCurrentLine != false){
		context.font = "bold 16px Arial";
		context.fillText(tempCurrentLine + "", farLeft + width / 2, y + height / 2);
	}
}
<commit_msg>Update scrollbar.js<commit_after>var isInScrollBar = function(canvas, context, x, y){
	var height = 400;
	var width = 30;
	var distanceFromTop = 100;

	return x > canvas.width - width && y > distanceFromTop && y < distanceFromTop + height;
}

var getScrollPositionFromScrollBar = function(canvas, context, y, maxScroll){
	var height = 400;
	var width = 20;
	var distanceFromTop = 100;

	return (y - distanceFromTop) * maxScroll / height;
}

var drawScrollBar = function(canvas, context, scrollPosition, maxScroll){
	var height = 400;
	var width = 30;
	var distanceFromTop = 100;

	context.strokeStyle=staveColour;
	context.rect(canvas.width - width, distanceFromTop, width, height);
	context.stroke();

	context.beginPath();
	context.strokeStyle=noteColour;
	context.lineWidth =4;
	context.moveTo(canvas.width - width, scrollPosition * height / maxScroll + distanceFromTop);
	context.lineTo(canvas.width, scrollPosition * height / maxScroll + distanceFromTop);
	context.stroke();
	context.lineWidth = 1;
}

function getCurrentLine(y, lines){
	for(var i = 0; i < lines.length; i++){
		if(lines[i].y > y)
		return lines[i].barNumber;
	}
	return false;
}

var drawScrollPreview = function(canvas, context, y, lines){
	var rightMargin = 30;
	var width = 100;
	var height = 100;
	var farLeft = canvas.width - (rightMargin + width) - 15;

	context.beginPath();
	context.moveTo(farLeft, y);
	context.lineTo(farLeft + width + 10, y);
	context.lineTo(farLeft + width, y + 5)
	context.lineTo(farLeft + width, y + height);
	context.lineTo(farLeft, y + height);
	context.lineTo(farLeft, y);
	context.strokeStyle = "black";
	context.lineWidth = 4;
	context.stroke();
	context.fillStyle="white";
	context.fill();
	context.lineWidth = 1;

	var tempCurrentLine = getCurrentLine(y, lines);
	if(tempCurrentLine != false){
		context.font = "bold 16px Arial";
		context.fillText(tempCurrentLine, farLeft + width / 2, y + height / 2);
	}
}
<|endoftext|>


<commit_before>var async = require('async');
var defaults = require('lodash.defaults');
var fastlyConfig = require('./lib/fastly-config-methods');
const languages = require('../languages.json');

var route_json = require('../src/routes.json');

const FASTLY_SERVICE_ID = process.env.FASTLY_SERVICE_ID || '';
const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || '';

var fastly = require('./lib/fastly-extended')(process.env.FASTLY_API_KEY, FASTLY_SERVICE_ID);

var extraAppRoutes = [
    // Homepage with querystring.
    // TODO: Should this be added for every route?
    '/\\?',
    // View html
    '/[^\/]*\.html$'
];

var routes = route_json.map(function (route) {
    return defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route);
});

async.auto({
    version: function (cb) {
        fastly.getLatestVersion(function (err, response) {
            if (err) return cb(err);
            // Validate latest version before continuing
            if (response.active || response.locked) {
                fastly.cloneVersion(response.number, function (err, response) {
                    if (err) return cb('Failed to clone latest version: ' + err);
                    cb(null, response.number);
                });
            } else {
                cb(null, response.number);
            }
        });
    },
    recvCustomVCL: ['version', function (cb, results) {
        // For all the routes in routes.json, construct a varnish-style regex that matches
        // on any of those route conditions.
        var notPassStatement = fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname);

        // For a non-pass condition, point backend at s3
        var recvCondition = '' +
            'if (' + notPassStatement + ') {\n' +
            '    set req.backend = F_s3;\n' +
            '    set req.http.host = \"' + S3_BUCKET_NAME + '\";\n' +
            '} else {\n' +
            '    if (!req.http.Fastly-FF) {\n' +
            '        if (req.http.X-Forwarded-For) {\n' +
            '            set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For \", \" client.ip;\n' +
            '        } else {\n' +
            '            set req.http.Fastly-Temp-XFF = client.ip;\n' +
            '        }\n' +
            '    } else {\n' +
            '        set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For;\n' +
            '    }\n' +
            '    set req.grace = 60s;\n' +
            '    if (req.http.Cookie:scratchlanguage) {\n' +
            '        set req.http.Accept-Language = req.http.Cookie:scratchlanguage;\n' +
            '    } else {\n' +
            '        set req.http.Accept-Language = accept.language_lookup("' +
                         Object.keys(languages).join(':') + '", ' +
                         '"en", ' +
                         'std.tolower(req.http.Accept-Language)' +
                     ');\n' +
            '    }\n' +
            '    if (req.url ~ "^/projects/" && !req.http.Cookie:scratchsessionsid) {\n' +
            '        set req.http.Cookie = "scratchlanguage=" req.http.Cookie:scratchlanguage;\n' +
            '    } else {\n' +
            '        return(pass);\n' +
            '    }\n' +
            '}\n';

        fastly.setCustomVCL(
            results.version,
            'recv-condition',
            recvCondition,
            cb
        );
    }],
    fetchCustomVCL: ['version', function (cb, results) {
        var passStatement = fastlyConfig.negateConditionStatement(
            fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname)
        );
        var ttlCondition = fastlyConfig.setResponseTTL(passStatement);
        fastly.setCustomVCL(results.version, 'fetch-condition', ttlCondition, cb);
    }],
    appRouteRequestConditions: ['version', function (cb, results) {
        var conditions = {};
        async.forEachOf(routes, function (route, id, cb2) {
            var condition = {
                name: fastlyConfig.getConditionNameForRoute(route, 'request'),
                statement: 'req.url ~ "' + route.pattern + '"',
                type: 'REQUEST',
                // Priority needs to be > 1 to not interact with http->https redirect
                priority: 10 + id
            };
            fastly.setCondition(results.version, condition, function (err, response) {
                if (err) return cb2(err);
                conditions[id] = response;
                cb2(null, response);
            });
        }, function (err) {
            if (err) return cb(err);
            cb(null, conditions);
        });
    }],
    appRouteHeaders: ['version', 'appRouteRequestConditions', function (cb, results) {
        var headers = {};
        async.forEachOf(routes, function (route, id, cb2) {
            if (route.redirect) {
                async.auto({
                    responseCondition: function (cb3) {
                        var condition = {
                            name: fastlyConfig.getConditionNameForRoute(route, 'response'),
                            statement: 'req.url ~ "' + route.pattern + '"',
                            type: 'RESPONSE',
                            priority: id
                        };
                        fastly.setCondition(results.version, condition, cb3);
                    },
                    responseObject: function (cb3) {
                        var responseObject = {
                            name: fastlyConfig.getResponseNameForRoute(route),
                            status: 301,
                            response: 'Moved Permanently',
                            request_condition: fastlyConfig.getConditionNameForRoute(route, 'request')
                        };
                        fastly.setResponseObject(results.version, responseObject, cb3);
                    },
                    redirectHeader: ['responseCondition', function (cb3, redirectResults) {
                        var header = {
                            name: fastlyConfig.getHeaderNameForRoute(route),
                            action: 'set',
                            ignore_if_set: 0,
                            type: 'RESPONSE',
                            dst: 'http.Location',
                            src: '"' + route.redirect + '"',
                            response_condition: redirectResults.responseCondition.name
                        };
                        fastly.setFastlyHeader(results.version, header, cb3);
                    }]
                }, function (err, redirectResults) {
                    if (err) return cb2(err);
                    headers[id] = redirectResults.redirectHeader;
                    cb2(null, redirectResults);
                });
            } else {
                var header = {
                    name: fastlyConfig.getHeaderNameForRoute(route, 'request'),
                    action: 'set',
                    ignore_if_set: 0,
                    type: 'REQUEST',
                    dst: 'url',
                    src: '"/' + route.name + '.html"',
                    request_condition: results.appRouteRequestConditions[id].name,
                    priority: 10
                };
                fastly.setFastlyHeader(results.version, header, function (err, response) {
                    if (err) return cb2(err);
                    headers[id] = response;
                    cb2(null, response);
                });
            }
        }, function (err) {
            if (err) return cb(err);
            cb(null, headers);
        });
    }]},
    function (err, results) {
        if (err) throw new Error(err);
        if (process.env.FASTLY_ACTIVATE_CHANGES) {
            fastly.activateVersion(results.version, function (err, response) {
                if (err) throw new Error(err);
                process.stdout.write('Successfully configured and activated version ' + response.number + '\n');
                fastly.purgeAll(FASTLY_SERVICE_ID, function (err) {
                    if (err) throw new Error(err);
                    process.stdout.write('Purged all.\n');
                });
            });
        }
    }
);
<commit_msg>Conditionally purge on deploys<commit_after>var async = require('async');
var defaults = require('lodash.defaults');
var fastlyConfig = require('./lib/fastly-config-methods');
const languages = require('../languages.json');

var route_json = require('../src/routes.json');

const FASTLY_SERVICE_ID = process.env.FASTLY_SERVICE_ID || '';
const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || '';

var fastly = require('./lib/fastly-extended')(process.env.FASTLY_API_KEY, FASTLY_SERVICE_ID);

var extraAppRoutes = [
    // Homepage with querystring.
    // TODO: Should this be added for every route?
    '/\\?',
    // View html
    '/[^\/]*\.html$'
];

var routes = route_json.map(function (route) {
    return defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route);
});

async.auto({
    version: function (cb) {
        fastly.getLatestVersion(function (err, response) {
            if (err) return cb(err);
            // Validate latest version before continuing
            if (response.active || response.locked) {
                fastly.cloneVersion(response.number, function (err, response) {
                    if (err) return cb('Failed to clone latest version: ' + err);
                    cb(null, response.number);
                });
            } else {
                cb(null, response.number);
            }
        });
    },
    recvCustomVCL: ['version', function (cb, results) {
        // For all the routes in routes.json, construct a varnish-style regex that matches
        // on any of those route conditions.
        var notPassStatement = fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname);

        // For a non-pass condition, point backend at s3
        var recvCondition = '' +
            'if (' + notPassStatement + ') {\n' +
            '    set req.backend = F_s3;\n' +
            '    set req.http.host = \"' + S3_BUCKET_NAME + '\";\n' +
            '} else {\n' +
            '    if (!req.http.Fastly-FF) {\n' +
            '        if (req.http.X-Forwarded-For) {\n' +
            '            set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For \", \" client.ip;\n' +
            '        } else {\n' +
            '            set req.http.Fastly-Temp-XFF = client.ip;\n' +
            '        }\n' +
            '    } else {\n' +
            '        set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For;\n' +
            '    }\n' +
            '    set req.grace = 60s;\n' +
            '    if (req.http.Cookie:scratchlanguage) {\n' +
            '        set req.http.Accept-Language = req.http.Cookie:scratchlanguage;\n' +
            '    } else {\n' +
            '        set req.http.Accept-Language = accept.language_lookup("' +
                         Object.keys(languages).join(':') + '", ' +
                         '"en", ' +
                         'std.tolower(req.http.Accept-Language)' +
                     ');\n' +
            '    }\n' +
            '    if (req.url ~ "^/projects/" && !req.http.Cookie:scratchsessionsid) {\n' +
            '        set req.http.Cookie = "scratchlanguage=" req.http.Cookie:scratchlanguage;\n' +
            '    } else {\n' +
            '        return(pass);\n' +
            '    }\n' +
            '}\n';

        fastly.setCustomVCL(
            results.version,
            'recv-condition',
            recvCondition,
            cb
        );
    }],
    fetchCustomVCL: ['version', function (cb, results) {
        var passStatement = fastlyConfig.negateConditionStatement(
            fastlyConfig.getAppRouteCondition('../build/*', routes, extraAppRoutes, __dirname)
        );
        var ttlCondition = fastlyConfig.setResponseTTL(passStatement);
        fastly.setCustomVCL(results.version, 'fetch-condition', ttlCondition, cb);
    }],
    appRouteRequestConditions: ['version', function (cb, results) {
        var conditions = {};
        async.forEachOf(routes, function (route, id, cb2) {
            var condition = {
                name: fastlyConfig.getConditionNameForRoute(route, 'request'),
                statement: 'req.url ~ "' + route.pattern + '"',
                type: 'REQUEST',
                // Priority needs to be > 1 to not interact with http->https redirect
                priority: 10 + id
            };
            fastly.setCondition(results.version, condition, function (err, response) {
                if (err) return cb2(err);
                conditions[id] = response;
                cb2(null, response);
            });
        }, function (err) {
            if (err) return cb(err);
            cb(null, conditions);
        });
    }],
    appRouteHeaders: ['version', 'appRouteRequestConditions', function (cb, results) {
        var headers = {};
        async.forEachOf(routes, function (route, id, cb2) {
            if (route.redirect) {
                async.auto({
                    responseCondition: function (cb3) {
                        var condition = {
                            name: fastlyConfig.getConditionNameForRoute(route, 'response'),
                            statement: 'req.url ~ "' + route.pattern + '"',
                            type: 'RESPONSE',
                            priority: id
                        };
                        fastly.setCondition(results.version, condition, cb3);
                    },
                    responseObject: function (cb3) {
                        var responseObject = {
                            name: fastlyConfig.getResponseNameForRoute(route),
                            status: 301,
                            response: 'Moved Permanently',
                            request_condition: fastlyConfig.getConditionNameForRoute(route, 'request')
                        };
                        fastly.setResponseObject(results.version, responseObject, cb3);
                    },
                    redirectHeader: ['responseCondition', function (cb3, redirectResults) {
                        var header = {
                            name: fastlyConfig.getHeaderNameForRoute(route),
                            action: 'set',
                            ignore_if_set: 0,
                            type: 'RESPONSE',
                            dst: 'http.Location',
                            src: '"' + route.redirect + '"',
                            response_condition: redirectResults.responseCondition.name
                        };
                        fastly.setFastlyHeader(results.version, header, cb3);
                    }]
                }, function (err, redirectResults) {
                    if (err) return cb2(err);
                    headers[id] = redirectResults.redirectHeader;
                    cb2(null, redirectResults);
                });
            } else {
                var header = {
                    name: fastlyConfig.getHeaderNameForRoute(route, 'request'),
                    action: 'set',
                    ignore_if_set: 0,
                    type: 'REQUEST',
                    dst: 'url',
                    src: '"/' + route.name + '.html"',
                    request_condition: results.appRouteRequestConditions[id].name,
                    priority: 10
                };
                fastly.setFastlyHeader(results.version, header, function (err, response) {
                    if (err) return cb2(err);
                    headers[id] = response;
                    cb2(null, response);
                });
            }
        }, function (err) {
            if (err) return cb(err);
            cb(null, headers);
        });
    }]},
    function (err, results) {
        if (err) throw new Error(err);
        if (process.env.FASTLY_ACTIVATE_CHANGES) {
            fastly.activateVersion(results.version, function (err, response) {
                if (err) throw new Error(err);
                process.stdout.write('Successfully configured and activated version ' + response.number + '\n');
                if (process.env.FASTLY_PURGE_ALL) {
                    fastly.purgeAll(FASTLY_SERVICE_ID, function (err) {
                        if (err) throw new Error(err);
                        process.stdout.write('Purged all.\n');
                    });
                }
            });
        }
    }
);
<|endoftext|>


<commit_before>#!/usr/bin/env node

const program = require('commander')
const chalk = require('chalk')

const error = chalk.bold.red
const logErr = (msg) => console.log(error(msg))

program
  .version(require('../package.json').version)
  .description('For better use of traffic-splitter create an isolated app. Take advantage of custom rules, handling events and adding middlewares.')
  .option('-c, --conf <file>', 'provide configuration file (.json or .js with module.exports = {...})')

program.on('/help', () => program.help())

program.parse(process.argv)

if (!program.conf) {
  logErr('Missing configuration file.')
  logErr('Use: traffic-splitter -c yourConfigurationFile.')
  program.help()
}

const fs = require('fs')
let config
try {
  if (program.conf.endsWith('.json')) {
    config = JSON.parse(fs.readFileSync(program.conf))
  } else {
    config = require(process.cwd() + '/' + program.conf)
  }
} catch (err) {
  logErr(err)
  process.exit(1)
}

const TrafficSplitter = require('..')

if (!TrafficSplitter.isConfigurationValid(config)) {
  logErr('Invalid configuration. Please check traffic-splitter documentation at http://trafficsplitter.io')
  process.exit(1)
}

try {
  const splitter = new TrafficSplitter(config)
  splitter.start()
} catch (err) {
  logErr(err)
  process.exit(1)
}
<commit_msg>Remove unuecessary logic.<commit_after>#!/usr/bin/env node

const program = require('commander')
const chalk = require('chalk')

const error = chalk.bold.red
const logErr = (msg) => console.log(error(msg))

program
  .version(require('../package.json').version)
  .description('For better use of traffic-splitter create an isolated app. Take advantage of custom rules, handling events and adding middlewares.')
  .option('-c, --conf <file>', 'provide configuration file (.json or .js with module.exports = {...})')

program.on('/help', () => program.help())

program.parse(process.argv)

if (!program.conf) {
  logErr('Missing configuration file.')
  logErr('Use: traffic-splitter -c yourConfigurationFile.')
  program.help()
}

let config
try {
  config = require(process.cwd() + '/' + program.conf)
} catch (err) {
  logErr(err)
  process.exit(1)
}

const TrafficSplitter = require('..')

if (!TrafficSplitter.isConfigurationValid(config)) {
  logErr('Invalid configuration. Please check traffic-splitter documentation at http://trafficsplitter.io')
  process.exit(1)
}

try {
  const splitter = new TrafficSplitter(config)
  splitter.start()
} catch (err) {
  logErr(err)
  process.exit(1)
}
<|endoftext|>


<commit_before>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *  PivotTable.js
 *
 *  Created by Julia.Radzhabova on 06.27.17
 *  Copyright (c) 2017 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'core',
    'spreadsheeteditor/main/app/view/PivotTable'
], function () {
    'use strict';

    SSE.Controllers.PivotTable = Backbone.Controller.extend(_.extend({
        models : [],
        views : [
            'PivotTable'
        ],
        sdkViewName : '#id_main',

        initialize: function () {

            this.addListeners({
                'PivotTable': {
                    // comments handlers
                    'pivottable:rowscolumns':   _.bind(this.onCheckTemplateChange, this),
                    'pivottable:create':        _.bind(this.onCreateClick, this),
                    'pivottable:refresh':       _.bind(this.onRefreshClick, this),
                    'pivottable:select':        _.bind(this.onSelectClick, this),
                    'pivottable:style':         _.bind(this.onPivotStyleSelect, this),
                    'pivottable:layout':        _.bind(this.onPivotLayout, this),
                    'pivottable:blankrows':     _.bind(this.onPivotBlankRows, this),
                    'pivottable:subtotals':     _.bind(this.onPivotSubtotals, this),
                    'pivottable:grandtotals':   _.bind(this.onPivotGrandTotals, this)
                }
            });
        },
        onLaunch: function () {
            this._state = {
                TableName: '',
                TemplateName: '',
                RowHeader: undefined,
                RowBanded: undefined,
                ColHeader: undefined,
                ColBanded: undefined,
                DisabledControls: false
            };
            this._originalProps = null;

            this.view =   this.createView('PivotTable');

            Common.NotificationCenter.on('app:ready', this.onAppReady.bind(this));
            Common.NotificationCenter.on('api:disconnect', _.bind(this.SetDisabled, this));
        },

        setConfig: function (data, api) {
            this.setApi(api);

            if (data) {
                this.sdkViewName        =   data['sdkviewname'] || this.sdkViewName;
            }
        },

        setApi: function (api) {
            if (api) {
                this.api = api;
                this.api.asc_registerCallback('asc_onCoAuthoringDisconnect',_.bind(this.SetDisabled, this));
                this.api.asc_registerCallback('asc_onSendThemeColors',      _.bind(this.onSendThemeColors, this));
                this.api.asc_registerCallback('asc_onSelectionChanged',     _.bind(this.onSelectionChanged, this));
            }
        },

        setMode: function(mode) {
            this.appConfig = mode;
            return this;
        },

        SetDisabled: function() {
            this.view && this.view.SetDisabled(true);
        },

        // helpers

        onCheckTemplateChange: function(type, value) {
            // this._state[stateName] = undefined;
            // if (this.api)
            //     this.api.asc_changeFormatTableInfo(this._state.TableName, type, value=='checked');
            // for test
            switch (type) {
                case 0:
                    this._originalProps.asc_getStyleInfo().asc_setShowRowHeaders(this.api, this._originalProps, value=='checked');
                    break;
                case 1:
                    this._originalProps.asc_getStyleInfo().asc_setShowColHeaders(this.api, this._originalProps, value=='checked');
                    break;
                case 2:
                    this._originalProps.asc_getStyleInfo().asc_setShowRowStripes(this.api, this._originalProps, value=='checked');
                    break;
                case 3:
                    this._originalProps.asc_getStyleInfo().asc_setShowColStripes(this.api, this._originalProps, value=='checked');
                    break;
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onCreateClick: function(btn, opts){
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onRefreshClick: function(btn, opts){
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onSelectClick: function(btn, opts){
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotStyleSelect: function(record){
            if (this.api) {
                this._originalProps.asc_getStyleInfo().asc_setName(this.api, this._originalProps, record.get('name'));
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotBlankRows: function(type){
            if (this.api) {
                if (type === 'insert'){

                } else {

                }
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotLayout: function(type){
            if (this.api) {
                switch (type){
                    case 0:
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                    case 3:
                        break;
                    case 4:
                        break;
                }
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotGrandTotals: function(type){
            if (this.api) {
                var props = new Asc.CT_pivotTableDefinition();
                props.asc_setColGrandTotals(type == 1 || type == 2);
                props.asc_setRowGrandTotals(type == 1 || type == 3);
                this._originalProps.asc_set(this.api, props);
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotSubtotals: function(type){
            if (this.api) {
                switch (type){
                    case 0:
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                }
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        ChangeSettings: function(props) {
            if (props )
            {
                this._originalProps = props;

                var view = this.view,
                    needTablePictures = false,
                    styleInfo = props.asc_getStyleInfo(),
                    value = styleInfo.asc_getShowRowHeaders();
                if (this._state.RowHeader!==value) {
                    view.chRowHeader.setValue(value, true);
                    this._state.RowHeader=value;
                    needTablePictures = true;
                }

                value = styleInfo.asc_getShowColHeaders();
				if (this._state.ColHeader!==value) {
					view.chColHeader.setValue(value, true);
					this._state.ColHeader=value;
					needTablePictures = true;
				}

                value = styleInfo.asc_getShowColStripes();
				if (this._state.ColBanded!==value) {
					view.chColBanded.setValue(value, true);
					this._state.ColBanded=value;
					needTablePictures = true;
				}

                value = styleInfo.asc_getShowRowStripes();
				if (this._state.RowBanded!==value) {
					view.chRowBanded.setValue(value, true);
					this._state.RowBanded=value;
					needTablePictures = true;
				}

                value = props.asc_getColGrandTotals();
                if (this._state.ColGrandTotals!==value) {
                    this._state.ColGrandTotals=value;
                    needTablePictures = true;
                }

                value = props.asc_getRowGrandTotals();
                if (this._state.RowGrandTotals!==value) {
                    this._state.RowGrandTotals=value;
                    needTablePictures = true;
                }

                if (needTablePictures)
                    this.onApiInitPivotStyles(this.api.asc_getTablePictures(this._originalProps, true));

                //for table-template
                value = styleInfo.asc_getName();
                if (this._state.TemplateName!==value || this._isTemplatesChanged) {
                    view.pivotStyles.suspendEvents();
                    var rec = view.pivotStyles.menuPicker.store.findWhere({
                        name: value
                    });
                    view.pivotStyles.menuPicker.selectRecord(rec);
                    view.pivotStyles.resumeEvents();

                    if (this._isTemplatesChanged) {
                        if (rec)
                            view.pivotStyles.fillComboView(view.pivotStyles.menuPicker.getSelectedRec()[0],true);
                        else
                            view.pivotStyles.fillComboView(view.pivotStyles.menuPicker.store.at(0), true);
                    }
                    this._state.TemplateName=value;
                }
                this._isTemplatesChanged = false;
            }
        },

        onSendThemeColors: function() {
            // get new table templates
            if (this.view.pivotStyles && this._originalProps) {
                this.onApiInitPivotStyles(this.api.asc_getTablePictures(this._originalProps, true));
                this.view.pivotStyles.menuPicker.scroller.update({alwaysVisibleY: true});
            }
        },

        onApiInitPivotStyles: function(Templates){
            var self = this,
                styles = this.view.pivotStyles;
            this._isTemplatesChanged = true;

            var count = styles.menuPicker.store.length;
            if (count>0 && count==Templates.length) {
                var data = styles.menuPicker.store.models;
                _.each(Templates, function(template, index){
                    data[index].set('imageUrl', template.asc_getImage());
                });
            } else {
                styles.menuPicker.store.reset([]);
                var arr = [];
                _.each(Templates, function(template){
                    arr.push({
                        id          : Common.UI.getId(),
                        name        : template.asc_getName(),
                        caption     : template.asc_getDisplayName(),
                        type        : template.asc_getType(),
                        imageUrl    : template.asc_getImage(),
                        allowSelected : true,
                        selected    : false,
                        tip         : template.asc_getDisplayName()
                    });
                });
                styles.menuPicker.store.add(arr);
            }
        },

        onSelectionChanged: function(info) {
            if (this.rangeSelectionMode || !this.appConfig.isEdit) return;

            var selectType = info.asc_getFlags().asc_getSelectionType(),
                pivotInfo = info.asc_getPivotTableInfo();

            var need_disable = info.asc_getLocked();

            this.view.SetDisabled(!pivotInfo);
            if (pivotInfo)
                this.ChangeSettings(pivotInfo);
        },

        createToolbarPanel: function() {
            return this.view.getPanel();
        },

        getView: function(name) {
            return !name && this.view ?
                this.view : Backbone.Controller.prototype.getView.call(this, name);
        },

        onAppReady: function (config) {
            var me = this;
            (new Promise(function (resolve) {
                resolve();
            })).then(function () {
            });
        }

    }, SSE.Controllers.PivotTable || {}));
});<commit_msg>[SSE] Select entire pivot table.<commit_after>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *  PivotTable.js
 *
 *  Created by Julia.Radzhabova on 06.27.17
 *  Copyright (c) 2017 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'core',
    'spreadsheeteditor/main/app/view/PivotTable'
], function () {
    'use strict';

    SSE.Controllers.PivotTable = Backbone.Controller.extend(_.extend({
        models : [],
        views : [
            'PivotTable'
        ],
        sdkViewName : '#id_main',

        initialize: function () {

            this.addListeners({
                'PivotTable': {
                    // comments handlers
                    'pivottable:rowscolumns':   _.bind(this.onCheckTemplateChange, this),
                    'pivottable:create':        _.bind(this.onCreateClick, this),
                    'pivottable:refresh':       _.bind(this.onRefreshClick, this),
                    'pivottable:select':        _.bind(this.onSelectClick, this),
                    'pivottable:style':         _.bind(this.onPivotStyleSelect, this),
                    'pivottable:layout':        _.bind(this.onPivotLayout, this),
                    'pivottable:blankrows':     _.bind(this.onPivotBlankRows, this),
                    'pivottable:subtotals':     _.bind(this.onPivotSubtotals, this),
                    'pivottable:grandtotals':   _.bind(this.onPivotGrandTotals, this)
                }
            });
        },
        onLaunch: function () {
            this._state = {
                TableName: '',
                TemplateName: '',
                RowHeader: undefined,
                RowBanded: undefined,
                ColHeader: undefined,
                ColBanded: undefined,
                DisabledControls: false
            };
            this._originalProps = null;

            this.view =   this.createView('PivotTable');

            Common.NotificationCenter.on('app:ready', this.onAppReady.bind(this));
            Common.NotificationCenter.on('api:disconnect', _.bind(this.SetDisabled, this));
        },

        setConfig: function (data, api) {
            this.setApi(api);

            if (data) {
                this.sdkViewName        =   data['sdkviewname'] || this.sdkViewName;
            }
        },

        setApi: function (api) {
            if (api) {
                this.api = api;
                this.api.asc_registerCallback('asc_onCoAuthoringDisconnect',_.bind(this.SetDisabled, this));
                this.api.asc_registerCallback('asc_onSendThemeColors',      _.bind(this.onSendThemeColors, this));
                this.api.asc_registerCallback('asc_onSelectionChanged',     _.bind(this.onSelectionChanged, this));
            }
        },

        setMode: function(mode) {
            this.appConfig = mode;
            return this;
        },

        SetDisabled: function() {
            this.view && this.view.SetDisabled(true);
        },

        // helpers

        onCheckTemplateChange: function(type, value) {
            // this._state[stateName] = undefined;
            // if (this.api)
            //     this.api.asc_changeFormatTableInfo(this._state.TableName, type, value=='checked');
            // for test
            switch (type) {
                case 0:
                    this._originalProps.asc_getStyleInfo().asc_setShowRowHeaders(this.api, this._originalProps, value=='checked');
                    break;
                case 1:
                    this._originalProps.asc_getStyleInfo().asc_setShowColHeaders(this.api, this._originalProps, value=='checked');
                    break;
                case 2:
                    this._originalProps.asc_getStyleInfo().asc_setShowRowStripes(this.api, this._originalProps, value=='checked');
                    break;
                case 3:
                    this._originalProps.asc_getStyleInfo().asc_setShowColStripes(this.api, this._originalProps, value=='checked');
                    break;
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onCreateClick: function(btn, opts){
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onRefreshClick: function(btn, opts){
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onSelectClick: function(btn, opts){
            if (this.api) {
                this._originalProps.asc_select(this.api);
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotStyleSelect: function(record){
            if (this.api) {
                this._originalProps.asc_getStyleInfo().asc_setName(this.api, this._originalProps, record.get('name'));
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotBlankRows: function(type){
            if (this.api) {
                if (type === 'insert'){

                } else {

                }
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotLayout: function(type){
            if (this.api) {
                switch (type){
                    case 0:
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                    case 3:
                        break;
                    case 4:
                        break;
                }
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotGrandTotals: function(type){
            if (this.api) {
                var props = new Asc.CT_pivotTableDefinition();
                props.asc_setColGrandTotals(type == 1 || type == 2);
                props.asc_setRowGrandTotals(type == 1 || type == 3);
                this._originalProps.asc_set(this.api, props);
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        onPivotSubtotals: function(type){
            if (this.api) {
                switch (type){
                    case 0:
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                }
            }
            Common.NotificationCenter.trigger('edit:complete', this);
        },

        ChangeSettings: function(props) {
            if (props )
            {
                this._originalProps = props;

                var view = this.view,
                    needTablePictures = false,
                    styleInfo = props.asc_getStyleInfo(),
                    value = styleInfo.asc_getShowRowHeaders();
                if (this._state.RowHeader!==value) {
                    view.chRowHeader.setValue(value, true);
                    this._state.RowHeader=value;
                    needTablePictures = true;
                }

                value = styleInfo.asc_getShowColHeaders();
				if (this._state.ColHeader!==value) {
					view.chColHeader.setValue(value, true);
					this._state.ColHeader=value;
					needTablePictures = true;
				}

                value = styleInfo.asc_getShowColStripes();
				if (this._state.ColBanded!==value) {
					view.chColBanded.setValue(value, true);
					this._state.ColBanded=value;
					needTablePictures = true;
				}

                value = styleInfo.asc_getShowRowStripes();
				if (this._state.RowBanded!==value) {
					view.chRowBanded.setValue(value, true);
					this._state.RowBanded=value;
					needTablePictures = true;
				}

                value = props.asc_getColGrandTotals();
                if (this._state.ColGrandTotals!==value) {
                    this._state.ColGrandTotals=value;
                    needTablePictures = true;
                }

                value = props.asc_getRowGrandTotals();
                if (this._state.RowGrandTotals!==value) {
                    this._state.RowGrandTotals=value;
                    needTablePictures = true;
                }

                if (needTablePictures)
                    this.onApiInitPivotStyles(this.api.asc_getTablePictures(this._originalProps, true));

                //for table-template
                value = styleInfo.asc_getName();
                if (this._state.TemplateName!==value || this._isTemplatesChanged) {
                    view.pivotStyles.suspendEvents();
                    var rec = view.pivotStyles.menuPicker.store.findWhere({
                        name: value
                    });
                    view.pivotStyles.menuPicker.selectRecord(rec);
                    view.pivotStyles.resumeEvents();

                    if (this._isTemplatesChanged) {
                        if (rec)
                            view.pivotStyles.fillComboView(view.pivotStyles.menuPicker.getSelectedRec()[0],true);
                        else
                            view.pivotStyles.fillComboView(view.pivotStyles.menuPicker.store.at(0), true);
                    }
                    this._state.TemplateName=value;
                }
                this._isTemplatesChanged = false;
            }
        },

        onSendThemeColors: function() {
            // get new table templates
            if (this.view.pivotStyles && this._originalProps) {
                this.onApiInitPivotStyles(this.api.asc_getTablePictures(this._originalProps, true));
                this.view.pivotStyles.menuPicker.scroller.update({alwaysVisibleY: true});
            }
        },

        onApiInitPivotStyles: function(Templates){
            var self = this,
                styles = this.view.pivotStyles;
            this._isTemplatesChanged = true;

            var count = styles.menuPicker.store.length;
            if (count>0 && count==Templates.length) {
                var data = styles.menuPicker.store.models;
                _.each(Templates, function(template, index){
                    data[index].set('imageUrl', template.asc_getImage());
                });
            } else {
                styles.menuPicker.store.reset([]);
                var arr = [];
                _.each(Templates, function(template){
                    arr.push({
                        id          : Common.UI.getId(),
                        name        : template.asc_getName(),
                        caption     : template.asc_getDisplayName(),
                        type        : template.asc_getType(),
                        imageUrl    : template.asc_getImage(),
                        allowSelected : true,
                        selected    : false,
                        tip         : template.asc_getDisplayName()
                    });
                });
                styles.menuPicker.store.add(arr);
            }
        },

        onSelectionChanged: function(info) {
            if (this.rangeSelectionMode || !this.appConfig.isEdit) return;

            var selectType = info.asc_getFlags().asc_getSelectionType(),
                pivotInfo = info.asc_getPivotTableInfo();

            var need_disable = info.asc_getLocked();

            this.view.SetDisabled(!pivotInfo);
            if (pivotInfo)
                this.ChangeSettings(pivotInfo);
        },

        createToolbarPanel: function() {
            return this.view.getPanel();
        },

        getView: function(name) {
            return !name && this.view ?
                this.view : Backbone.Controller.prototype.getView.call(this, name);
        },

        onAppReady: function (config) {
            var me = this;
            (new Promise(function (resolve) {
                resolve();
            })).then(function () {
            });
        }

    }, SSE.Controllers.PivotTable || {}));
});<|endoftext|>