<commit_before>'use strict';

/**
 * UI-ButtonManager
 */

var ButtonManager = (function CheckBoxManager() {

	var subscribers = [];
	var buttons = [];

	var CheckBox = function CheckBox(node) {
		var topic = node.getAttribute('data-topic');
		var state = node.getAttribute('data-state');
		var name = node.getAttribute('data-label');
		var align = node.getAttribute('data-text-on');

		state = (state === "true");

		var checkbox = document.createElement("input");
		var label = document.createElement("label");

		var id = 'checkbox-' + topic;
		checkbox.id = id;
		checkbox.setAttribute('type', 'checkbox');
		checkbox.checked = state;

		label.setAttribute('for', id);
		if (name) {
			label.className = 'text';
			if (align)
				label.className += ' ' + align;
			label.textContent = name;
		}

		node.appendChild(checkbox);
		node.appendChild(label);

		this.node = node;
		this.topic = topic;
		this.checkbox = checkbox;

		checkbox.addEventListener('change', function(e) {
			notify.call(this);
		}.bind(this));

		buttons[topic] = this;
	}

	var getNode =  function getNode(topic) {
		return buttons[topic].node;
	}

	var setValue = function setValue(topic, value) {
		try {
			buttons[topic].checkbox.checked = value;
			notify.call(buttons[topic]);
		}
		catch(error) {
			console.log(error, topic, value);
		}
	}

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];

		subscribers[topic].push(callback);
	}

	var unsubscribe = function unsubscribe(topic, callback) {
		subscribers[topic].indexOf(callback);
		subscribers[topic].splice(index, 1);
	}

	var notify = function notify() {
		if (subscribers[this.topic] === undefined)
			return;
		for (var i = 0; i < subscribers[this.topic].length; i++)
			subscribers[this.topic][i](this.checkbox.checked);
	}

	var init = function init() {
		var elem = document.querySelectorAll('.ui-checkbox');
		var size = elem.length;
		for (var i = 0; i < size; i++)
			new CheckBox(elem[i]);
	}

	return {
		init : init,
		setValue : setValue,
		subscribe : subscribe,
		unsubscribe : unsubscribe
	}

})();
<commit_msg>update setValue<commit_after>'use strict';

/**
 * UI-ButtonManager
 */

var ButtonManager = (function CheckBoxManager() {

	var subscribers = [];
	var buttons = [];

	var CheckBox = function CheckBox(node) {
		var topic = node.getAttribute('data-topic');
		var state = node.getAttribute('data-state');
		var name = node.getAttribute('data-label');
		var align = node.getAttribute('data-text-on');

		state = (state === "true");

		var checkbox = document.createElement("input");
		var label = document.createElement("label");

		var id = 'checkbox-' + topic;
		checkbox.id = id;
		checkbox.setAttribute('type', 'checkbox');
		checkbox.checked = state;

		label.setAttribute('for', id);
		if (name) {
			label.className = 'text';
			if (align)
				label.className += ' ' + align;
			label.textContent = name;
		}

		node.appendChild(checkbox);
		node.appendChild(label);

		this.node = node;
		this.topic = topic;
		this.checkbox = checkbox;

		checkbox.addEventListener('change', function(e) {
			notify.call(this);
		}.bind(this));

		buttons[topic] = this;
	};

	var getNode =  function getNode(topic) {
		return buttons[topic].node;
	};

	var setValue = function setValue(topic, value) {
		var obj = buttons[topic];
		if (obj === undefined)
			return;

		obj.checkbox.checked = value;
		notify.call(obj);
	};

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];

		subscribers[topic].push(callback);
	};

	var unsubscribe = function unsubscribe(topic, callback) {
		subscribers[topic].indexOf(callback);
		subscribers[topic].splice(index, 1);
	};

	var notify = function notify() {
		if (subscribers[this.topic] === undefined)
			return;
		for (var i = 0; i < subscribers[this.topic].length; i++)
			subscribers[this.topic][i](this.checkbox.checked);
	};

	var init = function init() {
		var elem = document.querySelectorAll('.ui-checkbox');
		var size = elem.length;
		for (var i = 0; i < size; i++)
			new CheckBox(elem[i]);
	};

	return {
		init : init,
		setValue : setValue,
		subscribe : subscribe,
		unsubscribe : unsubscribe
	};

})();
<|endoftext|>


<commit_before>import Widget from "./base_widget.js";

frappe.provide("frappe.utils");

export default class QuickListWidget extends Widget {
	constructor(opts) {
		opts.shadow = true;
		super(opts);
	}

	get_config() {
		return {
			document_type: this.document_type,
			label: this.label,
			quick_list_filter: this.quick_list_filter
		};
	}

	set_actions() {
		if (this.in_customize_mode) return;

		this.setup_add_new_button();
		this.setup_refresh_list_button();
		this.setup_filter_list_button();
	}

	setup_add_new_button() {
		this.add_new_button = $(
			`

				${frappe.utils.icon('add', 'sm')}

`
		);

		this.add_new_button.appendTo(this.action_area);
		this.add_new_button.on("click", () => {
			frappe.set_route(
				frappe.utils.generate_route({type: 'doctype', name: this.document_type, doc_view: 'New'})
			);
		});
	}

	setup_refresh_list_button() {
		this.refresh_list = $(
			`

				${frappe.utils.icon('refresh', 'sm')}

`
		);

		this.refresh_list.appendTo(this.action_area);
		this.refresh_list.on("click", () => {
			this.body.empty();
			this.set_body();
		});
	}

	setup_filter_list_button() {
		this.filter_list = $(
			`

				${frappe.utils.icon('filter', 'sm')}

`
		);

		this.filter_list.appendTo(this.action_area);
		this.filter_list.on("click", () => this.setup_filter_dialog());
	}

	setup_filter(doctype) {
		if (this.filter_group) {
			this.filter_group.wrapper.empty();
			delete this.filter_group;
		}

		this.filters = frappe.utils.get_filter_from_json(this.quick_list_filter, doctype);

		this.filter_group = new frappe.ui.FilterGroup({
			parent: this.dialog.get_field("filter_area").$wrapper,
			doctype: doctype,
			on_change: () => {},
		});

		frappe.model.with_doctype(doctype, () => {
			this.filter_group.add_filters_to_filter_group(this.filters);
			this.dialog.set_df_property("filter_area", "hidden", false);
		});
	}

	setup_filter_dialog() {
		let fields = [
			{
				fieldtype: "HTML",
				fieldname: "filter_area"
			}
		];
		let me = this;
		this.dialog = new frappe.ui.Dialog({
			title: __("Set Filters for {0}", [this.document_type]),
			fields: fields,
			primary_action: function() {
				let old_filter = me.quick_list_filter;
				let filters = me.filter_group.get_filters();
				me.quick_list_filter = frappe.utils.get_filter_as_json(filters);

				this.hide();

				if (old_filter != me.quick_list_filter) {
					me.body.empty();
					me.set_footer();
					me.set_body();
				}
			},
			primary_action_label: "Set"
		});

		this.dialog.show();
		this.setup_filter(this.document_type);
	}

	render_loading_state() {
		this.body.empty();
		this.loading = $(
			`
${__(
				"Loading..."
			)}
`
		);
		this.loading.appendTo(this.body);
	}

	render_no_data_state() {
		this.loading = $(
			`
${__(
				"No Data..."
			)}
`
		);
		this.loading.appendTo(this.body);
	}

	setup_quick_list_item(doc) {
		const indicator = frappe.get_indicator(doc, this.document_type);

		let $quick_list_item = $(`

						${strip_html(doc[this.title_field_name])}

						${frappe.datetime.prettyDate(doc.modified)}

		`);

		if (indicator) {
			$(`

					${__(indicator[0])}

			`).appendTo($quick_list_item);
		}

		$(`<div class="right-arrow">${frappe.utils.icon('right', 'xs')}</div>`).appendTo($quick_list_item);

		$quick_list_item.click(() => {
			frappe.set_route(`${frappe.utils.get_form_link(this.document_type, doc.name)}`);
		});

		return $quick_list_item;
	}

	set_body() {
		this.widget.addClass("quick-list-widget-box");

		this.render_loading_state();

		frappe.model.with_doctype(this.document_type, () => {
			let fields = ['name'];

			// get name of title field
			if (!this.title_field_name) {
				let meta = frappe.get_meta(this.document_type);
				this.title_field_name = meta && meta.title_field || 'name';
			}

			if (this.title_field_name && this.title_field_name != 'name') {
				fields.push(this.title_field_name);
			}

			// check doctype has status field
			this.has_status_field = frappe.meta.has_field(this.document_type, 'status');

			if (this.has_status_field) {
				fields.push('status');
				fields.push('docstatus');

				// add workflow state field if workflow exist & is active
				let workflow_fieldname = frappe.workflow.get_state_fieldname(this.document_type);
				workflow_fieldname && fields.push(workflow_fieldname);
			}

			fields.push('modified');

			let quick_list_filter = frappe.utils.get_filter_from_json(this.quick_list_filter);

			let args = {
				method: 'frappe.desk.reportview.get',
				args: {
					doctype: this.document_type,
					fields: fields,
					filters: quick_list_filter,
					order_by: 'modified desc',
					start: 0,
					page_length: 4
				}
			};

			frappe.call(args).then((r) => {
				if (!r.message) return;
				let data = r.message;

				this.body.empty();
				data = !Array.isArray(data)
					? frappe.utils.dict(data.keys, data.values)
					: data;

				if (!data.length) {
					this.render_no_data_state();
					return;
				}

				this.quick_list = data.map(doc => this.setup_quick_list_item(doc));
				this.quick_list.forEach($quick_list_item => $quick_list_item.appendTo(this.body));
			});
		});
	}

	set_footer() {
		this.footer.empty();

		let filters = frappe.utils.get_filter_from_json(this.quick_list_filter);
		if (filters) {
			frappe.route_options = filters;
		}

		this.see_all_button = $(`
			View List
		`).appendTo(this.footer);
	}
}
<commit_msg>chore: used variable for better code visibility<commit_after>import Widget from "./base_widget.js";

frappe.provide("frappe.utils");

export default class QuickListWidget extends Widget {
	constructor(opts) {
		opts.shadow = true;
		super(opts);
	}

	get_config() {
		return {
			document_type: this.document_type,
			label: this.label,
			quick_list_filter: this.quick_list_filter
		};
	}

	set_actions() {
		if (this.in_customize_mode) return;

		this.setup_add_new_button();
		this.setup_refresh_list_button();
		this.setup_filter_list_button();
	}

	setup_add_new_button() {
		this.add_new_button = $(
			`

				${frappe.utils.icon('add', 'sm')}

`
		);

		this.add_new_button.appendTo(this.action_area);
		this.add_new_button.on("click", () => {
			frappe.set_route(
				frappe.utils.generate_route({type: 'doctype', name: this.document_type, doc_view: 'New'})
			);
		});
	}

	setup_refresh_list_button() {
		this.refresh_list = $(
			`

				${frappe.utils.icon('refresh', 'sm')}

`
		);

		this.refresh_list.appendTo(this.action_area);
		this.refresh_list.on("click", () => {
			this.body.empty();
			this.set_body();
		});
	}

	setup_filter_list_button() {
		this.filter_list = $(
			`

				${frappe.utils.icon('filter', 'sm')}

`
		);

		this.filter_list.appendTo(this.action_area);
		this.filter_list.on("click", () => this.setup_filter_dialog());
	}

	setup_filter(doctype) {
		if (this.filter_group) {
			this.filter_group.wrapper.empty();
			delete this.filter_group;
		}

		this.filters = frappe.utils.get_filter_from_json(this.quick_list_filter, doctype);

		this.filter_group = new frappe.ui.FilterGroup({
			parent: this.dialog.get_field("filter_area").$wrapper,
			doctype: doctype,
			on_change: () => {},
		});

		frappe.model.with_doctype(doctype, () => {
			this.filter_group.add_filters_to_filter_group(this.filters);
			this.dialog.set_df_property("filter_area", "hidden", false);
		});
	}

	setup_filter_dialog() {
		let fields = [
			{
				fieldtype: "HTML",
				fieldname: "filter_area"
			}
		];
		let me = this;
		this.dialog = new frappe.ui.Dialog({
			title: __("Set Filters for {0}", [this.document_type]),
			fields: fields,
			primary_action: function() {
				let old_filter = me.quick_list_filter;
				let filters = me.filter_group.get_filters();
				me.quick_list_filter = frappe.utils.get_filter_as_json(filters);

				this.hide();

				if (old_filter != me.quick_list_filter) {
					me.body.empty();
					me.set_footer();
					me.set_body();
				}
			},
			primary_action_label: "Set"
		});

		this.dialog.show();
		this.setup_filter(this.document_type);
	}

	render_loading_state() {
		this.body.empty();
		this.loading = $(
			`
${__(
				"Loading..."
			)}
`
		);
		this.loading.appendTo(this.body);
	}

	render_no_data_state() {
		this.loading = $(
			`
${__(
				"No Data..."
			)}
`
		);
		this.loading.appendTo(this.body);
	}

	setup_quick_list_item(doc) {
		const indicator = frappe.get_indicator(doc, this.document_type);

		let $quick_list_item = $(`

						${strip_html(doc[this.title_field_name])}

						${frappe.datetime.prettyDate(doc.modified)}

		`);

		if (indicator) {
			$(`

					${__(indicator[0])}

			`).appendTo($quick_list_item);
		}

		$(`<div class="right-arrow">${frappe.utils.icon('right', 'xs')}</div>`).appendTo($quick_list_item);

		$quick_list_item.click(() => {
			frappe.set_route(`${frappe.utils.get_form_link(this.document_type, doc.name)}`);
		});

		return $quick_list_item;
	}

	set_body() {
		this.widget.addClass("quick-list-widget-box");

		this.render_loading_state();

		frappe.model.with_doctype(this.document_type, () => {
			let fields = ['name'];

			// get name of title field
			if (!this.title_field_name) {
				let meta = frappe.get_meta(this.document_type);
				this.title_field_name = meta && meta.title_field || 'name';
			}

			if (this.title_field_name && this.title_field_name != 'name') {
				fields.push(this.title_field_name);
			}

			// check doctype has status field
			this.has_status_field = frappe.meta.has_field(this.document_type, 'status');

			if (this.has_status_field) {
				fields.push('status');
				fields.push('docstatus');

				// add workflow state field if workflow exist & is active
				let workflow_fieldname = frappe.workflow.get_state_fieldname(this.document_type);
				workflow_fieldname && fields.push(workflow_fieldname);
			}

			fields.push('modified');

			let quick_list_filter = frappe.utils.get_filter_from_json(this.quick_list_filter);

			let args = {
				method: 'frappe.desk.reportview.get',
				args: {
					doctype: this.document_type,
					fields: fields,
					filters: quick_list_filter,
					order_by: 'modified desc',
					start: 0,
					page_length: 4
				}
			};

			frappe.call(args).then((r) => {
				if (!r.message) return;
				let data = r.message;

				this.body.empty();
				data = !Array.isArray(data)
					? frappe.utils.dict(data.keys, data.values)
					: data;

				if (!data.length) {
					this.render_no_data_state();
					return;
				}

				this.quick_list = data.map(doc => this.setup_quick_list_item(doc));
				this.quick_list.forEach($quick_list_item => $quick_list_item.appendTo(this.body));
			});
		});
	}

	set_footer() {
		this.footer.empty();

		let filters = frappe.utils.get_filter_from_json(this.quick_list_filter);
		if (filters) {
			frappe.route_options = filters;
		}
		let route = frappe.utils.generate_route({type: 'doctype', name: this.document_type});
		this.see_all_button = $(`
			View List
		`).appendTo(this.footer);
	}
}
<|endoftext|>


<commit_before>
const os = require('os');
const util = require('util');
const path = require('path');
const fs = require('fs-extra');
const child_process = require('child_process');
const async = require('async');
const common = require('./sqlite_common');

function download(options, callback){

  // load configuration variables
  const config = require('pelias-config').generate(require('../schema')).imports.whosonfirst;
  const sqliteDir = path.join(config.datapath, 'sqlite');
  fs.ensureDirSync(sqliteDir);

  // generate a download function per database listed in config
  const downloadFunctions = options.databases.map(filename => {
    return (done) => {

      // build shell command
      const options = { cwd: path.basename(__dirname) };
      const cmd = './sqlite_download.sh';
      const args = [ filename, path.join( sqliteDir, filename ) ];
      const child = child_process.spawn(cmd, args, options);

      // handle stdio
      function stdio( ioname, buffer ){
        child[ioname].on('data', data => {
          buffer += data;
          let line = data.toString().trim();
          if( line.length ){ console.log( line ); }
        });
      }

      var stdout, stderr;
      stdio( 'stdout', stdout );
      stdio( 'stderr', stderr );

      // handle exit code
      child.on('exit', code => {
        if( '0' !== code.toString() ){
          console.error('error downloading: ' + filename);
        }
        done();
      });
    };
  });

  // download one database for every other CPU (tar and bzip2 can both max out one core)
  // (but not more than 4, to keep things from getting too intense)
  // lower this number to make the downloader more CPU friendly
  // raise this number to (possibly) make it faster
  const simultaneousDownloads = Math.max(4, Math.min(1, os.cpus().length / 2));

  // download all files
  async.parallelLimit(downloadFunctions, simultaneousDownloads, callback);
}

module.exports.download = download;
<commit_msg>fix(sqlite-download): Merge pull request #380 from by-implication/sqlite-download<commit_after>
const os = require('os');
const util = require('util');
const path = require('path');
const fs = require('fs-extra');
const child_process = require('child_process');
const async = require('async');
const common = require('./sqlite_common');

function download(options, callback){

  // load configuration variables
  const config = require('pelias-config').generate(require('../schema')).imports.whosonfirst;
  const sqliteDir = path.join(config.datapath, 'sqlite');
  fs.ensureDirSync(sqliteDir);

  // generate a download function per database listed in config
  const downloadFunctions = options.databases.map(filename => {
    return (done) => {

      // build shell command
      const options = { cwd: __dirname };
      const cmd = './sqlite_download.sh';
      const args = [ filename, path.join( sqliteDir, filename ) ];
      const child = child_process.spawn(cmd, args, options);

      // handle stdio
      function stdio( ioname, buffer ){
        child[ioname].on('data', data => {
          buffer += data;
          let line = data.toString().trim();
          if( line.length ){ console.log( line ); }
        });
      }

      var stdout, stderr;
      stdio( 'stdout', stdout );
      stdio( 'stderr', stderr );

      // handle exit code
      child.on('exit', code => {
        if( '0' !== code.toString() ){
          console.error('error downloading: ' + filename);
        }
        done();
      });
    };
  });

  // download one database for every other CPU (tar and bzip2 can both max out one core)
  // (but not more than 4, to keep things from getting too intense)
  // lower this number to make the downloader more CPU friendly
  // raise this number to (possibly) make it faster
  const simultaneousDownloads = Math.max(4, Math.min(1, os.cpus().length / 2));

  // download all files
  async.parallelLimit(downloadFunctions, simultaneousDownloads, callback);
}

module.exports.download = download;
<|endoftext|>


<commit_before>
var ComposeView = function (options) {
  "use strict";
  var self = this;
  options = $.extend({"id": ''}, options);
  options = $.extend({"email": Email.prototype.fromSelector(options.id+'.compose-view')}, options);

  /**
   * form validation
   * @returns {boolean}
   */
  self.isValid = function () {
    "use strict";
    return self.isToValid() &&
      self.isCcValid() &&
      self.isBccValid() &&
      self.isSubjectValid() &&
      self.isBodyValid();
  };

  /**
   *
   * @returns {boolean}
   */
  self.isToValid = function () {
    "use strict";
    var emailAddresses = $('#' + options.id + ' [name=to_addrs_names]').val().split('/[,;]/');

    if(self.isValidEmailAddresses(emailAddresses)) {
      return true;
    }

    self.setValidationMessage('to_addrs_names', 'LBL_HAS_INVALID_EMAIL_TO');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isCcValid = function () {
    "use strict";

    var cc =$('#' + options.id + ' [name=cc_addrs_names]').val();
    var emailAddresses = cc.split('/[,;]/');

    if(self.isValidEmailAddresses(emailAddresses) || cc === '') {
      return true;
    }

    self.setValidationMessage('cc_addrs_names', 'LBL_HAS_INVALID_EMAIL_CC');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isBccValid = function () {
    "use strict";
    var bcc =$('#' + options.id + ' [name=bcc_addrs_names]').val();
    var emailAddresses = bcc.split('/[,;]/');

    if(self.isValidEmailAddresses(emailAddresses) || bcc === '') {
      return true;
    }

    self.setValidationMessage('bcc_addrs_names', 'LBL_HAS_INVALID_EMAIL_BCC');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isSubjectValid = function () {
    "use strict";

    if($('#'  + options.id + ' [name=name]').val() !== '') {
      return true;
    }

    self.setValidationMessage('name', 'LBL_HAS_EMPTY_EMAIL_SUBJECT');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isBodyValid = function () {
    "use strict";

    if($('#' + options.id + ' [name=description_html]').val() !== '') {
      return true;
    }

    self.setValidationMessage('description_html', 'LBL_HAS_EMPTY_EMAIL_BODY');
    return false;
  };

  /**
   *
   * @param field string name
   * @param label string eg LBL_OK
   */
  self.setValidationMessage = function(field, label) {
    "use strict";
    var translated_message = SUGAR.language.translate('Emails', label);
    alert(translated_message);
  };

  /**
   *
   * @param emailAddresses array|object eg ['a@example.com', 'b@example.com']
   * @returns {boolean}
   */
  self.isValidEmailAddresses = function(emailAddresses) {
    "use strict";
    if(typeof emailAddresses === 'object' || typeof emailAddresses === 'array') {
      for(var i = 0; i < emailAddresses.length; i++) {
        emailAddresses[i] = (emailAddresses[i] !== '') && isValidEmail(emailAddresses[i]);
      }
      if(emailAddresses.indexOf(false) === -1) {
        return true;
      }
    }

    return false;
  };

  // Construct view
  $(document).ready(function() {
    "use strict";
    /**
     * Used to preview email. It also doubles as a means to get the plain text version
     * using $('#'+options.id + ' .html_preview').text();s
     */
    $('

').addClass('hidden').addClass('html_preview').appendTo("form#" + options.id + ".composer-view");

    if (typeof tinymce === "undefined") {
      console.error('Cannot find tiny mce. Please include it in modules/Emails/metadata/composeviewdefs.php.');
      $('<input>')
        .attr('name', 'description_html')
        .attr('type', 'hidden')
        .attr('id', 'description_html')
        .appendTo($('#' + options.id));

      // copy plain to html
      $('#' + options.id + ' #description_html').closest('.edit-view-row-item').addClass('hidden');
      $('#' + options.id + ' textarea[name=description]').on("keyup", function (e) {
        $('#' + options.id + ' [name=description_html]').val($('#' + options.id + ' textarea[name=description]').val());
      });
    } else {
      $('#' + options.id + ' [name=description]').closest('.edit-view-row-item').addClass('hidden');
      tinymce.init({
        selector: '#' + options.id + ' #description_html',
        mode: "specific_textareas",
        plugins: "fullscreen",
        formats: {
          bold: {inline: 'b'},
          italic: {inline: 'i'},
          underline: {inline: 'u'}
        },
        setup: function (editor) {
          editor.on('change', function (e) {
            // copy html to plain
            $('#' + options.id + ' .html_preview').html(editor.getContent());
            $('#' + options.id + ' [name=description_html]').val(editor.getContent());
            $('#' + options.id + ' [name=description]').val($('#' + options.id + ' .html_preview').text());
          });
        }
      });
    }

    // Handle sent email submission
    $("form#" + options.id + ".composer-view").submit(function () {
      $.ajax({
        type: "POST",
        data: $(this).serialize(),
        cache: false,
        url: $(this).attr('action')
      }).done(function (data) {
        "use strict";
        // If the user is view the form own its own
        if ($('#' + options.id + ' input[type="hidden"][name="return_module"]').val() !== '') {
          var redirect_location = 'index.php?module=' + $('#' + options.id + ' input[type="hidden"][name="return_module"]').val() +
            '&action=' +
            $('#' + options.id + ' input[type="hidden"][name="return_action"]').val();
          location.href = redirect_location;
        };
      }).error(function (data) {
        "use strict";
        alert(SUGAR.language.translate($('#' + options.id + ' input[type="hidden"][name="module"]').val(), 'LBL_ERROR_SENDING_EMAIL'))
      });
      return false;
    });

    // Handle toolbar button events
    $('#' + options.id + ' .btn-send-email').click(function () {
      "use strict";
      self.email = Email.prototype.fromSelector(options.id + '.compose-view');
      if (self.isValid()) {
        $('#' + options.id).submit();
      }
      return false;
    });
  });
};
<commit_msg>Adding license<commit_after>/**
 *
 * SugarCRM Community Edition is a customer relationship management program developed by
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
 *
 * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
 * Copyright (C) 2011 - 2017 SalesAgility Ltd.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by the
 * Free Software Foundation with the addition of the following permission added
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along with
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 *
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
 */

var ComposeView = function (options) {
  "use strict";
  var self = this;
  options = $.extend({"id": ''}, options);
  options = $.extend({"email": Email.prototype.fromSelector(options.id+'.compose-view')}, options);

  /**
   * form validation
   * @returns {boolean}
   */
  self.isValid = function () {
    "use strict";
    return self.isToValid() &&
      self.isCcValid() &&
      self.isBccValid() &&
      self.isSubjectValid() &&
      self.isBodyValid();
  };

  /**
   *
   * @returns {boolean}
   */
  self.isToValid = function () {
    "use strict";
    var emailAddresses = $('#' + options.id + ' [name=to_addrs_names]').val().split('/[,;]/');

    if(self.isValidEmailAddresses(emailAddresses)) {
      return true;
    }

    self.setValidationMessage('to_addrs_names', 'LBL_HAS_INVALID_EMAIL_TO');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isCcValid = function () {
    "use strict";

    var cc =$('#' + options.id + ' [name=cc_addrs_names]').val();
    var emailAddresses = cc.split('/[,;]/');

    if(self.isValidEmailAddresses(emailAddresses) || cc === '') {
      return true;
    }

    self.setValidationMessage('cc_addrs_names', 'LBL_HAS_INVALID_EMAIL_CC');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isBccValid = function () {
    "use strict";
    var bcc =$('#' + options.id + ' [name=bcc_addrs_names]').val();
    var emailAddresses = bcc.split('/[,;]/');

    if(self.isValidEmailAddresses(emailAddresses) || bcc === '') {
      return true;
    }

    self.setValidationMessage('bcc_addrs_names', 'LBL_HAS_INVALID_EMAIL_BCC');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isSubjectValid = function () {
    "use strict";

    if($('#'  + options.id + ' [name=name]').val() !== '') {
      return true;
    }

    self.setValidationMessage('name', 'LBL_HAS_EMPTY_EMAIL_SUBJECT');
    return false;
  };

  /**
   *
   * @returns {boolean}
   */
  self.isBodyValid = function () {
    "use strict";

    if($('#' + options.id + ' [name=description_html]').val() !== '') {
      return true;
    }

    self.setValidationMessage('description_html', 'LBL_HAS_EMPTY_EMAIL_BODY');
    return false;
  };

  /**
   *
   * @param field string name
   * @param label string eg LBL_OK
   */
  self.setValidationMessage = function(field, label) {
    "use strict";
    var translated_message = SUGAR.language.translate('Emails', label);
    alert(translated_message);
  };

  /**
   *
   * @param emailAddresses array|object eg ['a@example.com', 'b@example.com']
   * @returns {boolean}
   */
  self.isValidEmailAddresses = function(emailAddresses) {
    "use strict";
    if(typeof emailAddresses === 'object' || typeof emailAddresses === 'array') {
      for(var i = 0; i < emailAddresses.length; i++) {
        emailAddresses[i] = (emailAddresses[i] !== '') && isValidEmail(emailAddresses[i]);
      }
      if(emailAddresses.indexOf(false) === -1) {
        return true;
      }
    }

    return false;
  };

  // Construct view
  $(document).ready(function() {
    "use strict";
    /**
     * Used to preview email. It also doubles as a means to get the plain text version
     * using $('#'+options.id + ' .html_preview').text();s
     */
    $('

').addClass('hidden').addClass('html_preview').appendTo("form#" + options.id + ".composer-view");

    if (typeof tinymce === "undefined") {
      console.error('Cannot find tiny mce. Please include it in modules/Emails/metadata/composeviewdefs.php.');
      $('<input>')
        .attr('name', 'description_html')
        .attr('type', 'hidden')
        .attr('id', 'description_html')
        .appendTo($('#' + options.id));

      // copy plain to html
      $('#' + options.id + ' #description_html').closest('.edit-view-row-item').addClass('hidden');
      $('#' + options.id + ' textarea[name=description]').on("keyup", function (e) {
        $('#' + options.id + ' [name=description_html]').val($('#' + options.id + ' textarea[name=description]').val());
      });
    } else {
      $('#' + options.id + ' [name=description]').closest('.edit-view-row-item').addClass('hidden');
      tinymce.init({
        selector: '#' + options.id + ' #description_html',
        mode: "specific_textareas",
        plugins: "fullscreen",
        formats: {
          bold: {inline: 'b'},
          italic: {inline: 'i'},
          underline: {inline: 'u'}
        },
        setup: function (editor) {
          editor.on('change', function (e) {
            // copy html to plain
            $('#' + options.id + ' .html_preview').html(editor.getContent());
            $('#' + options.id + ' [name=description_html]').val(editor.getContent());
            $('#' + options.id + ' [name=description]').val($('#' + options.id + ' .html_preview').text());
          });
        }
      });
    }

    // Handle sent email submission
    $("form#" + options.id + ".composer-view").submit(function () {
      $.ajax({
        type: "POST",
        data: $(this).serialize(),
        cache: false,
        url: $(this).attr('action')
      }).done(function (data) {
        "use strict";
        // If the user is view the form own its own
        if ($('#' + options.id + ' input[type="hidden"][name="return_module"]').val() !== '') {
          var redirect_location = 'index.php?module=' + $('#' + options.id + ' input[type="hidden"][name="return_module"]').val() +
            '&action=' +
            $('#' + options.id + ' input[type="hidden"][name="return_action"]').val();
          location.href = redirect_location;
        } else {
          // TODO: Create custom event for success
        }
      }).error(function (data) {
        "use strict";
        alert(SUGAR.language.translate($('#' + options.id + ' input[type="hidden"][name="module"]').val(), 'LBL_ERROR_SENDING_EMAIL'))
        // TODO: Create custom event for error
      });
      return false;
    });

    // Handle toolbar button events
    $('#' + options.id + ' .btn-send-email').click(function () {
      "use strict";
      self.email = Email.prototype.fromSelector(options.id + '.compose-view');
      if (self.isValid()) {
        $('#' + options.id).submit();
      }
      return false;
    });
    // TODO: Create custom event for on load
  });
};
<|endoftext|>


<commit_before>elemId = null;
isWorkerTask = function(eventObj) {
	return current_user && eventObj.members.indexOf(current_user.id) > - 1;
}

window.onload = function(){
	//Initialize the tour
	if (!$.cookie('first')){
		pOverview = flashTeamsJSON['projectoverview']
		if (!pOverview){
			pOverview = "This project has no project description"
		}
		for (i = 0; i < flashTeamsJSON["events"].length; i++){
	    	if (isWorkerTask(flashTeamsJSON["events"][i])){
	    		elemId = flashTeamsJSON["events"][i]["id"];
	    		if(i > 0){
	    			prevElem = flashTeamsJSON["events"][i-1]["id"]
	    		}
	    		console.log(elemId);
	    		break;
	    	}
	    }
	    var eventTour = new Tour({
		autoscroll: true,
		steps: [
		// {	orphan: true,
		{
			orphan: true,
			title: "Welcome to Foundry!",
			// content: flashTeamsJSON['projectoverview'],
			content: "
Welcome to Foundry. We're here to help you get started!
"
			+ "Read the Project Description below, and follow the next few steps in order to start your project."
			+ "

"
			+ pOverview
			+"
"
			+"
"
			+"<button class='btn btn-default' data-role='next'>Next »</button>
"
			+"<button class='btn btn-default' data-role='end'>End tour</button>
",
			template: "

"
			+"

"
		},
		{	element: "#g_" + prevElem,
			title: "The Previous Task",
			// backdrop: true,
			html: true,
			content: "This is the task right before yours."
			+ " Click on the task to read about the details of the task, and the documentation information"
			+ " that the previous worker has left for you."
		},
		{	element: "#g_" + elemId,
			title: "Your Task",
			// backdrop: true,
			html: true,
			content: "This is YOUR task. You can now end this tour, and
click on the task rectangle"
			+ " to read about your task, and get started.

"
			+ "Pay close attention to the task description, the 'inputs' (what other workers have handed off to you)"
			+ ", and the deliverables you are expected to create"
		}
		]
		});
		eventTour.init();
	    eventTour.start(true);
	    eventTour.goTo(0); //Always start tour at the first step
	    $.cookie('first','1',{expires: 1});
	}
	else{
		console.log("YAY COOKIE");
	}
};

<commit_msg>Alexandra's comments added<commit_after>elemId = null;
prevElem = null;
isWorkerTask = function(eventObj) {
	return current_user && eventObj.members.indexOf(current_user.id) > - 1;
}

window.onload = function(){
	//Initialize the tour
	if (!$.cookie('first')){
		pOverview = flashTeamsJSON['projectoverview']
		if (!pOverview){
			pOverview = "This project has no project description"
		}
		for (i = 0; i < flashTeamsJSON["events"].length; i++){
	    	if (isWorkerTask(flashTeamsJSON["events"][i])){
	    		elemId = flashTeamsJSON["events"][i]["id"];
	    		if(i > 0){
	    			prevElem = flashTeamsJSON["events"][i-1]["id"]
	    		}
	    		console.log(elemId);
	    		break;
	    	}
	    }
	    var eventTour = new Tour({
		autoscroll: true,
		steps: [
		// {	orphan: true,
		{
			orphan: true,
			title: "Welcome to Foundry!",
			// content: flashTeamsJSON['projectoverview'],
			content: "
Welcome to Foundry. We're here to help you get started!
"
			+ "Read the Project Description below, and follow the next few steps in order to start your project."
			+ "

"
			+ pOverview
			+"
"
			+"
"
			+"<button class='btn btn-default' data-role='next'>Next »</button>
"
			+"<button class='btn btn-default' data-role='end'>End tour</button>
",
			template: "

"
			+"

"
		},
		{	element: "#g_" + prevElem,
			title: "The Previous Task",
			// backdrop: true,
			html: true,
			content: "This is the task right before yours."
			+ " Click on the task to read about the details of the task, and the documentation information"
			+ " that the previous worker has left for you."
			+ "
Pay close attention to the tasks that have handoffs (arrows) leading into your task."
		},
		{	element: "#g_" + elemId,
			title: "Your Task",
			// backdrop: true,
			html: true,
			content: "This is YOUR task. You can now end this tour, and
click on the task rectangle"
			+ " to read about your task, and get started.

"
			+ "Pay close attention to the task description, the 'inputs' (what other workers have handed off to you)"
			+ ", and the deliverables you are expected to create"
		}
		]
		});
		eventTour.init();
	    eventTour.start(true);
	    eventTour.goTo(0); //Always start tour at the first step
	    $.cookie('first','1',{expires: 1});
	}
	else{
		console.log("YAY COOKIE");
	}
};

<|endoftext|>


<commit_before>( function( mw, $ ) { "use strict";
	// Add supported external players:
	$( mw ).bind('EmbedPlayerUpdateMediaPlayers', function( event, mediaPlayers ){

		var youTubePlayer = new mw.MediaPlayer( 'youTube', ['video/youtube'], 'YouTube' );
		mediaPlayers.addPlayer( youTubePlayer );
		mediaPlayers.defaultPlayers['video/youtube'] = [ 'YouTube' ];

	});
	// Setup the check for KalturaSupport_AddExternalMedia event
	$( mw ).bind( 'EmbedPlayerNewPlayer', function(event, embedPlayer){
		$( embedPlayer ).bind( 'KalturaSupport_AddExternalMedia', function(event, entryMeta){
			switch( entryMeta.externalSourceType ){
				case 'YouTube':
					embedPlayer.mediaElement.tryAddSource(
						$('<soruce>').attr({
							'src' : entryMeta.creditUrl,
							'type': 'video/youtube'
						})
					)
				break;
				default:
					mw.log( "Error: Unknown external type: " + entryMeta.externalSourceType );
				break;
			}
		})
	});

} )( window.mw, window.jQuery );<commit_msg>ExternalPlayers: WP change<commit_after>( function( mw, $ ) { "use strict";

	// Add supported external players:
	$( mw ).bind('EmbedPlayerUpdateMediaPlayers', function( event, mediaPlayers ){

		var youTubePlayer = new mw.MediaPlayer( 'youTube', ['video/youtube'], 'YouTube' );
		mediaPlayers.addPlayer( youTubePlayer );
		mediaPlayers.defaultPlayers['video/youtube'] = [ 'YouTube' ];

	});

	// Setup the check for KalturaSupport_AddExternalMedia event
	$( mw ).bind( 'EmbedPlayerNewPlayer', function(event, embedPlayer){
		$( embedPlayer ).bind( 'KalturaSupport_AddExternalMedia', function(event, entryMeta){
			switch( entryMeta.externalSourceType ){
				case 'YouTube':
					embedPlayer.mediaElement.tryAddSource(
						$('<soruce>').attr({
							'src' : entryMeta.creditUrl,
							'type': 'video/youtube'
						})
					)
				break;
				default:
					mw.log( "Error: Unknown external type: " + entryMeta.externalSourceType );
				break;
			}
		})
	});

} )( window.mw, window.jQuery );<|endoftext|>


<commit_before>function isInt(n) {
    return typeof n === 'number' && n % 1 == 0;
}

var noop = function (args) {
    return true;
};

var singleNumberValidation = function (args) {
    if (args.length === 1) {
        if (isInt(args[0])) {
            return true;
        } else {
            return new TypeError('Argument must be an integer');
        }
    }
    return new Error('Method must be called with exactly one Number argument');
};

/**
 * @type {Object.<string, Function>} name of the method and validation function
 */
module.exports = {	//query methods which modifies the collection are not included, those have to be called via RPC methods
    all: noop,
    and: noop,
    box: noop,
    center: noop,
    centerSphere: noop,
    circle: noop,
    comment: noop,
    //    count: noop,      //this is query option done in server memory, so you can use it on client
    //	distinct: noop,		//must be done in server memory, TODO implement this
    elemMatch: noop,
    equals: noop,
    exists: noop,
    find: noop,
    findOne: function (args) {
        if (args.length === 0) {
            return true;
        } else {
            if (args.length > 1) {
                return new Error("FindOne does not take more than one argument");
            }
            if (typeof args[0] !== 'object') {
                return new TypeError("FindOne takes just one Object as argument");
            }
            return true;
        }
    },
    geometry: noop,
    gt: noop,
    gte: noop,
    hint: noop,
    in: noop,
    intersects: noop,
//		lean: noop, //always enabled
    limit: singleNumberValidation,  //is not sent to the DB, skipping and limiting is done in memory because it would be a problem for liveQueries
    lt: noop,
    lte: noop,
    maxDistance: noop,
    maxScan: singleNumberValidation,
    mod: noop,
    ne: noop,
    near: noop,
    nearSphere: noop,
    nin: noop,
    nor: noop,
    or: noop,
    polygon: noop,
    populate: noop,
    read: noop,
    regex: noop,
    select: noop,
    size: noop,
    skip: singleNumberValidation,	//is not sent to the DB, skipping and limiting is done in memory because it would be a problem for liveQueries
    slice: noop,
    sort: noop,     //must be a string, does not accept an array
    where: function (args) {
        if (args.length > 0 && args.length <= 2) {
            return true;    //TODO check types here
        }
        return new Error('Method was called with wrong number of arguments');
    },
    within: noop
};
<commit_msg>noop does not need arguments<commit_after>function isInt(n) {
    return typeof n === 'number' && n % 1 == 0;
}

var noop = function () {
    return true;
};

var singleNumberValidation = function (args) {
    if (args.length === 1) {
        if (isInt(args[0])) {
            return true;
        } else {
            return new TypeError('Argument must be an integer');
        }
    }
    return new Error('Method must be called with exactly one Number argument');
};

/**
 * @type {Object.<string, Function>} name of the method and validation function
 */
module.exports = {	//query methods which modifies the collection are not included, those have to be called via RPC methods
    all: noop,
    and: noop,
    box: noop,
    center: noop,
    centerSphere: noop,
    circle: noop,
    comment: noop,
    //    count: noop,      //this is query option done in server memory, so you can use it on client
    //	distinct: noop,		//must be done in server memory, TODO implement this
    elemMatch: noop,
    equals: noop,
    exists: noop,
    find: noop,
    findOne: function (args) {
        if (args.length === 0) {
            return true;
        } else {
            if (args.length > 1) {
                return new Error("FindOne does not take more than one argument");
            }
            if (typeof args[0] !== 'object') {
                return new TypeError("FindOne takes just one Object as argument");
            }
            return true;
        }
    },
    geometry: noop,
    gt: noop,
    gte: noop,
    hint: noop,
    in: noop,
    intersects: noop,
//		lean: noop, //always enabled
    limit: singleNumberValidation,  //is not sent to the DB, skipping and limiting is done in memory because it would be a problem for liveQueries
    lt: noop,
    lte: noop,
    maxDistance: noop,
    maxScan: singleNumberValidation,
    mod: noop,
    ne: noop,
    near: noop,
    nearSphere: noop,
    nin: noop,
    nor: noop,
    or: noop,
    polygon: noop,
    populate: noop,
    read: noop,
    regex: noop,
    select: noop,
    size: noop,
    skip: singleNumberValidation,	//is not sent to the DB, skipping and limiting is done in memory because it would be a problem for liveQueries
    slice: noop,
    sort: noop,     //must be a string, does not accept an array
    where: function (args) {
        if (args.length > 0 && args.length <= 2) {
            return true;    //TODO check types here
        }
        return new Error('Method was called with wrong number of arguments');
    },
    within: noop
};
<|endoftext|>


<commit_before>( function( mw, $ ) {"use strict";

	// Todo: support "visible" attribute to show/hide button on player state change
	mw.PluginManager.add( 'largePlayBtn', mw.KBaseComponent.extend({
		defaultConfig: {
			'parent': 'videoHolder',
			'order': 1
		},
		isSafeEnviornment: function(){
			return !(mw.getConfig( 'EmbedPlayer.WebKitPlaysInline') && mw.isIphone());
		},
		setup: function() {
			this.addBindings();
		},
		/**
		 * Checks if the play button should stay on screen during playback,
		 * cases where a native player is dipalyed such as iPhone.
		 */
		isPersistantPlayBtn: function(){
			return mw.isAndroid2() || this.getPlayer().isLinkPlayer ||
					( mw.isIphone() && mw.getConfig( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' ) );
		},
		/**
		 * Checks if a large play button should be displayed on the
		 * otherwise native player
		 */
		useLargePlayBtn: function(){
			if( this.isPersistantPlayBtn() ){
				return true;
			}
			// If we are using native controls return false:
			return !this.getPlayer().useNativePlayerControls();
		},
		addBindings: function() {
			var _this = this;
			this.bind('showInlineDownloadLink', function(e, linkUrl){
				_this.getComponent().attr({
					'href': linkUrl,
					'target': '_blank'
				});
			});
			this.bind('onChangeMediaDone', function(){
				_this.showButton();
			});
			this.bind('playerReady', function() {
				_this.showButton();
			});
			this.bind('playing', function() {
				_this.hideButton();
			});
			this.bind('onpause', function() {
				_this.showButton();
			});
			this.bind('onEndedDone', function(){
				_this.showButton();
			});
		},
		showButton: function(){
			if( this.useLargePlayBtn() ) {
				this.getComponent().show();
			}
		},
		hideButton: function(){
			if( !this.isPersistantPlayBtn() ) {
				this.getComponent().hide();
			}
		},
		clickButton: function( e ){
			if( this.getPlayer().isLinkPlayer ) {
				this.getPlayer().triggerHelper( 'firstPlay' ); // To send stats event for play
				this.getPlayer().triggerHelper( 'playing' );
			} else {
				e.preventDefault();
				this.getPlayer().sendNotification( 'doPlay' );
			}
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				this.$el = $( '<a />' )
							.attr( {
								'href' : '#',
								'title' : gM( 'mwe-embedplayer-play_clip' ),
								'class'	: "large-play-btn icon-play-2"
							} )
							.hide()
							// Add play hook:
							.click( function(e) {
								_this.clickButton(e);
							} );
			}
			return this.$el;
		}
	})
	);

} )( window.mw, window.jQuery );<commit_msg>little clean up<commit_after>( function( mw, $ ) {"use strict";

	// Todo: support "visible" attribute to show/hide button on player state change
	mw.PluginManager.add( 'largePlayBtn', mw.KBaseComponent.extend({
		defaultConfig: {
			'parent': 'videoHolder',
			'order': 1
		},
		isSafeEnviornment: function(){
			return !(mw.getConfig( 'EmbedPlayer.WebKitPlaysInline') && mw.isIphone());
		},
		setup: function() {
			this.addBindings();
		},
		/**
		 * Checks if the play button should stay on screen during playback,
		 * cases where a native player is dipalyed such as iPhone.
		 */
		isPersistantPlayBtn: function(){
			return mw.isAndroid2() || this.getPlayer().isLinkPlayer ||
					( mw.isIphone() && mw.getConfig( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' ) );
		},
		/**
		 * Checks if a large play button should be displayed on the
		 * otherwise native player
		 */
		useLargePlayBtn: function(){
			if( this.isPersistantPlayBtn() ){
				return true;
			}
			// If we are using native controls return false:
			return !this.getPlayer().useNativePlayerControls();
		},
		addBindings: function() {
			var _this = this;
			this.bind('showInlineDownloadLink', function(e, linkUrl){
				_this.getComponent().attr({
					'href': linkUrl,
					'target': '_blank'
				});
			});
			this.bind('onChangeMediaDone', function(){
				_this.showButton();
			});
			this.bind('playerReady', function(){
				_this.showButton();
			});
			this.bind('playing', function(){
				_this.hideButton();
			});
			this.bind('onpause', function(){
				_this.showButton();
			});
			this.bind('onEndedDone', function(){
				_this.showButton();
			});
		},
		showButton: function(){
			if( this.useLargePlayBtn() ) {
				this.getComponent().show();
			}
		},
		hideButton: function(){
			if( !this.isPersistantPlayBtn() ) {
				this.getComponent().hide();
			}
		},
		clickButton: function( event ){
			if( this.getPlayer().isLinkPlayer ) {
				this.getPlayer().triggerHelper( 'firstPlay' ); // To send stats event for play
				this.getPlayer().triggerHelper( 'playing' );
			} else {
				event.preventDefault();
				this.getPlayer().sendNotification( 'doPlay' );
			}
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				this.$el = $( '<a />' )
							.attr( {
								'href' : '#',
								'title' : gM( 'mwe-embedplayer-play_clip' ),
								'class'	: "large-play-btn icon-play-2"
							} )
							.hide()
							// Add play hook:
							.click( function(e) {
								_this.clickButton(e);
							} );
			}
			return this.$el;
		}
	})
	);

} )( window.mw, window.jQuery );<|endoftext|>


<commit_before>( function( mw, $ ) {"use strict";

	// Todo: support "visible" attribute to show/hide button on player state change
	mw.PluginManager.add( 'largePlayBtn', mw.KBaseComponent.extend({
		//indicates we were explicitly asked to show the button (will be used when re-enabling the button)
		shouldShow : false,
		isDisabled: false,
		defaultConfig: {
			'parent': 'videoHolder',
			'order': 1
		},
		isSafeEnviornment: function(){
			return !(mw.getConfig( 'EmbedPlayer.WebKitPlaysInline') && mw.isIphone());
		},
		setup: function() {
			this.addBindings();
		},
		/**
		 * Checks if the play button should stay on screen during playback,
		 * cases where a native player is dipalyed such as iPhone.
		 */
		isPersistantPlayBtn: function(){
			return mw.isAndroid2() || this.getPlayer().isLinkPlayer() ||
					( mw.isIphone() && mw.getConfig( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' ) );
		},
		/**
		 * Checks if a large play button should be displayed on the
		 * otherwise native player
		 */
		useLargePlayBtn: function(){
			if( this.isPersistantPlayBtn() ){
				return true;
			}
			// If we are using native controls return false:
			return !this.getPlayer().useNativePlayerControls();
		},
		addBindings: function() {
			var _this = this;
			this.bind('showInlineDownloadLink', function(e, linkUrl){
				_this.getComponent().attr({
					'href': linkUrl,
					'target': '_blank'
				});
			});
			this.bind('onChangeMediaDone playerReady onpause onEndedDone', function(){
				_this.showButton();
			});
			this.bind('playing AdSupport_StartAdPlayback', function(){
				_this.hideButton();
			});
			this.bind('onPlayerStateChange', function(e, newState, oldState){
				if( newState == 'load' ){
					_this.hideButton();
				}
				if( newState == 'pause' && _this.getPlayer().isPauseLoading ){
					_this.hideButton();
				}
			});
		},
		showButton: function(){
			if ( !this.isDisabled ) {
				this.showComponent();
			}
			this.shouldShow = true;
		},
		hideButton: function(){
			this.hideComponent();
			this.shouldShow = false;
		},
		hideComponent: function() {
			if( !this.isPersistantPlayBtn() ) {
				this.getComponent().hide();
			}
		},
		showComponent: function() {
			if( this.useLargePlayBtn() ) {
				this.getComponent().show();
			}
		},
		clickButton: function( event ){
			// If link player, only trigger events
			if( this.getPlayer().isLinkPlayer() ) {
				this.getPlayer().triggerHelper( 'firstPlay' ); // To send stats event for play
				this.getPlayer().triggerHelper( 'playing' );
				return;
			}

			event.preventDefault();
			this.getPlayer().sendNotification('doPlay');
		},
		onEnable: function(){
			this.isDisabled = false;
			if ( this.shouldShow ) {
				this.showComponent();
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.hideComponent();
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				this.$el = $( '<a />' )
							.attr( {
								'tabindex': '-1',
								'href' : '#',
								'title' : gM( 'mwe-embedplayer-play_clip' ),
								'class'	: "icon-play" + this.getCssClass()
							} )
							.hide()
							// Add play hook:
							.click( function(e) {
								_this.clickButton(e);
							} );
			}
			return this.$el;
		}
	})
	);

} )( window.mw, window.jQuery );<commit_msg>largePlayBtn code enhancements, support setAttribute visible<commit_after>( function( mw, $ ) {"use strict";
	mw.PluginManager.add( 'largePlayBtn', mw.KBaseComponent.extend({
		//indicates we were explicitly asked to show the button (will be used when re-enabling the button)
		shouldShow : false,
		isDisabled: false,
		defaultConfig: {
			'parent': 'videoHolder',
			'order': 1
		},
		isSafeEnviornment: function(){
			return ( !(mw.getConfig( 'EmbedPlayer.WebKitPlaysInline' ) && mw.isIphone() ) && this.useLargePlayBtn() );
		},
		setup: function() {
			this.addBindings();
		},
		/**
		 * Checks if the play button should stay on screen during playback,
		 * cases where a native player is dipalyed such as iPhone.
		 */
		isPersistantPlayBtn: function(){
			return mw.isAndroid2() || this.getPlayer().isLinkPlayer() ||
					( mw.isIphone() && mw.getConfig( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' ) );
		},
		/**
		 * Checks if a large play button should be displayed on the
		 * otherwise native player
		 */
		useLargePlayBtn: function(){
			if( this.isPersistantPlayBtn() ){
				return true;
			}
			// If we are using native controls return false:
			return !this.getPlayer().useNativePlayerControls();
		},
		addBindings: function() {
			var _this = this;
			this.bind('showInlineDownloadLink', function(e, linkUrl){
				_this.getComponent().attr({
					'href': linkUrl,
					'target': '_blank'
				});
			});
			this.bind('onChangeMediaDone playerReady onpause onEndedDone', function(){
				_this.show();
			});
			this.bind('playing AdSupport_StartAdPlayback', function(){
				_this.hide();
			});
			this.bind('onPlayerStateChange', function(e, newState, oldState){
				if( newState == 'load' ){
					_this.hide();
				}
				if( newState == 'pause' && _this.getPlayer().isPauseLoading ){
					_this.hide();
				}
			});
		},
		show: function(){
			if ( !this.isDisabled ) {
				this.getComponent().show();
			}
			this.shouldShow = true;
		},
		hide: function(){
			this.hideComponent();
			this.shouldShow = false;
		},
		hideComponent: function() {
			if( !this.isPersistantPlayBtn() ) {
				this.getComponent().hide();
			}
		},
		clickButton: function( event ){
			// If link player, only trigger events
			if( this.getPlayer().isLinkPlayer() ) {
				this.getPlayer().triggerHelper( 'firstPlay' ); // To send stats event for play
				this.getPlayer().triggerHelper( 'playing' );
				return;
			}

			event.preventDefault();
			this.getPlayer().sendNotification('doPlay');
		},
		onEnable: function(){
			this.isDisabled = false;
			if ( this.shouldShow ) {
				this.getComponent().show();
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.hideComponent();
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				this.$el = $( '<a />' )
							.attr( {
								'tabindex': '-1',
								'href' : '#',
								'title' : gM( 'mwe-embedplayer-play_clip' ),
								'class'	: "icon-play" + this.getCssClass()
							} )
							.hide()
							// Add play hook:
							.click( function(e) {
								_this.clickButton(e);
							} );
			}
			return this.$el;
		}
	})
	);

} )( window.mw, window.jQuery );<|endoftext|>


<commit_before>/**
 * Kaltura style analytics reporting class
 */
( function( mw, $ ) { "use strict";

// Avoid undefined symbol for javascript response "Kaltura" from the api
window['Kaltura'] = true;

// KAnalytics Constructor
mw.KAnalytics = function( embedPlayer ){
	this.init( embedPlayer );
};

// Add analytics to the embed player:
mw.addKAnalytics = function( embedPlayer ) {
	embedPlayer.kAnalytics = new mw.KAnalytics( embedPlayer );
}
mw.KAnalytics.prototype = {

	// Local reference to embedPlayer
	embedPlayer: null,

	// Report Set object
	reportSet : null,

	// Stores the last time we issued a seek event
	// avoids sending lots of seeks while scrubbing
	lastSeekEventTime: 0,

	bindPostFix: '.kAnalytics',

	// Start Time
	startReportTime: 0,

	//delay the stats call in x sec
	delay:0,

    histroyEvent : {},
    histroyEventCount:{},
	kEventTypes : {
		'WIDGET_LOADED' : 1,
		'MEDIA_LOADED' : 2,
		'PLAY' : 3,
		'PLAY_REACHED_25' : 4,
		'PLAY_REACHED_50' : 5,
		'PLAY_REACHED_75' : 6,
		'PLAY_REACHED_100' : 7,
		'OPEN_EDIT' : 8,
		'OPEN_VIRAL' : 9,
		'OPEN_DOWNLOAD' : 10,
		'OPEN_REPORT' : 11,
		'BUFFER_START' : 12,
		'BUFFER_END' : 13,
		'OPEN_FULL_SCREEN' : 14,
		'CLOSE_FULL_SCREEN' : 15,
		'REPLAY' : 16,
		'SEEK' : 17,
		'OPEN_UPLOAD' : 18,
		'SAVE_PUBLISH' : 19,
		'CLOSE_EDITOR' : 20,
		'PRE_BUMPER_PLAYED' : 21,
		'POST_BUMPER_PLAYED' : 22,
		'BUMPER_CLICKED' : 23,
		'FUTURE_USE_1' : 24,
		'FUTURE_USE_2' : 25,
		'FUTURE_USE_3' : 26
	},

	/**
	 * Constructor for kAnalytics
	 *
	 * @param {Object}
	 *		  embedPlayer Player to apply Kaltura analytics to.
	 * @parma {Object}
	 * 			kalturaClient Kaltura client object for the api session.
	 */
	init: function( embedPlayer ) {
		var _this = this;
		// set the version of html5 player
		this.version = mw.getConfig( 'version' );
        if (!mw.KAnalytics.totalEventCount)  {
            mw.KAnalytics.totalEventCount = 0;
        }
		// Setup the local reference to the embed player
		this.embedPlayer = embedPlayer;
		if( ! this.kClient ) {
			this.kClient = mw.kApiGetPartnerClient( embedPlayer.kwidgetid );
			this.delay = this.embedPlayer.getKalturaConfig( 'statistics' , 'delay' ) ? this.embedPlayer.getKalturaConfig( 'statistics' , 'delay' ) * 1000 : 0;
		}
		// Remove any old bindings:
		$( embedPlayer ).unbind( this.bindPostFix );

		$( embedPlayer ).bind( 'playerReady' + this.bindPostFix, function(){
			// Setup the initial state of some flags
			_this.resetPlayerflags();
		});

        $( embedPlayer ).bind( 'changeMedia' + this.bindPostFix, function() {
            // Setup the initial state of some flags
            _this.histroyEvent = {};
            _this.histroyEventCount = {};
        });

		// Add relevant hooks for reporting beacons
		this.bindPlayerEvents();
	},
	resetPlayerflags:function(){
		this._p25Once = false;
		this._p50Once = false;
		this._p75Once = false;
		this._p100Once = false;
		this.hasSeeked = false;
		this.lastSeek = 0;
    },
	/**
	 * Get the current report set
	 *
	 * @param {Number}
	 *			KalturaStatsEventType The eventType number.
	 */
	sendAnalyticsEvent: function( KalturaStatsEventKey ){
		var _this = this;
		mw.log("KAnalytics :: doSendAnalyticsEvent > " + KalturaStatsEventKey );
		// Kalutra analytics does not collect info for ads:
		if( this.embedPlayer.evaluate('{sequenceProxy.isInSequence}') ){
			return ;
		}

		// get the id for the given event:
		var eventKeyId = this.kEventTypes[ KalturaStatsEventKey ];
		// Generate the status event
		var eventSet = {
			'eventType'			: eventKeyId,
			'clientVer'			: this.version,
			'currentPoint'		: parseInt( this.embedPlayer.currentTime * 1000 ),
			'duration'			: this.embedPlayer.getDuration(),
			'eventTimestamp'	: new Date().getTime(),
			'isFirstInSession'	: 'false',
			'objectType'		: 'KalturaStatsEvent',
			'partnerId'			: this.embedPlayer.kpartnerid,
			'sessionId'			: this.embedPlayer.evaluate('{configProxy.sessionId}'),
			'uiconfId'			: 0
		};
		if( isNaN( eventSet.duration )  ){
			eventSet.duration = 0;
		}

		// Set the seek condition:
		eventSet[ 'seek' ] = ( this.hasSeeked ) ? 'true' : 'false';

		// Set the 'event:entryId'
		if( this.embedPlayer.kentryid ){
			eventSet[ 'entryId' ] = this.embedPlayer.kentryid;
		} else {
			// if kentryid is not set, use the selected source url
			eventSet[ 'entryId' ] = this.embedPlayer.getSrc();
		}

        if (this.histroyEvent[eventSet[ 'entryId' ]]   == null)
        {
            this.histroyEvent[eventSet[ 'entryId' ]] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
        }

        if (this.histroyEventCount[eventSet[ 'entryId' ]]   == null)
        {
            this.histroyEventCount[eventSet[ 'entryId' ]] = 0;
        }
        this.histroyEvent[eventSet[ 'entryId' ]][eventKeyId - 1] = 1;
        this.histroyEventCount[eventSet[ 'entryId' ]]++;
        mw.KAnalytics.totalEventCount++;

        eventSet[ 'historyEvents' ] = this.histroyEvent[eventSet[ 'entryId' ]].join('') + '-' + this.histroyEventCount[eventSet[ 'entryId' ]] + '-' + mw.KAnalytics.totalEventCount ;
        // Set the 'event:uiconfId'
		if( this.embedPlayer.kuiconfid ) {
			eventSet[ 'uiconfId' ] = this.embedPlayer.kuiconfid;
		}
		// Set the 'event:widgetId'
		if( this.embedPlayer.kwidgetid ) {
			eventSet[ 'widgetId' ] = this.embedPlayer.kwidgetid;
		}
		var flashVarEvents = {
				'playbackContext' : 'contextId',
				'originFeature' : 'featureType',
				'applicationName' : 'applicationId',
				'userId' : 'userId'
		}
		// support legacy ( deprecated ) top level config
		for( var fvKey in flashVarEvents){
			if( this.embedPlayer.getKalturaConfig( '', fvKey ) ){
				eventSet[ flashVarEvents[ fvKey ] ] = encodeURIComponent( this.embedPlayer.getKalturaConfig('', fvKey ) );
			}
		}
		// check for the vars in the correct location:
		for( var fvKey in flashVarEvents){
			if( this.embedPlayer.getKalturaConfig( 'statistics', fvKey ) ){
				eventSet[ flashVarEvents[ fvKey ] ] = encodeURIComponent( this.embedPlayer.getKalturaConfig('statistics', fvKey ) );
			}
		}
		// hideUserId will remove the userId from the analytics call EVEN if the embed code sends one (unless hashedUserId is in use)
		if(this.embedPlayer.getKalturaConfig( 'statistics' , 'hideUserId') && eventSet.userId){
			delete(eventSet.userId);
		}

		// Add referrer parameter
		var pageReferrer =  mw.getConfig('EmbedPlayer.IsFriendlyIframe') ? mw.getConfig('EmbedPlayer.IframeParentUrl') : document.referrer;
		eventSet[ 'referrer' ] = encodeURIComponent( pageReferrer );

		// Add in base service and action calls:
		var eventRequest = {'service' : 'stats', 'action' : 'collect'};
		// Add event parameters
		for( var i in eventSet){
			eventRequest[ 'event:' + i] = eventSet[i];
		}

		// Send events for this player:
		$( this.embedPlayer ).trigger( 'KalturaSendAnalyticEvent', [ KalturaStatsEventKey, eventSet ] );

		// check for defined callback:
		var parentTrackName = this.embedPlayer.getKalturaConfig( 'statistics', 'trackEventMonitor');
		if(  mw.getConfig('EmbedPlayer.IsFriendlyIframe') ){
			try {
				if( window.parent[ parentTrackName ] ){
					 window.parent[ parentTrackName ]( KalturaStatsEventKey, eventSet );
				}
			} catch( e ){
				// error in calling parent page event
			}
		}
		//hideKS is an attribute that will prevent the request from sending the KS even if the embed code receives one
		if (this.embedPlayer.getFlashvars('ks') && !this.embedPlayer.getKalturaConfig( 'statistics' , 'hideKs') ){
			eventRequest['ks'] = this.embedPlayer.getFlashvars('ks');
		}

		// Do the api request:
		if (this.delay) {
			setTimeout( function () {
				_this.kClient.doRequest( eventRequest , null , true );
			} , this.delay );
		} else {
			this.kClient.doRequest( eventRequest , null , true );
		}
	},

	/**
	 * Binds player events for analytics reporting
	 */
	bindPlayerEvents: function(){

		// Setup local reference to embedPlayer
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Setup shortcut anonymous function for player bindings
		var b = function( hookName, eventType ){
			$( _this.embedPlayer ).bind( hookName + _this.bindPostFix, function(){
				_this.sendAnalyticsEvent( eventType );
			});
		};

		// When the player is ready
		b( 'widgetLoaded', 'WIDGET_LOADED' );

		// When the poster or video ( when autoplay ) media is loaded
		b( 'KalturaSupport_EntryDataReady', 'MEDIA_LOADED' );

		// When the play button is pressed or called from javascript
		b( 'firstPlay', 'PLAY' );

		// When the show Share menu is displayed
		b( 'showShareEvent', 'OPEN_VIRAL' );

		// When the show download menu is displayed
		b( 'downloadMedia', 'OPEN_DOWNLOAD' );

		// When the clip starts to buffer ( not all player types )
		b( 'bufferStartEvent', 'BUFFER_START' );

		// When the clip is full buffered
		b( 'bufferEndEvent', 'BUFFER_END' );

		// When the fullscreen button is pressed
		// ( presently does not register iPhone / iPad until it has js bindings )
		b( 'onOpenFullScreen', 'OPEN_FULL_SCREEN' );

		// When the close fullscreen button is pressed.
		// ( presently does not register iphone / ipad until it has js bindings )
		b( 'onCloseFullScreen', 'CLOSE_FULL_SCREEN' );

		// When the user plays (after the ondone event was fired )
		b( 'replayEvent', 'REPLAY' );

		// Bind on the seek event
		$( embedPlayer ).bind( 'seeked' + this.bindPostFix, function( seekTarget ) {
			// Don't send a bunch of seeks on scrub:
			if( _this.lastSeekEventTime == 0 ||
				_this.lastSeekEventTime + 2000	< new Date().getTime() )
			{
				_this.sendAnalyticsEvent( 'SEEK' );
			}

			// Update the last seekTime
			_this.lastSeekEventTime =  new Date().getTime();

			// Then set local seek flags
			this.hasSeeked = true;
			this.lastSeek = seekTarget;
		} );

		// Let updateTimeStats handle the currentTime monitor timing

		$( embedPlayer ).bind( 'monitorEvent' + this.bindPostFix, function(){
			_this.updateTimeStats();
		});

		/*
		 * Other kaltura event types that are presently not usable in the
		 * html5 player at this point in time:
		 *
		 * OPEN_EDIT = 8;
		 * OPEN_REPORT = 11;
		 * OPEN_UPLOAD = 18;
		 * SAVE_PUBLISH = 19;
		 * CLOSE_EDITOR = 20;
		 *
		 * PRE_BUMPER_PLAYED = 21;
		 * POST_BUMPER_PLAYED = 22;
		 * BUMPER_CLICKED = 23;
		 *
		 * FUTURE_USE_1 = 24;
		 * FUTURE_USE_2 = 25;
		 * FUTURE_USE_3 = 26;
		 */
	},

	/**
	 * Send updates for time stats
	 */
	updateTimeStats: function() {
		// Setup local references:
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Set the seek and time percent:
		var percent = embedPlayer.currentTime / embedPlayer.duration;
		var seekPercent = this.lastSeek/ embedPlayer.duration;

		// Send updates based on logic present in StatisticsMediator.as
		if ( !embedPlayer.isLive() ){
			if( !_this._p25Once && percent >= .25  &&  seekPercent <= .25 ) {

				_this._p25Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_25' );
				$( embedPlayer ).trigger( "firstQuartile" );

			} else if ( !_this._p50Once && percent >= .50 && seekPercent < .50 ) {

				_this._p50Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_50' );
				$( embedPlayer ).trigger( "secondQuartile" );

			} else if( !_this._p75Once && percent >= .75 && seekPercent < .75 ) {

				_this._p75Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_75' );
				$( embedPlayer ).trigger( "thirdQuartile" );

			} else if(  !_this._p100Once && percent >= .98 && seekPercent < 1) {

				_this._p100Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_100' );
			}
		}
	}
};

})( window.mw, window.jQuery );<commit_msg>feat: add hasKanalony param to stats event to signal kava (#3524)<commit_after>/**
 * Kaltura style analytics reporting class
 */
( function( mw, $ ) { "use strict";

// Avoid undefined symbol for javascript response "Kaltura" from the api
window['Kaltura'] = true;

// KAnalytics Constructor
mw.KAnalytics = function( embedPlayer ){
	this.init( embedPlayer );
};

// Add analytics to the embed player:
mw.addKAnalytics = function( embedPlayer ) {
	embedPlayer.kAnalytics = new mw.KAnalytics( embedPlayer );
}
mw.KAnalytics.prototype = {

	// Local reference to embedPlayer
	embedPlayer: null,

	// Report Set object
	reportSet : null,

	// Stores the last time we issued a seek event
	// avoids sending lots of seeks while scrubbing
	lastSeekEventTime: 0,

	bindPostFix: '.kAnalytics',

	// Start Time
	startReportTime: 0,

	//delay the stats call in x sec
	delay:0,

    histroyEvent : {},
    histroyEventCount:{},
	kEventTypes : {
		'WIDGET_LOADED' : 1,
		'MEDIA_LOADED' : 2,
		'PLAY' : 3,
		'PLAY_REACHED_25' : 4,
		'PLAY_REACHED_50' : 5,
		'PLAY_REACHED_75' : 6,
		'PLAY_REACHED_100' : 7,
		'OPEN_EDIT' : 8,
		'OPEN_VIRAL' : 9,
		'OPEN_DOWNLOAD' : 10,
		'OPEN_REPORT' : 11,
		'BUFFER_START' : 12,
		'BUFFER_END' : 13,
		'OPEN_FULL_SCREEN' : 14,
		'CLOSE_FULL_SCREEN' : 15,
		'REPLAY' : 16,
		'SEEK' : 17,
		'OPEN_UPLOAD' : 18,
		'SAVE_PUBLISH' : 19,
		'CLOSE_EDITOR' : 20,
		'PRE_BUMPER_PLAYED' : 21,
		'POST_BUMPER_PLAYED' : 22,
		'BUMPER_CLICKED' : 23,
		'FUTURE_USE_1' : 24,
		'FUTURE_USE_2' : 25,
		'FUTURE_USE_3' : 26
	},

	/**
	 * Constructor for kAnalytics
	 *
	 * @param {Object}
	 *		  embedPlayer Player to apply Kaltura analytics to.
	 * @parma {Object}
	 * 			kalturaClient Kaltura client object for the api session.
	 */
	init: function( embedPlayer ) {
		var _this = this;
		// set the version of html5 player
		this.version = mw.getConfig( 'version' );
        if (!mw.KAnalytics.totalEventCount)  {
            mw.KAnalytics.totalEventCount = 0;
        }
		// Setup the local reference to the embed player
		this.embedPlayer = embedPlayer;
		if( ! this.kClient ) {
			this.kClient = mw.kApiGetPartnerClient( embedPlayer.kwidgetid );
			this.delay = this.embedPlayer.getKalturaConfig( 'statistics' , 'delay' ) ? this.embedPlayer.getKalturaConfig( 'statistics' , 'delay' ) * 1000 : 0;
		}
		// Remove any old bindings:
		$( embedPlayer ).unbind( this.bindPostFix );

		$( embedPlayer ).bind( 'playerReady' + this.bindPostFix, function(){
			// Setup the initial state of some flags
			_this.resetPlayerflags();
		});

        $( embedPlayer ).bind( 'changeMedia' + this.bindPostFix, function() {
            // Setup the initial state of some flags
            _this.histroyEvent = {};
            _this.histroyEventCount = {};
        });

		// Add relevant hooks for reporting beacons
		this.bindPlayerEvents();
	},
	resetPlayerflags:function(){
		this._p25Once = false;
		this._p50Once = false;
		this._p75Once = false;
		this._p100Once = false;
		this.hasSeeked = false;
		this.lastSeek = 0;
    },
	/**
	 * Get the current report set
	 *
	 * @param {Number}
	 *			KalturaStatsEventType The eventType number.
	 */
	sendAnalyticsEvent: function( KalturaStatsEventKey ){
		var _this = this;
		mw.log("KAnalytics :: doSendAnalyticsEvent > " + KalturaStatsEventKey );
		// Kalutra analytics does not collect info for ads:
		if( this.embedPlayer.evaluate('{sequenceProxy.isInSequence}') ){
			return ;
		}

		// get the id for the given event:
		var eventKeyId = this.kEventTypes[ KalturaStatsEventKey ];
		// Generate the status event
		var eventSet = {
			'eventType'			: eventKeyId,
			'clientVer'			: this.version,
			'currentPoint'		: parseInt( this.embedPlayer.currentTime * 1000 ),
			'duration'			: this.embedPlayer.getDuration(),
			'eventTimestamp'	: new Date().getTime(),
			'isFirstInSession'	: 'false',
			'objectType'		: 'KalturaStatsEvent',
			'partnerId'			: this.embedPlayer.kpartnerid,
			'sessionId'			: this.embedPlayer.evaluate('{configProxy.sessionId}'),
			'uiconfId'			: 0
		};
		if( isNaN( eventSet.duration )  ){
			eventSet.duration = 0;
		}

		// Set the seek condition:
		eventSet[ 'seek' ] = ( this.hasSeeked ) ? 'true' : 'false';

		// Set the 'event:entryId'
		if( this.embedPlayer.kentryid ){
			eventSet[ 'entryId' ] = this.embedPlayer.kentryid;
		} else {
			// if kentryid is not set, use the selected source url
			eventSet[ 'entryId' ] = this.embedPlayer.getSrc();
		}

        if (this.histroyEvent[eventSet[ 'entryId' ]]   == null)
        {
            this.histroyEvent[eventSet[ 'entryId' ]] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
        }

        if (this.histroyEventCount[eventSet[ 'entryId' ]]   == null)
        {
            this.histroyEventCount[eventSet[ 'entryId' ]] = 0;
        }
        this.histroyEvent[eventSet[ 'entryId' ]][eventKeyId - 1] = 1;
        this.histroyEventCount[eventSet[ 'entryId' ]]++;
        mw.KAnalytics.totalEventCount++;

        eventSet[ 'historyEvents' ] = this.histroyEvent[eventSet[ 'entryId' ]].join('') + '-' + this.histroyEventCount[eventSet[ 'entryId' ]] + '-' + mw.KAnalytics.totalEventCount ;
        // Set the 'event:uiconfId'
		if( this.embedPlayer.kuiconfid ) {
			eventSet[ 'uiconfId' ] = this.embedPlayer.kuiconfid;
		}
		// Set the 'event:widgetId'
		if( this.embedPlayer.kwidgetid ) {
			eventSet[ 'widgetId' ] = this.embedPlayer.kwidgetid;
		}
		var flashVarEvents = {
				'playbackContext' : 'contextId',
				'originFeature' : 'featureType',
				'applicationName' : 'applicationId',
				'userId' : 'userId'
		}
		// support legacy ( deprecated ) top level config
		for( var fvKey in flashVarEvents){
			if( this.embedPlayer.getKalturaConfig( '', fvKey ) ){
				eventSet[ flashVarEvents[ fvKey ] ] = encodeURIComponent( this.embedPlayer.getKalturaConfig('', fvKey ) );
			}
		}
		// check for the vars in the correct location:
		for( var fvKey in flashVarEvents){
			if( this.embedPlayer.getKalturaConfig( 'statistics', fvKey ) ){
				eventSet[ flashVarEvents[ fvKey ] ] = encodeURIComponent( this.embedPlayer.getKalturaConfig('statistics', fvKey ) );
			}
		}
		// hideUserId will remove the userId from the analytics call EVEN if the embed code sends one (unless hashedUserId is in use)
		if(this.embedPlayer.getKalturaConfig( 'statistics' , 'hideUserId') && eventSet.userId){
			delete(eventSet.userId);
		}

		var kanalonyConfig = this.embedPlayer.getKalturaConfig( 'kAnalony' );
		if (kanalonyConfig && kanalonyConfig.plugin ){
			eventSet[ 'hasKanalony' ] = true;
		}
		// Add referrer parameter
		var pageReferrer =  mw.getConfig('EmbedPlayer.IsFriendlyIframe') ? mw.getConfig('EmbedPlayer.IframeParentUrl') : document.referrer;
		eventSet[ 'referrer' ] = encodeURIComponent( pageReferrer );

		// Add in base service and action calls:
		var eventRequest = {'service' : 'stats', 'action' : 'collect'};
		// Add event parameters
		for( var i in eventSet){
			eventRequest[ 'event:' + i] = eventSet[i];
		}

		// Send events for this player:
		$( this.embedPlayer ).trigger( 'KalturaSendAnalyticEvent', [ KalturaStatsEventKey, eventSet ] );

		// check for defined callback:
		var parentTrackName = this.embedPlayer.getKalturaConfig( 'statistics', 'trackEventMonitor');
		if(  mw.getConfig('EmbedPlayer.IsFriendlyIframe') ){
			try {
				if( window.parent[ parentTrackName ] ){
					 window.parent[ parentTrackName ]( KalturaStatsEventKey, eventSet );
				}
			} catch( e ){
				// error in calling parent page event
			}
		}
		//hideKS is an attribute that will prevent the request from sending the KS even if the embed code receives one
		if (this.embedPlayer.getFlashvars('ks') && !this.embedPlayer.getKalturaConfig( 'statistics' , 'hideKs') ){
			eventRequest['ks'] = this.embedPlayer.getFlashvars('ks');
		}

		// Do the api request:
		if (this.delay) {
			setTimeout( function () {
				_this.kClient.doRequest( eventRequest , null , true );
			} , this.delay );
		} else {
			this.kClient.doRequest( eventRequest , null , true );
		}
	},

	/**
	 * Binds player events for analytics reporting
	 */
	bindPlayerEvents: function(){

		// Setup local reference to embedPlayer
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Setup shortcut anonymous function for player bindings
		var b = function( hookName, eventType ){
			$( _this.embedPlayer ).bind( hookName + _this.bindPostFix, function(){
				_this.sendAnalyticsEvent( eventType );
			});
		};

		// When the player is ready
		b( 'widgetLoaded', 'WIDGET_LOADED' );

		// When the poster or video ( when autoplay ) media is loaded
		b( 'KalturaSupport_EntryDataReady', 'MEDIA_LOADED' );

		// When the play button is pressed or called from javascript
		b( 'firstPlay', 'PLAY' );

		// When the show Share menu is displayed
		b( 'showShareEvent', 'OPEN_VIRAL' );

		// When the show download menu is displayed
		b( 'downloadMedia', 'OPEN_DOWNLOAD' );

		// When the clip starts to buffer ( not all player types )
		b( 'bufferStartEvent', 'BUFFER_START' );

		// When the clip is full buffered
		b( 'bufferEndEvent', 'BUFFER_END' );

		// When the fullscreen button is pressed
		// ( presently does not register iPhone / iPad until it has js bindings )
		b( 'onOpenFullScreen', 'OPEN_FULL_SCREEN' );

		// When the close fullscreen button is pressed.
		// ( presently does not register iphone / ipad until it has js bindings )
		b( 'onCloseFullScreen', 'CLOSE_FULL_SCREEN' );

		// When the user plays (after the ondone event was fired )
		b( 'replayEvent', 'REPLAY' );

		// Bind on the seek event
		$( embedPlayer ).bind( 'seeked' + this.bindPostFix, function( seekTarget ) {
			// Don't send a bunch of seeks on scrub:
			if( _this.lastSeekEventTime == 0 ||
				_this.lastSeekEventTime + 2000	< new Date().getTime() )
			{
				_this.sendAnalyticsEvent( 'SEEK' );
			}

			// Update the last seekTime
			_this.lastSeekEventTime =  new Date().getTime();

			// Then set local seek flags
			this.hasSeeked = true;
			this.lastSeek = seekTarget;
		} );

		// Let updateTimeStats handle the currentTime monitor timing

		$( embedPlayer ).bind( 'monitorEvent' + this.bindPostFix, function(){
			_this.updateTimeStats();
		});

		/*
		 * Other kaltura event types that are presently not usable in the
		 * html5 player at this point in time:
		 *
		 * OPEN_EDIT = 8;
		 * OPEN_REPORT = 11;
		 * OPEN_UPLOAD = 18;
		 * SAVE_PUBLISH = 19;
		 * CLOSE_EDITOR = 20;
		 *
		 * PRE_BUMPER_PLAYED = 21;
		 * POST_BUMPER_PLAYED = 22;
		 * BUMPER_CLICKED = 23;
		 *
		 * FUTURE_USE_1 = 24;
		 * FUTURE_USE_2 = 25;
		 * FUTURE_USE_3 = 26;
		 */
	},

	/**
	 * Send updates for time stats
	 */
	updateTimeStats: function() {
		// Setup local references:
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Set the seek and time percent:
		var percent = embedPlayer.currentTime / embedPlayer.duration;
		var seekPercent = this.lastSeek/ embedPlayer.duration;

		// Send updates based on logic present in StatisticsMediator.as
		if ( !embedPlayer.isLive() ){
			if( !_this._p25Once && percent >= .25  &&  seekPercent <= .25 ) {

				_this._p25Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_25' );
				$( embedPlayer ).trigger( "firstQuartile" );

			} else if ( !_this._p50Once && percent >= .50 && seekPercent < .50 ) {

				_this._p50Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_50' );
				$( embedPlayer ).trigger( "secondQuartile" );

			} else if( !_this._p75Once && percent >= .75 && seekPercent < .75 ) {

				_this._p75Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_75' );
				$( embedPlayer ).trigger( "thirdQuartile" );

			} else if(  !_this._p100Once && percent >= .98 && seekPercent < 1) {

				_this._p100Once = true;
				_this.sendAnalyticsEvent( 'PLAY_REACHED_100' );
			}
		}
	}
};

})( window.mw, window.jQuery );<|endoftext|>