<commit_before>'use strict';

// Helper methods needed by multiple controllers.

var Rx = require('../rx');
var xenaQuery = require('../xenaQuery');
var _ = require('../underscore_ext');
var {reifyErrors, collectResults} = require('./errors');
var fetch = require('../fieldFetch');
var {getColSpec} = require('../models/datasetJoins');
var {signatureField} = require('../models/fieldSpec');
var {publicServers} = require('../defaultServers');
// pick up signature fetch
require('../models/signatures');

var datasetResults = resps => collectResults(resps, servers =>
		_.object(_.flatmap(servers, s => _.map(s.datasets, d => [d.dsID, d]))));

function datasetQuery(servers, cohort) {
	var cohorts = _.pluck(cohort, 'name');
	return Rx.Observable.zipArray(
		_.map(servers, server => reifyErrors(
				xenaQuery.datasetList(server, cohorts).map(datasets => ({server, datasets})),
				{host: server}))
	).flatMap(datasetResults);
}

function fetchDatasets(serverBus, servers, cohort) {
	serverBus.next(['datasets', datasetQuery(servers, cohort)]);
}

// Might want to bump this up after fixing our rendering problems @ 40k.
const MAX_SAMPLES = 30 * 1000;

var allSamples = _.curry((cohort, max, server) => xenaQuery.cohortSamples(server, cohort, max === Infinity ? null : max));

function unionOfGroup(gb) {
	return _.union(..._.map(gb, ([, v]) => v));
}

// Performance of this is probably poor, esp. due to underscore's horrible
// n^2 set operations.
function cohortHasPrivateSamples(cohortResps) {
	var {'true': pub, 'false': priv} = _.groupBy(cohortResps, ([,,, server]) => _.contains(publicServers, server)),
		pubSamps = unionOfGroup(pub),
		privSamps = unionOfGroup(priv);
	return _.difference(privSamps, pubSamps).length > 0;
}

function filterSamples(sampleFilter, samples) {
	return sampleFilter ? _.intersection(sampleFilter, samples) : samples;
}

// For the cohort, query all servers,
// return a stream per-cohort, each of which returns an event
// [cohort, [sample, ...]].
// By not combining them here, we can uniformly handle errors, below.
var cohortSamplesQuery = _.curry(
	(servers, max, {name, sampleFilter}, i) =>
		_.map(servers, allSamples(name, max))
			.map((resp, j) => resp.map(samples => [i, filterSamples(sampleFilter, samples), samples.length >= max, servers[j]])));

// XXX The use of 'i' here looks wrong: it should be the cohort index, to line up with 'cohorts',
// but collectResults may have dropped a response due to ajax error, shifting the indexes of cohorts
// after the error.
// XXX Regarding MAX_SAMPLES, this query operates like this: for each cohort, for each server, fetch
// the sample list, and collate the results. To enforce MAX_SAMPLES and avoid hammering the server we
// should 1) limit each (cohort, server) request to MAX_SAMPLES, 2) limit the union per-cohort to MAX_SAMPLES,
// 3) limit the combined (all cohort) list to MAX_SAMPLES. The latter is harder to do because we can't
// just slice the list of lists. Currently we only enforce 1 & 2.
var collateSamplesByCohort = _.curry((cohorts, max, resps) => {
	var byCohort = _.groupBy(resps, _.first),
		serverOver = _.any(resps, ([,, over]) => over),
		cohortSamples = _.map(cohorts, (c, i) => unionOfGroup(byCohort[i] || []).slice(0, max)),
		cohortOver = _.any(cohortSamples, samples => samples.length >= max),
		hasPrivateSamples = _.any(byCohort, cohortHasPrivateSamples);
	return {samples: cohortSamples, over: serverOver || cohortOver, hasPrivateSamples};
});

// reifyErrors should be pass the server name, but in this expression we don't have it.
function samplesQuery(servers, cohort, max) {
	return Rx.Observable.zipArray(_.flatmap(cohort, cohortSamplesQuery(servers, max)).map(reifyErrors))
		.flatMap(resps => collectResults(resps, collateSamplesByCohort(cohort, max)));
}

// query samples if non-empty cohorts
var neSamplesQuery = (servers, cohort, max) =>
	cohort.length > 0 ? samplesQuery(servers, cohort, max) : Rx.Observable.of({samples: [], over: false}, Rx.Scheduler.asap);

function fetchSamples(serverBus, servers, cohort, allowOverSamples) {
	serverBus.next(['samples', neSamplesQuery(servers, cohort, allowOverSamples ? Infinity : MAX_SAMPLES)]);
}

function fetchColumnData(serverBus, samples, id, settings) {

	// XXX  Note that the widget-data-xxx slots are leaked in the groupBy
	// in main.js. We need a better mechanism.
//	if (Math.random() > 0.5) { // testing error handling
		serverBus.next([['widget-data', id], fetch(settings, samples)]);
//	} else {
//		serverBus.onNext([['widget-data', id], Rx.Observable.throw(new Error('Injected error'))]);
//	}
}

function resetZoom(state) {
	let count = _.getIn(state, ['cohortSamples', 0, 'length'], 0);
	return _.updateIn(state, ["zoom"],
					 z => _.merge(z, {count: count, index: 0}));
}

var setCohortRelatedFields = (state, cohort) =>
	_.assoc(state,
		'cohort', cohort,
		'hasPrivateSamples', false,
		'cohortSamples', [],
		'columns', {},
		'columnOrder', [],
		'data', {},
		'survival', null,
		'km', _.assoc(state.km, ['id'], null));

// This adds or overwrites a 'sample' column in the state.
// Called from setCohort, the column data will be fetched after
// the sample list returns from the server.
function addSampleColumn(state, width) {
	if (state.cohort.length === 0) {
		return state;
	}
	var field = signatureField('samples', {
			columnLabel: 'Sample ID',
			valueType: 'coded',
			signature: ['samples']
		}),
		newOrder = _.has(state.columns, 'samples') ? state.columnOrder : [...state.columnOrder, 'samples'],
		colSpec = getColSpec([field], {}),
		settings = _.assoc(colSpec,
				'width', Math.round(width == null ? 136 : width),
				'user', _.pick(colSpec, ['columnLabel', 'fieldLabel'])),
		newState = _.assocIn(state,
			['columns', 'samples'], settings,
			['columnOrder'], newOrder);
	return _.assocIn(newState, ['data', 'samples', 'status'], 'loading');
}

var setWizardAndMode = state =>
	_.assocIn(state,
			['wizardMode'], true,
			['mode'], 'heatmap');

var setCohort = _.curry((cohort, width, state) =>
		addSampleColumn(
			setWizardAndMode(
				resetZoom(
					setCohortRelatedFields(state, cohort))),
			width));

var userServers = state => _.keys(state.servers).filter(h => state.servers[h].user);

var fetchCohortData = (serverBus, state) => {
	let user = userServers(state);
	if (state.cohort) {
		fetchDatasets(serverBus, user, state.cohort);
		fetchSamples(serverBus, user, state.cohort, state.allowOverSamples);
	}
};

var unionOfResults = resps => collectResults(resps, results => _.union(...results));

function cohortQuery(servers) {
	return Rx.Observable.zipArray(_.map(servers, s => reifyErrors(xenaQuery.allCohorts(s), {host: s})))
			.flatMap(unionOfResults);
}

function fetchCohorts(serverBus, state, newState, {force} = {}) {
	var user = userServers(state),
		newUser = userServers(newState);
	if (force || !_.listSetsEqual(user, newUser)) {
		serverBus.next(['cohorts', cohortQuery(newUser)]);
	}
}

function updateWizard(serverBus, state, newState, opts) {
	fetchCohorts(serverBus, state, newState, opts);
	let user = userServers(state);
	// If there's a bookmark on wizard mode step 2, will we fail
	// to load the dataset?
	if (newState.cohort && newState.cohort !== state.cohort) {
		fetchDatasets(serverBus, user, newState.cohort);
	}
}

var clearWizardCohort = state =>
	_.assocIn(state, ['wizard', 'datasets'], undefined,
					 ['wizard', 'features'], undefined);

module.exports = {
	fetchCohortData,
	fetchCohorts,
	fetchColumnData,
	fetchDatasets,
	fetchSamples,
	resetZoom,
	setCohort,
	userServers,
	updateWizard,
	clearWizardCohort,
	datasetQuery
};
<commit_msg>increase max sample number from 30K to 50K<commit_after>'use strict';

// Helper methods needed by multiple controllers.

var Rx = require('../rx');
var xenaQuery = require('../xenaQuery');
var _ = require('../underscore_ext');
var {reifyErrors, collectResults} = require('./errors');
var fetch = require('../fieldFetch');
var {getColSpec} = require('../models/datasetJoins');
var {signatureField} = require('../models/fieldSpec');
var {publicServers} = require('../defaultServers');
// pick up signature fetch
require('../models/signatures');

var datasetResults = resps => collectResults(resps, servers =>
		_.object(_.flatmap(servers, s => _.map(s.datasets, d => [d.dsID, d]))));

function datasetQuery(servers, cohort) {
	var cohorts = _.pluck(cohort, 'name');
	return Rx.Observable.zipArray(
		_.map(servers, server => reifyErrors(
				xenaQuery.datasetList(server, cohorts).map(datasets => ({server, datasets})),
				{host: server}))
	).flatMap(datasetResults);
}

function fetchDatasets(serverBus, servers, cohort) {
	serverBus.next(['datasets', datasetQuery(servers, cohort)]);
}

const MAX_SAMPLES = 50 * 1000;

var allSamples = _.curry((cohort, max, server) => xenaQuery.cohortSamples(server, cohort, max === Infinity ? null : max));

function unionOfGroup(gb) {
	return _.union(..._.map(gb, ([, v]) => v));
}

// Performance of this is probably poor, esp. due to underscore's horrible
// n^2 set operations.
function cohortHasPrivateSamples(cohortResps) {
	var {'true': pub, 'false': priv} = _.groupBy(cohortResps, ([,,, server]) => _.contains(publicServers, server)),
		pubSamps = unionOfGroup(pub),
		privSamps = unionOfGroup(priv);
	return _.difference(privSamps, pubSamps).length > 0;
}

function filterSamples(sampleFilter, samples) {
	return sampleFilter ? _.intersection(sampleFilter, samples) : samples;
}

// For the cohort, query all servers,
// return a stream per-cohort, each of which returns an event
// [cohort, [sample, ...]].
// By not combining them here, we can uniformly handle errors, below.
var cohortSamplesQuery = _.curry(
	(servers, max, {name, sampleFilter}, i) =>
		_.map(servers, allSamples(name, max))
			.map((resp, j) => resp.map(samples => [i, filterSamples(sampleFilter, samples), samples.length >= max, servers[j]])));

// XXX The use of 'i' here looks wrong: it should be the cohort index, to line up with 'cohorts',
// but collectResults may have dropped a response due to ajax error, shifting the indexes of cohorts
// after the error.
// XXX Regarding MAX_SAMPLES, this query operates like this: for each cohort, for each server, fetch
// the sample list, and collate the results. To enforce MAX_SAMPLES and avoid hammering the server we
// should 1) limit each (cohort, server) request to MAX_SAMPLES, 2) limit the union per-cohort to MAX_SAMPLES,
// 3) limit the combined (all cohort) list to MAX_SAMPLES. The latter is harder to do because we can't
// just slice the list of lists. Currently we only enforce 1 & 2.
var collateSamplesByCohort = _.curry((cohorts, max, resps) => {
	var byCohort = _.groupBy(resps, _.first),
		serverOver = _.any(resps, ([,, over]) => over),
		cohortSamples = _.map(cohorts, (c, i) => unionOfGroup(byCohort[i] || []).slice(0, max)),
		cohortOver = _.any(cohortSamples, samples => samples.length >= max),
		hasPrivateSamples = _.any(byCohort, cohortHasPrivateSamples);
	return {samples: cohortSamples, over: serverOver || cohortOver, hasPrivateSamples};
});

// reifyErrors should be pass the server name, but in this expression we don't have it.
function samplesQuery(servers, cohort, max) {
	return Rx.Observable.zipArray(_.flatmap(cohort, cohortSamplesQuery(servers, max)).map(reifyErrors))
		.flatMap(resps => collectResults(resps, collateSamplesByCohort(cohort, max)));
}

// query samples if non-empty cohorts
var neSamplesQuery = (servers, cohort, max) =>
	cohort.length > 0 ? samplesQuery(servers, cohort, max) : Rx.Observable.of({samples: [], over: false}, Rx.Scheduler.asap);

function fetchSamples(serverBus, servers, cohort, allowOverSamples) {
	serverBus.next(['samples', neSamplesQuery(servers, cohort, allowOverSamples ? Infinity : MAX_SAMPLES)]);
}

function fetchColumnData(serverBus, samples, id, settings) {

	// XXX  Note that the widget-data-xxx slots are leaked in the groupBy
	// in main.js. We need a better mechanism.
//	if (Math.random() > 0.5) { // testing error handling
		serverBus.next([['widget-data', id], fetch(settings, samples)]);
//	} else {
//		serverBus.onNext([['widget-data', id], Rx.Observable.throw(new Error('Injected error'))]);
//	}
}

function resetZoom(state) {
	let count = _.getIn(state, ['cohortSamples', 0, 'length'], 0);
	return _.updateIn(state, ["zoom"],
					 z => _.merge(z, {count: count, index: 0}));
}

var setCohortRelatedFields = (state, cohort) =>
	_.assoc(state,
		'cohort', cohort,
		'hasPrivateSamples', false,
		'cohortSamples', [],
		'columns', {},
		'columnOrder', [],
		'data', {},
		'survival', null,
		'km', _.assoc(state.km, ['id'], null));

// This adds or overwrites a 'sample' column in the state.
// Called from setCohort, the column data will be fetched after
// the sample list returns from the server.
function addSampleColumn(state, width) {
	if (state.cohort.length === 0) {
		return state;
	}
	var field = signatureField('samples', {
			columnLabel: 'Sample ID',
			valueType: 'coded',
			signature: ['samples']
		}),
		newOrder = _.has(state.columns, 'samples') ? state.columnOrder : [...state.columnOrder, 'samples'],
		colSpec = getColSpec([field], {}),
		settings = _.assoc(colSpec,
				'width', Math.round(width == null ? 136 : width),
				'user', _.pick(colSpec, ['columnLabel', 'fieldLabel'])),
		newState = _.assocIn(state,
			['columns', 'samples'], settings,
			['columnOrder'], newOrder);
	return _.assocIn(newState, ['data', 'samples', 'status'], 'loading');
}

var setWizardAndMode = state =>
	_.assocIn(state,
			['wizardMode'], true,
			['mode'], 'heatmap');

var setCohort = _.curry((cohort, width, state) =>
		addSampleColumn(
			setWizardAndMode(
				resetZoom(
					setCohortRelatedFields(state, cohort))),
			width));

var userServers = state => _.keys(state.servers).filter(h => state.servers[h].user);

var fetchCohortData = (serverBus, state) => {
	let user = userServers(state);
	if (state.cohort) {
		fetchDatasets(serverBus, user, state.cohort);
		fetchSamples(serverBus, user, state.cohort, state.allowOverSamples);
	}
};

var unionOfResults = resps => collectResults(resps, results => _.union(...results));

function cohortQuery(servers) {
	return Rx.Observable.zipArray(_.map(servers, s => reifyErrors(xenaQuery.allCohorts(s), {host: s})))
			.flatMap(unionOfResults);
}

function fetchCohorts(serverBus, state, newState, {force} = {}) {
	var user = userServers(state),
		newUser = userServers(newState);
	if (force || !_.listSetsEqual(user, newUser)) {
		serverBus.next(['cohorts', cohortQuery(newUser)]);
	}
}

function updateWizard(serverBus, state, newState, opts) {
	fetchCohorts(serverBus, state, newState, opts);
	let user = userServers(state);
	// If there's a bookmark on wizard mode step 2, will we fail
	// to load the dataset?
	if (newState.cohort && newState.cohort !== state.cohort) {
		fetchDatasets(serverBus, user, newState.cohort);
	}
}

var clearWizardCohort = state =>
	_.assocIn(state, ['wizard', 'datasets'], undefined,
					 ['wizard', 'features'], undefined);

module.exports = {
	fetchCohortData,
	fetchCohorts,
	fetchColumnData,
	fetchDatasets,
	fetchSamples,
	resetZoom,
	setCohort,
	userServers,
	updateWizard,
	clearWizardCohort,
	datasetQuery
};
<|endoftext|>


<commit_before>/**
 * @module jquery
 */

modules.define('jquery', ['ua'], function(provide, ua, $) {

if(ua.ie) { // TODO: investigate for which version of IE we need this workaround
    var win = window,
        $win = $(window),
        winWidth = $win.width(),
        winHeight = $win.height();

    ($.event.special.resize || ($.event.special.resize = {})).preDispatch = function(e) {
        if(e.target === win) {
            var curWinWidth = $win.width(),
                curWinHeight = $win.height();

            if(curWinWidth === winWidth && curWinHeight === winHeight) {
                return false;
            } else {
                winWidth = curWinWidth;
                winHeight = curWinHeight;
            }
        }
    };
}

provide($);

});
<commit_msg>jquery__event_type_winresize: ie -> msie<commit_after>/**
 * @module jquery
 */

modules.define('jquery', ['ua'], function(provide, ua, $) {

// IE8 and below, https://msdn.microsoft.com/en-us/library/ie/ms536959%28v=vs.85%29.aspx
if(ua.msie && document.documentMode < 9) {
    var win = window,
        $win = $(window),
        winWidth = $win.width(),
        winHeight = $win.height();

    ($.event.special.resize || ($.event.special.resize = {})).preDispatch = function(e) {
        if(e.target === win) {
            var curWinWidth = $win.width(),
                curWinHeight = $win.height();

            if(curWinWidth === winWidth && curWinHeight === winHeight) {
                return false;
            } else {
                winWidth = curWinWidth;
                winHeight = curWinHeight;
            }
        }
    };
}

provide($);

});
<|endoftext|>


<commit_before>define(function (require) {
  var d3 = require("d3");
  var svgRect = require("src/modules/element/svg/rect");
  var canvasRect = require("src/modules/element/canvas/rect");
  var axis = require("src/modules/component/axis/axis");

  return function heatmap() {
    // Private variables
    var margin = { top: 20, right: 20, bottom: 20, left: 50 };
    var width = 960;
    var height = 500;
    var color = d3.scale.category10();

    var rect = {
      cssClass: "rect",
      canvas: false,
      x: function (d) { return d.x; },
      y: function (d) { return d.y; },
      fill: function (d) { return d.fill; },
      opacity: function (d) { return 1; },
      strokeWidth: 0,
      padding: 0.1
    };

    var axisX = {
      show: true,
      axisClass: "x axis",
      titleClass: "x-label",
      x: function () { return width / 2; },
      y: 30,
      dy: ".35em",
      textAnchor: "start",
      title: "",
      filterTicksBy: 1,
      tickRotate: 270
    };

    var axisY = {
      show: true,
      axisClass: "y axis",
      titleClass: "y-label",
      x: function () { return -height / 2; },
      y: -60,
      dy: ".35em",
      textAnchor: "start",
      title: "",
      filterTicksBy: 1
    };

    function chart(selection) {
      selection.each(function (data, index) {
        width = width - margin.left - margin.right;
        height = height - margin.top - margin.bottom;

        data.forEach(function (d, i) {
          d.x = rect.x.call(data, d, i);
          d.y = rect.y.call(data, d, i);
          d.fill = rect.fill.call(data, d, i);
          d.opacity = rect.opacity.call(data, d, i);
        });

        if (rect.canvas) {
          var padding = Object.keys(margin).map(function (key) {
            return margin[key];
          }).join("px ") + "px";

          var canvas = d3.select(this).append("canvas")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .style("padding", padding);
        }

        var svg = d3.select(this).append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)

        var g = svg.append("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var xScale = d3.scale.ordinal()
          .domain(getDomain(data, "x"))
          .rangeBands([0, width], rect.padding);

        var yScale = d3.scale.ordinal()
          .domain(getDomain(data, "y"))
          .rangeBands([height, 0], rect.padding);

        if (!rect.canvas) {
          var svgRects = svgRect()
            .cssClass(rect.cssClass)
            .x(function (d) { return xScale(d.x); })
            .y(function (d) { return yScale(d.y); })
            .width(xScale.rangeBand())
            .height(yScale.rangeBand())
            .fill(function (d) { return color(d.fill); })
            .stroke(function (d) { return color(d.fill); })
            .strokeWidth(rect.strokeWidth)
            .opacity(function (d) { return d.opacity; });

          g.datum(data).call(svgRects);
        } else {
          var canvasRects = canvasRect()
            .cssClass(rect.cssClass)
            .x(function (d) { return xScale(d.x); })
            .y(function (d) { return yScale(d.y); })
            .width(xScale.rangeBand())
            .height(yScale.rangeBand())
            .fillStyle(function (d) { return color(d.fill); })
            .opacity(function (d) { return d.opacity; })
            .strokeStyle(function (d) { return color(d.fill); })
            .lineWidth(rect.strokeWidth);

          canvas.datum(data).call(canvasRects);
        }

        if (axisX.show) {
          var xAxis = axis()
            .scale(xScale)
            .tickValues(
              xScale.domain()
                .filter(function (d, i) { return !(i % axisX.filterTicksBy); })
            )
            .gClass(axisX.axisClass)
            .transform("translate(0," + height + ")")
            .titleX(axisX.x)
            .titleY(axisY.y)
            .titleDY(axisX.dy)
            .titleAnchor(axisX.textAnchor)
            .title(axisX.title);

          g.call(xAxis);

          // Modifying the x axis tick labels
          g.selectAll(".x.axis .tick text")
            .attr("x", -10)
            .attr("y", -4)
            .attr("transform", "rotate(" + axisX.tickRotate + ")")
            .style("text-anchor", "end");
        }

        if (axisY.show) {
          var yAxis = axis()
            .scale(yScale)
            .tickValues(
              yScale.domain()
                .filter(function (d, i) { return !(i % axisY.filterTicksBy); })
            )
            .orient("left")
            .gClass(axisY.axisClass)
            .titleClass(axisY.titleClass)
            .titleX(axisY.x)
            .titleY(axisY.y)
            .titleDY(axisY.dy)
            .titleAnchor(axisY.textAnchor)
            .title(axisY.title);

          g.call(yAxis);
        }
      });
    }

    function getDomain(data, accessor) {
      return data
        .map(function (item) {
          return item[accessor];
        })
        .sort(function (prev, cur) {
          if (prev > cur) return 1;
          if (prev < cur) return -1;
          return 0;
        })
        .filter(function (item, index, array) {
          return array.indexOf(item) === index;
        });
    }

    // Public API
    chart.margin = function (_) {
      if (!arguments.length) { return margin; }
      margin.top = typeof _.top !== "undefined" ? _.top : margin.top;
      margin.right = typeof _.right !== "undefined" ? _.right : margin.right;
      margin.bottom = typeof _.bottom !== "undefined" ? _.bottom : margin.bottom;
      margin.left = typeof _.left !== "undefined" ? _.left : margin.left;
      return chart;
    };

    chart.width = function (_) {
      if (!arguments.length) return width;
      width = _;
      return chart;
    };

    chart.height = function (_) {
      if (!arguments.length) return height;
      height = _;
      return chart;
    };

    chart.color = function (_) {
      if (!arguments.length) return color;
      color = _;
      return chart;
    };

    chart.rect = function (_) {
      if (!arguments.length) { return rect; }
      rect.x = typeof _.x !== "undefined" ? _.x : rect.x;
      rect.y = typeof _.y !== "undefined" ? _.y : rect.y;
      rect.color = typeof _.color !== "undefined" ? _.color : rect.color;
      rect.cssClass = typeof _.cssClass !== "undefined" ? _.cssClass : rect.cssClass;
      rect.strokeWidth = typeof _.strokeWidth !== "undefined" ? _.strokeWidth : rect.strokeWidth;
      rect.fill = typeof _.fill !== "undefined" ? _.fill : rect.fill;
      rect.opacity = typeof _.opacity !== "undefined" ? _.opacity : rect.opacity;
      rect.padding = typeof _.padding !== "undefined" ? _.padding : rect.padding;
      rect.canvas = typeof _.canvas !== "undefined" ? _.canvas : rect.canvas;
      return chart;
    };

    chart.xAxis = function (_) {
      if (!arguments.length) { return axisX; }
      axisX.show = typeof _.show !== "undefined" ? _.show : axisX.show;
      axisX.axisClass = typeof _.axisClass !== "undefined" ? _.axisClass : axisX.axisClass;
      axisX.titleClass = typeof _.titleClass !== "undefined" ? _.titleClass : axisX.titleClass;
      axisX.x = typeof _.x !== "undefined" ? _.x : axisX.x;
      axisX.y = typeof _.y !== "undefined" ? _.y : axisX.y;
      axisX.dy = typeof _.dy !== "undefined" ? _.dy : axisX.dy;
      axisX.tickValues = typeof _.tickValues !== "undefined" ? _.tickValues: axisX.tickValues;
      axisX.textAnchor = typeof _.textAnchor !== "undefined" ? _.textAnchor : axisX.textAnchor;
      axisX.title = typeof _.title !== "undefined" ? _.title : axisX.title;
      axisX.filterTicksBy = typeof _.filterTicksBy !== "undefined" ? _.filterTicksBy : axisX.filterTicksBy;
      axisX.tickRotate = typeof _.tickRotate !== "undefined" ? _.tickRotate : axisX.tickRotate;
      return chart;
    };

    chart.yAxis = function (_) {
      if (!arguments.length) { return axisY; }
      axisY.show = typeof _.show !== "undefined" ? _.show : axisY.show;
      axisY.axisClass = typeof _.axisClass !== "undefined" ? _.axisClass : axisY.axisClass;
      axisY.titleClass = typeof _.titleClass !== "undefined" ? _.titleClass : axisY.titleClass;
      axisY.x = typeof _.x !== "undefined" ? _.x : axisY.x;
      axisY.y = typeof _.y !== "undefined" ? _.y : axisY.y;
      axisY.dy = typeof _.dy !== "undefined" ? _.dy : axisY.dy;
      axisY.tickValues = typeof _.tickValues !== "undefined" ? _.tickValues: axisY.tickValues;
      axisY.textAnchor = typeof _.textAnchor !== "undefined" ? _.textAnchor : axisY.textAnchor;
      axisY.title = typeof _.title !== "undefined" ? _.title : axisY.title;
      axisY.filterTicksBy = typeof _.filterTicksBy !== "undefined" ? _.filterTicksBy : axisY.filterTicksBy;
      return chart;
    };

    return chart;
  }
});
<commit_msg>changing canvas option<commit_after>define(function (require) {
  var d3 = require("d3");
  var svgRect = require("src/modules/element/svg/rect");
  var canvasRect = require("src/modules/element/canvas/rect");
  var axis = require("src/modules/component/axis/axis");

  return function heatmap() {
    // Private variables
    var margin = { top: 20, right: 20, bottom: 20, left: 50 };
    var width = 960;
    var height = 500;
    var color = d3.scale.category10();
    var isCanvas = false;

    var rect = {
      cssClass: "rect",
      x: function (d) { return d.x; },
      y: function (d) { return d.y; },
      fill: function (d) { return d.fill; },
      opacity: function (d) { return 1; },
      strokeWidth: 0,
      padding: 0.1
    };

    var axisX = {
      show: true,
      axisClass: "x axis",
      titleClass: "x-label",
      x: function () { return width / 2; },
      y: 30,
      dy: ".35em",
      textAnchor: "start",
      title: "",
      filterTicksBy: 1,
      tickRotate: 270
    };

    var axisY = {
      show: true,
      axisClass: "y axis",
      titleClass: "y-label",
      x: function () { return -height / 2; },
      y: -60,
      dy: ".35em",
      textAnchor: "start",
      title: "",
      filterTicksBy: 1
    };

    function chart(selection) {
      selection.each(function (data, index) {
        width = width - margin.left - margin.right;
        height = height - margin.top - margin.bottom;

        data.forEach(function (d, i) {
          d.x = rect.x.call(data, d, i);
          d.y = rect.y.call(data, d, i);
          d.fill = rect.fill.call(data, d, i);
          d.opacity = rect.opacity.call(data, d, i);
        });

        if (isCanvas) {
          var padding = Object.keys(margin).map(function (key) {
            return margin[key];
          }).join("px ") + "px";

          var canvas = d3.select(this).append("canvas")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .style("padding", padding);
        }

        var svg = d3.select(this).append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)

        var g = svg.append("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var xScale = d3.scale.ordinal()
          .domain(getDomain(data, "x"))
          .rangeBands([0, width], rect.padding);

        var yScale = d3.scale.ordinal()
          .domain(getDomain(data, "y"))
          .rangeBands([height, 0], rect.padding);

        if (isCanvas) {
          var canvasRects = canvasRect()
            .cssClass(rect.cssClass)
            .x(function (d) { return xScale(d.x); })
            .y(function (d) { return yScale(d.y); })
            .width(xScale.rangeBand())
            .height(yScale.rangeBand())
            .fillStyle(function (d) { return color(d.fill); })
            .opacity(function (d) { return d.opacity; })
            .strokeStyle(function (d) { return color(d.fill); })
            .lineWidth(rect.strokeWidth);

          canvas.datum(data).call(canvasRects);
        } else {
          var svgRects = svgRect()
            .cssClass(rect.cssClass)
            .x(function (d) { return xScale(d.x); })
            .y(function (d) { return yScale(d.y); })
            .width(xScale.rangeBand())
            .height(yScale.rangeBand())
            .fill(function (d) { return color(d.fill); })
            .stroke(function (d) { return color(d.fill); })
            .strokeWidth(rect.strokeWidth)
            .opacity(function (d) { return d.opacity; });

          g.datum(data).call(svgRects);
        }

        if (axisX.show) {
          var xAxis = axis()
            .scale(xScale)
            .tickValues(
              xScale.domain()
                .filter(function (d, i) { return !(i % axisX.filterTicksBy); })
            )
            .gClass(axisX.axisClass)
            .transform("translate(0," + height + ")")
            .titleX(axisX.x)
            .titleY(axisY.y)
            .titleDY(axisX.dy)
            .titleAnchor(axisX.textAnchor)
            .title(axisX.title);

          g.call(xAxis);

          // Modifying the x axis tick labels
          g.selectAll(".x.axis .tick text")
            .attr("x", -10)
            .attr("y", -4)
            .attr("transform", "rotate(" + axisX.tickRotate + ")")
            .style("text-anchor", "end");
        }

        if (axisY.show) {
          var yAxis = axis()
            .scale(yScale)
            .tickValues(
              yScale.domain()
                .filter(function (d, i) { return !(i % axisY.filterTicksBy); })
            )
            .orient("left")
            .gClass(axisY.axisClass)
            .titleClass(axisY.titleClass)
            .titleX(axisY.x)
            .titleY(axisY.y)
            .titleDY(axisY.dy)
            .titleAnchor(axisY.textAnchor)
            .title(axisY.title);

          g.call(yAxis);
        }
      });
    }

    function getDomain(data, accessor) {
      return data
        .map(function (item) {
          return item[accessor];
        })
        .sort(function (prev, cur) {
          if (prev > cur) return 1;
          if (prev < cur) return -1;
          return 0;
        })
        .filter(function (item, index, array) {
          return array.indexOf(item) === index;
        });
    }

    // Public API
    chart.margin = function (_) {
      if (!arguments.length) { return margin; }
      margin.top = typeof _.top !== "undefined" ? _.top : margin.top;
      margin.right = typeof _.right !== "undefined" ? _.right : margin.right;
      margin.bottom = typeof _.bottom !== "undefined" ? _.bottom : margin.bottom;
      margin.left = typeof _.left !== "undefined" ? _.left : margin.left;
      return chart;
    };

    chart.width = function (_) {
      if (!arguments.length) return width;
      width = _;
      return chart;
    };

    chart.height = function (_) {
      if (!arguments.length) return height;
      height = _;
      return chart;
    };

    chart.color = function (_) {
      if (!arguments.length) return color;
      color = _;
      return chart;
    };

    chart.canvas = function (_) {
      if (!arguments.length) return isCanvas;
      isCanvas = _;
      return chart;
    };

    chart.rect = function (_) {
      if (!arguments.length) { return rect; }
      rect.x = typeof _.x !== "undefined" ? _.x : rect.x;
      rect.y = typeof _.y !== "undefined" ? _.y : rect.y;
      rect.color = typeof _.color !== "undefined" ? _.color : rect.color;
      rect.cssClass = typeof _.cssClass !== "undefined" ? _.cssClass : rect.cssClass;
      rect.strokeWidth = typeof _.strokeWidth !== "undefined" ? _.strokeWidth : rect.strokeWidth;
      rect.fill = typeof _.fill !== "undefined" ? _.fill : rect.fill;
      rect.opacity = typeof _.opacity !== "undefined" ? _.opacity : rect.opacity;
      rect.padding = typeof _.padding !== "undefined" ? _.padding : rect.padding;
      return chart;
    };

    chart.xAxis = function (_) {
      if (!arguments.length) { return axisX; }
      axisX.show = typeof _.show !== "undefined" ? _.show : axisX.show;
      axisX.axisClass = typeof _.axisClass !== "undefined" ? _.axisClass : axisX.axisClass;
      axisX.titleClass = typeof _.titleClass !== "undefined" ? _.titleClass : axisX.titleClass;
      axisX.x = typeof _.x !== "undefined" ? _.x : axisX.x;
      axisX.y = typeof _.y !== "undefined" ? _.y : axisX.y;
      axisX.dy = typeof _.dy !== "undefined" ? _.dy : axisX.dy;
      axisX.tickValues = typeof _.tickValues !== "undefined" ? _.tickValues: axisX.tickValues;
      axisX.textAnchor = typeof _.textAnchor !== "undefined" ? _.textAnchor : axisX.textAnchor;
      axisX.title = typeof _.title !== "undefined" ? _.title : axisX.title;
      axisX.filterTicksBy = typeof _.filterTicksBy !== "undefined" ? _.filterTicksBy : axisX.filterTicksBy;
      axisX.tickRotate = typeof _.tickRotate !== "undefined" ? _.tickRotate : axisX.tickRotate;
      return chart;
    };

    chart.yAxis = function (_) {
      if (!arguments.length) { return axisY; }
      axisY.show = typeof _.show !== "undefined" ? _.show : axisY.show;
      axisY.axisClass = typeof _.axisClass !== "undefined" ? _.axisClass : axisY.axisClass;
      axisY.titleClass = typeof _.titleClass !== "undefined" ? _.titleClass : axisY.titleClass;
      axisY.x = typeof _.x !== "undefined" ? _.x : axisY.x;
      axisY.y = typeof _.y !== "undefined" ? _.y : axisY.y;
      axisY.dy = typeof _.dy !== "undefined" ? _.dy : axisY.dy;
      axisY.tickValues = typeof _.tickValues !== "undefined" ? _.tickValues: axisY.tickValues;
      axisY.textAnchor = typeof _.textAnchor !== "undefined" ? _.textAnchor : axisY.textAnchor;
      axisY.title = typeof _.title !== "undefined" ? _.title : axisY.title;
      axisY.filterTicksBy = typeof _.filterTicksBy !== "undefined" ? _.filterTicksBy : axisY.filterTicksBy;
      return chart;
    };

    return chart;
  }
});
<|endoftext|>


<commit_before>'use strict';

angular.module('copay.header').controller('HeaderController',
  function($scope, $rootScope, $location, walletFactory, controllerUtils) {
    $scope.menu = [{
      'title': 'Copayers',
      'icon': 'fi-torsos-all',
      'link': '#/peer'
    }, {
      'title': 'Addresses',
      'icon': 'fi-address-book',
      'link': '#/addresses'
    }, {
      'title': 'Transactions',
      'icon': 'fi-loop',
      'link': '#/transactions'
    }, {
      'title': 'Send',
      'icon': 'fi-arrow-right',
      'link': '#/send'
    }, {
      'title': 'Backup',
      'icon': 'fi-archive',
      'link': '#/backup'
    }];

    $rootScope.$watch('wallet', function(wallet) {
      if (wallet) {
        controllerUtils.setSocketHandlers();
      }
    });

    $scope.isActive = function(item) {
      if (item.link && item.link.replace('#','') == $location.path()) {
        return true;
      }
      return false;
    };

    $scope.signout = function() {
      var w = $rootScope.wallet;
      if (w) {
        w.disconnect();
        controllerUtils.logout();
      }
    };

    $scope.clearFlashMessage = function() {
      $rootScope.flashMessage = {};
    };

    $rootScope.isCollapsed = true;
  });
<commit_msg>Clear all notifications when sign out.<commit_after>'use strict';

angular.module('copay.header').controller('HeaderController',
  function($scope, $rootScope, $location, walletFactory, controllerUtils) {
    $scope.menu = [{
      'title': 'Copayers',
      'icon': 'fi-torsos-all',
      'link': '#/peer'
    }, {
      'title': 'Addresses',
      'icon': 'fi-address-book',
      'link': '#/addresses'
    }, {
      'title': 'Transactions',
      'icon': 'fi-loop',
      'link': '#/transactions'
    }, {
      'title': 'Send',
      'icon': 'fi-arrow-right',
      'link': '#/send'
    }, {
      'title': 'Backup',
      'icon': 'fi-archive',
      'link': '#/backup'
    }];

    $rootScope.$watch('wallet', function(wallet) {
      if (wallet) {
        controllerUtils.setSocketHandlers();
      }
    });

    $scope.isActive = function(item) {
      if (item.link && item.link.replace('#','') == $location.path()) {
        return true;
      }
      return false;
    };

    $scope.signout = function() {
      var w = $rootScope.wallet;
      if (w) {
        w.disconnect();
        controllerUtils.logout();
      }
      $rootScope.flashMessage = {};
    };

    $scope.clearFlashMessage = function() {
      $rootScope.flashMessage = {};
    };

    $rootScope.isCollapsed = true;
  });
<|endoftext|>


<commit_before>(function() {
    try {
        // from Eli Grey @ http://eligrey.com/blog/post/textcontent-in-ie8
        if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
            Object.getOwnPropertyDescriptor(Element.prototype, "textContent") &&
            !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get) {
            var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
            Object.defineProperty(Element.prototype, "textContent", {
                // It won't work if you just drop in innerText.get
                // and innerText.set or the whole descriptor.
                get: function() {
                    return innerText.get.call(this);
                },
                set: function(x) {
                    return innerText.set.call(this, x);
                }
            });
        }
    } catch (e) {
        // bad Firefox
    }
})();
<commit_msg>Slightly more correct shim for Node.textContent<commit_after>(function() {
    try {
        // inspired by Eli Grey's shim @ http://eligrey.com/blog/post/textcontent-in-ie8
        // heavily modified to better match the spec:
        // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent
        if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
            Object.getOwnPropertyDescriptor(Element.prototype, "textContent") &&
            !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get) {
            var nodeValue = Object.getOwnPropertyDescriptor(Text.prototype, "nodeValue");
            Object.defineProperty(Text.prototype, "textContent", {
                // It won't work if you just drop in nodeValue.get
                // and nodeValue.set or the whole descriptor.
                get: function() {
                    return nodeValue.get.call(this);
                },
                set: function(x) {
                    return nodeValue.set.call(this,x);
                }
            });
            var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
            Object.defineProperty(Element.prototype, "textContent", {
                get: function() {
                    // It won't work if you just drop in innerText.get
                    // or the whole descriptor.
                    return innerText.get.call(this);
                },
                set: function(x) {
                    //return innerText.set.call(this,x); // nope! you do weird things!
                    var c;
                    while(!!(c=this.firstChild)) { this.removeChild(c); }
                    if (x!==null) {
                        c=document.createTextNode(x);
                        this.appendChild(c);
                    }
                    c=null;
                    return x;
                }
            });
        }
    } catch (e) {
        // bad Firefox
    }
})();
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'foam.ui',
  name: 'SlidePanel',
  extendsModel: 'View',

  requires: [
    'GestureTarget'
  ],
  imports: [
    'clearTimeout',
    'document',
    'gestureManager',
    'setTimeout'
  ],

  constants: {
    CLOSED: {
      name: 'CLOSED',
      layout: function() {
        return [ this.parentWidth - this.stripWidth, this.minPanelWidth, this.stripWidth ];
      },
      onResize: function() {
        if ( this.parentWidth > this.minWidth + this.minPanelWidth )
          this.state = this.EXPANDED;
      },
      toggle: function() { this.open(); },
      open: function() { this.state = this.OPEN; },
      over: true
    },
    EXPANDED: {
      name: 'EXPANDED',
      layout: function() {
        var extraWidth = this.parentWidth - this.minWidth - this.minPanelWidth;
        var panelWidth = this.minPanelWidth + extraWidth * this.panelRatio;
        return [ this.parentWidth - panelWidth, panelWidth, panelWidth ];
      },
      onResize: function() {
        if ( this.parentWidth < this.minWidth + this.minPanelWidth )
          this.state = this.CLOSED;
      }
    },
    OPEN: {
      name: 'OPEN',
      layout: function() {
        return [ this.parentWidth - this.stripWidth, this.minPanelWidth, this.panelWidth ];
      },
      onResize: function() {
        if ( this.parentWidth > this.minWidth + this.minPanelWidth )
          this.state = this.OPEN_EXPANDED;
      },
      close: function() { this.state = this.CLOSED; },
      toggle: function() { this.close(); },
      over: true
    },
    OPEN_EXPANDED: {
      name: 'OPEN_EXPANDED',
      layout: function() { return this.EXPANDED.layout.call(this); },
      onResize: function() {
        if ( this.parentWidth < this.minWidth + this.minPanelWidth )
          this.state = this.OPEN;
      }
    }
  },

  help: 'A controller that shows a main view with a small strip of the ' +
      'secondary view visible at the right edge. This "panel" can be dragged ' +
      'by a finger or mouse pointer to any position from its small strip to ' +
      'fully exposed. If the containing view is wide enough, both panels ' +
      'will always be visible.',

  properties: [
    {
      name: 'state',
      postSet: function(oldState, newState) {
        var layout = this.state.layout.call(this);
        if ( oldState === newState && ! this.af_ ) {
          this.currentLayout = layout;
        } else {
          this.desiredLayout = layout;
        }
      }
    },
    {
      name: 'currentLayout',
      postSet: function(_, layout) {
        this.panelWidth = Math.max(layout[1]+2, this.minPanelWidth);
        this.panelX     = Math.min(this.parentWidth-this.stripWidth, this.parentWidth-layout[2]);
        this.mainWidth  = Math.max(layout[0], this.panelX);
      }
    },
    {
      name: 'desiredLayout',
      postSet: function(_, layout) {
        if ( ! this.currentLayout ) {
          this.currentLayout = layout;
          return;
        }
        var startLayout = this.currentLayout;
        var start = Date.now();
        var end   = start + 200;
        var animate = function() {
          var now = Date.now();
          var p = (now-start) / (end-start);
          if ( p < 1 ) {
            var mainWidth =
            this.currentLayout = [
              startLayout[0] * ( 1 - p ) + layout[0] * p,
              startLayout[1] * ( 1 - p ) + layout[1] * p,
              startLayout[2] * ( 1 - p ) + layout[2] * p
            ];
            if ( this.af_ ) this.X.cancelAnimationFrame(this.af_);
            this.af_ = this.X.requestAnimationFrame(animate);
          } else {
            this.currentLayout = layout;
            this.af_ = null;
          }
        }.bind(this);
        animate();
      }
    },
    { model_: 'ViewFactoryProperty', name: 'mainView' },
    { model_: 'ViewFactoryProperty', name: 'panelView' },
    {
      model_: 'IntProperty',
      name: 'minWidth',
      defaultValueFn: function() {
        var e = this.main$();
        return e ? toNum(this.X.window.getComputedStyle(e).width) : 300;
      }
    },
    {
      model_: 'IntProperty',
      name: 'mainWidth',
      model_: 'IntProperty',
      hidden: true,
      help: 'Set internally by the resize handler',
      postSet: function(_, x) {
        this.main$().style.width = x + 'px';
      }
    },
    {
      model_: 'IntProperty',
      name: 'panelWidth',
      model_: 'IntProperty',
      hidden: true,
      help: 'Set internally by the resize handler',
      postSet: function(_, x) {
        this.panel$().style.width = (x+2) + 'px';
      }
    },
    {
      model_: 'IntProperty',
      name: 'minPanelWidth',
      defaultValueFn: function() {
        if ( this.panelView && this.panelView.minWidth )
          return this.panelView.minWidth + (this.panelView.stripWidth || 0);

        var e = this.panel$();
        return e ? toNum(this.X.window.getComputedStyle(e).width) : 250;
      }
    },
    {
      model_: 'IntProperty',
      name: 'parentWidth',
      help: 'A pseudoproperty that returns the current width (CSS pixels) of the containing element',
      getter: function() { return toNum(this.X.window.getComputedStyle(this.$.parentNode).width); }
    },
    {
      model_: 'IntProperty',
      name: 'stripWidth',
      help: 'The width in (CSS) pixels of the minimal visible strip of panel',
      defaultValue: 30
    },
    {
      model_: 'FloatProperty',
      name: 'panelRatio',
      help: 'The ratio (0-1) of the total width occupied by the panel, when ' +
          'the containing element is wide enough for expanded view.',
      defaultValue: 0.5
    },
    {
      model_: 'IntProperty',
      name: 'panelX',
      postSet: function(oldX, x) {
        if ( this.currentLayout ) this.currentLayout[2] = this.parentWidth-x;
        if ( oldX !== x ) this.dir_ = oldX.compareTo(x);
        this.panel$().style.webkitTransform = 'translate3d(' + x + 'px, 0,0)';
      }
    },
    {
      name: 'dragGesture',
      hidden: true,
      transient: true,
      lazyFactory: function() {
        return this.GestureTarget.create({
          containerID: this.id + '-panel',
          handler: this,
          gesture: 'drag'
        });
      }
    },
    {
      name: 'tapGesture',
      hidden: true,
      transient: true,
      lazyFactory: function() {
        return this.GestureTarget.create({
          containerID: this.id + '-panel',
          handler: this,
          gesture: 'tap'
        });
      }
    },
    {
      name: 'expanded',
      help: 'If the panel is wide enough to expand the panel permanently.',
      defaultValue: false
    }
  ],

  templates: [
    function CSS() {/*
      .SlidePanel .shadow {
        background: linear-gradient(to left, rgba(0,0,0,0.15) 0%,
                                             rgba(0,0,0,0) 100%);
        height: 100%;
        left: -8px;
        position: absolute;
        width: 8px;
      }
    */},
    function toHTML() {/*

          <%= this.mainView() %>

          <%= this.panelView() %>

    */}
  ],

  methods: {
    initHTML: function() {
      this.state = this.state = this.CLOSED;

      this.gestureManager.install(this.dragGesture);
      this.gestureManager.install(this.tapGesture);

      // Resize first, then init the outer view, and finally the panel view.
      this.X.window.addEventListener('resize', this.onResize);

      this.main$().addEventListener('click',       this.onMainFocus);
      this.main$().addEventListener('DOMFocusIn',  this.onMainFocus);
      this.panel$().addEventListener('DOMFocusIn', this.onPanelFocus);
      this.onResize();
      this.initChildren(); // We didn't call SUPER(), so we have to do this here.
    },
    interpolate: function(state1, state2) {
      var layout1 = state1.layout.call(this);
      var layout2 = state2.layout.call(this);
      return [
        layout1[0] * this.progress + layout2[0] * ( 1 - this.progress ),
        layout1[1] * this.progress + layout2[1] * ( 1 - this.progress ),
        layout1[2] * this.progress + layout2[2] * ( 1 - this.progress ),
      ];
    },
    main$:   function() { return this.X.$(this.id + '-main'); },
    panel$:  function() { return this.X.$(this.id + '-panel'); },
    shadow$: function() { return this.X.$(this.id + '-shadow'); },
    open:    function() { this.state.open && this.state.open.call(this); },
    close:   function() { this.state.close && this.state.close.call(this); },
    toggle:  function() { this.state.toggle && this.state.toggle.call(this); }
  },

  listeners: [
    {
      name: 'onPanelFocus',
      isMerged: 1,
      code: function(e) { this.open(); }
    },
    {
      name: 'onMainFocus',
      isMerged: 1,
      code: function(e) { this.close(); }
    },
    {
      name: 'onResize',
      isFramed: true,
      code: function(e) {
        if ( ! this.$ ) return;
        this.state.onResize.call(this);
        this.shadow$().style.display = this.state.over ? 'inline' : 'none';
        this.state = this.state;
        var parentWidth = this.parentWidth;
        // TODO(kgr): temporary hack in case SlidePanel's are nested and
        // the the inner one needs to be re-layedout after the outer one
        // changes its size.  Being resized should also fire an onResize event.
        this.X.setTimeout(function() {
          if ( this.parentWidth !== parentWidth ) this.onResize();
        }.bind(this), 205);
      }
    },
    {
      name: 'tapClick',
      code: function() { this.toggle(); }
    },
    {
      name: 'dragStart',
      code: function(point) {
        if ( this.expanded ) return;
        // Otherwise, bind panelX to the absolute X.
        var self = this;
        var originalX = this.panelX;
        Events.map(point.x$, this.panelX$, function(x) {
          var x = originalX + point.totalX;

          // Bound it between its left and right limits: full open and just the
          // strip.
          if ( x <= this.parentWidth - this.panelWidth )
            return this.parentWidth - this.panelWidth;

          if ( x >= this.parentWidth - this.stripWidth )
            return this.parentWidth - this.stripWidth;

          return x;
        }.bind(this));
      }
    },
    {
      name: 'dragEnd',
      code: function(point) {
        var currentLayout = this.currentLayout;
        if ( this.af_ ) this.X.cancelAnimationFrame(this.af_);
        this.af_ = null;
        if ( this.dir_ < 0 ) this.close(); else this.open();
        var layout = this.state.layout.call(this);
        this.currentLayout = currentLayout;
        this.desiredLayout = layout;
      }
    }
  ]
});
<commit_msg>Added ANIMATION_DELAY constant to SlidePanel.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'foam.ui',
  name: 'SlidePanel',
  extendsModel: 'View',

  requires: [
    'GestureTarget'
  ],
  imports: [
    'clearTimeout',
    'document',
    'gestureManager',
    'setTimeout'
  ],

  constants: {
    ANIMATION_DELAY: 200,

    CLOSED: {
      name: 'CLOSED',
      layout: function() {
        return [ this.parentWidth - this.stripWidth, this.minPanelWidth, this.stripWidth ];
      },
      onResize: function() {
        if ( this.parentWidth > this.minWidth + this.minPanelWidth )
          this.state = this.EXPANDED;
      },
      toggle: function() { this.open(); },
      open: function() { this.state = this.OPEN; },
      over: true
    },
    EXPANDED: {
      name: 'EXPANDED',
      layout: function() {
        var extraWidth = this.parentWidth - this.minWidth - this.minPanelWidth;
        var panelWidth = this.minPanelWidth + extraWidth * this.panelRatio;
        return [ this.parentWidth - panelWidth, panelWidth, panelWidth ];
      },
      onResize: function() {
        if ( this.parentWidth < this.minWidth + this.minPanelWidth )
          this.state = this.CLOSED;
      }
    },
    OPEN: {
      name: 'OPEN',
      layout: function() {
        return [ this.parentWidth - this.stripWidth, this.minPanelWidth, this.panelWidth ];
      },
      onResize: function() {
        if ( this.parentWidth > this.minWidth + this.minPanelWidth )
          this.state = this.OPEN_EXPANDED;
      },
      close: function() { this.state = this.CLOSED; },
      toggle: function() { this.close(); },
      over: true
    },
    OPEN_EXPANDED: {
      name: 'OPEN_EXPANDED',
      layout: function() { return this.EXPANDED.layout.call(this); },
      onResize: function() {
        if ( this.parentWidth < this.minWidth + this.minPanelWidth )
          this.state = this.OPEN;
      }
    }
  },

  help: 'A controller that shows a main view with a small strip of the ' +
      'secondary view visible at the right edge. This "panel" can be dragged ' +
      'by a finger or mouse pointer to any position from its small strip to ' +
      'fully exposed. If the containing view is wide enough, both panels ' +
      'will always be visible.',

  properties: [
    {
      name: 'state',
      postSet: function(oldState, newState) {
        var layout = this.state.layout.call(this);
        if ( oldState === newState && ! this.af_ ) {
          this.currentLayout = layout;
        } else {
          this.desiredLayout = layout;
        }
      }
    },
    {
      name: 'currentLayout',
      postSet: function(_, layout) {
        this.panelWidth = Math.max(layout[1]+2, this.minPanelWidth);
        this.panelX     = Math.min(this.parentWidth-this.stripWidth, this.parentWidth-layout[2]);
        this.mainWidth  = Math.max(layout[0], this.panelX);
      }
    },
    {
      name: 'desiredLayout',
      postSet: function(_, layout) {
        if ( ! this.currentLayout ) {
          this.currentLayout = layout;
          return;
        }
        var startLayout = this.currentLayout;
        var start = Date.now();
        var end   = start + this.ANIMATION_DELAY;
        var animate = function() {
          var now = Date.now();
          var p = (now-start) / (end-start);
          if ( p < 1 ) {
            var mainWidth =
            this.currentLayout = [
              startLayout[0] * ( 1 - p ) + layout[0] * p,
              startLayout[1] * ( 1 - p ) + layout[1] * p,
              startLayout[2] * ( 1 - p ) + layout[2] * p
            ];
            if ( this.af_ ) this.X.cancelAnimationFrame(this.af_);
            this.af_ = this.X.requestAnimationFrame(animate);
          } else {
            this.currentLayout = layout;
            this.af_ = null;
          }
        }.bind(this);
        animate();
      }
    },
    { model_: 'ViewFactoryProperty', name: 'mainView' },
    { model_: 'ViewFactoryProperty', name: 'panelView' },
    {
      model_: 'IntProperty',
      name: 'minWidth',
      defaultValueFn: function() {
        var e = this.main$();
        return e ? toNum(this.X.window.getComputedStyle(e).width) : 300;
      }
    },
    {
      model_: 'IntProperty',
      name: 'mainWidth',
      model_: 'IntProperty',
      hidden: true,
      help: 'Set internally by the resize handler',
      postSet: function(_, x) {
        this.main$().style.width = x + 'px';
      }
    },
    {
      model_: 'IntProperty',
      name: 'panelWidth',
      model_: 'IntProperty',
      hidden: true,
      help: 'Set internally by the resize handler',
      postSet: function(_, x) {
        this.panel$().style.width = (x+2) + 'px';
      }
    },
    {
      model_: 'IntProperty',
      name: 'minPanelWidth',
      defaultValueFn: function() {
        if ( this.panelView && this.panelView.minWidth )
          return this.panelView.minWidth + (this.panelView.stripWidth || 0);

        var e = this.panel$();
        return e ? toNum(this.X.window.getComputedStyle(e).width) : 250;
      }
    },
    {
      model_: 'IntProperty',
      name: 'parentWidth',
      help: 'A pseudoproperty that returns the current width (CSS pixels) of the containing element',
      getter: function() { return toNum(this.X.window.getComputedStyle(this.$.parentNode).width); }
    },
    {
      model_: 'IntProperty',
      name: 'stripWidth',
      help: 'The width in (CSS) pixels of the minimal visible strip of panel',
      defaultValue: 30
    },
    {
      model_: 'FloatProperty',
      name: 'panelRatio',
      help: 'The ratio (0-1) of the total width occupied by the panel, when ' +
          'the containing element is wide enough for expanded view.',
      defaultValue: 0.5
    },
    {
      model_: 'IntProperty',
      name: 'panelX',
      postSet: function(oldX, x) {
        if ( this.currentLayout ) this.currentLayout[2] = this.parentWidth-x;
        if ( oldX !== x ) this.dir_ = oldX.compareTo(x);
        this.panel$().style.webkitTransform = 'translate3d(' + x + 'px, 0,0)';
      }
    },
    {
      name: 'dragGesture',
      hidden: true,
      transient: true,
      lazyFactory: function() {
        return this.GestureTarget.create({
          containerID: this.id + '-panel',
          handler: this,
          gesture: 'drag'
        });
      }
    },
    {
      name: 'tapGesture',
      hidden: true,
      transient: true,
      lazyFactory: function() {
        return this.GestureTarget.create({
          containerID: this.id + '-panel',
          handler: this,
          gesture: 'tap'
        });
      }
    },
    {
      name: 'expanded',
      help: 'If the panel is wide enough to expand the panel permanently.',
      defaultValue: false
    }
  ],

  templates: [
    function CSS() {/*
      .SlidePanel .shadow {
        background: linear-gradient(to left, rgba(0,0,0,0.15) 0%,
                                             rgba(0,0,0,0) 100%);
        height: 100%;
        left: -8px;
        position: absolute;
        width: 8px;
      }
    */},
    function toHTML() {/*

          <%= this.mainView() %>

          <%= this.panelView() %>

    */}
  ],

  methods: {
    initHTML: function() {
      this.state = this.state = this.CLOSED;

      this.gestureManager.install(this.dragGesture);
      this.gestureManager.install(this.tapGesture);

      // Resize first, then init the outer view, and finally the panel view.
      this.X.window.addEventListener('resize', this.onResize);

      this.main$().addEventListener('click',       this.onMainFocus);
      this.main$().addEventListener('DOMFocusIn',  this.onMainFocus);
      this.panel$().addEventListener('DOMFocusIn', this.onPanelFocus);
      this.onResize();
      this.initChildren(); // We didn't call SUPER(), so we have to do this here.
    },
    interpolate: function(state1, state2) {
      var layout1 = state1.layout.call(this);
      var layout2 = state2.layout.call(this);
      return [
        layout1[0] * this.progress + layout2[0] * ( 1 - this.progress ),
        layout1[1] * this.progress + layout2[1] * ( 1 - this.progress ),
        layout1[2] * this.progress + layout2[2] * ( 1 - this.progress ),
      ];
    },
    main$:   function() { return this.X.$(this.id + '-main'); },
    panel$:  function() { return this.X.$(this.id + '-panel'); },
    shadow$: function() { return this.X.$(this.id + '-shadow'); },
    open:    function() { this.state.open && this.state.open.call(this); },
    close:   function() { this.state.close && this.state.close.call(this); },
    toggle:  function() { this.state.toggle && this.state.toggle.call(this); }
  },

  listeners: [
    {
      name: 'onPanelFocus',
      isMerged: 1,
      code: function(e) { this.open(); }
    },
    {
      name: 'onMainFocus',
      isMerged: 1,
      code: function(e) { this.close(); }
    },
    {
      name: 'onResize',
      isFramed: true,
      code: function(e) {
        if ( ! this.$ ) return;
        this.state.onResize.call(this);
        this.shadow$().style.display = this.state.over ? 'inline' : 'none';
        this.state = this.state;
        var parentWidth = this.parentWidth;
        // TODO(kgr): temporary hack in case SlidePanel's are nested and
        // the the inner one needs to be re-layedout after the outer one
        // changes its size.  Being resized should also fire an onResize event.
        this.X.setTimeout(function() {
          if ( this.parentWidth !== parentWidth ) this.onResize();
        }.bind(this), this.ANIMATION_DELAY + 10);
      }
    },
    {
      name: 'tapClick',
      code: function() { this.toggle(); }
    },
    {
      name: 'dragStart',
      code: function(point) {
        if ( this.expanded ) return;
        // Otherwise, bind panelX to the absolute X.
        var self = this;
        var originalX = this.panelX;
        Events.map(point.x$, this.panelX$, function(x) {
          var x = originalX + point.totalX;

          // Bound it between its left and right limits: full open and just the
          // strip.
          if ( x <= this.parentWidth - this.panelWidth )
            return this.parentWidth - this.panelWidth;

          if ( x >= this.parentWidth - this.stripWidth )
            return this.parentWidth - this.stripWidth;

          return x;
        }.bind(this));
      }
    },
    {
      name: 'dragEnd',
      code: function(point) {
        var currentLayout = this.currentLayout;
        if ( this.af_ ) this.X.cancelAnimationFrame(this.af_);
        this.af_ = null;
        if ( this.dir_ < 0 ) this.close(); else this.open();
        var layout = this.state.layout.call(this);
        this.currentLayout = currentLayout;
        this.desiredLayout = layout;
      }
    }
  ]
});
<|endoftext|>


<commit_before>!function(Foundation, $) {
  'use strict';

  // The plugin matches the plugin classes with these plugin instances.
  var menubarPlugins = {
    dropdown: {
      cssClass: 'dropdown',
      plugin: Foundation._plugins.dropdown || null
    },
    drilldown: {
      cssClass: 'drilldown',
      plugin: Foundation._plugins.drilldown || null
    }
  }

  // [PH] Media queries
  var phMedia = {
    small: '(min-width: 0px)',
    medium: '(min-width: 640px)'
  }

  /**
   * Creates a new instance of Dropdown.
   * @class
   * @fires Dropdown#init
   * @param {jQuery} element - jQuery object to make into a dropdown menu.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  function MenuBar(element, options) {
    this.$element = $(element);
    this.rules = this.$element.data('menubar');
    this.currentMq = null;
    this.currentPlugin = null;

    this._init();
    this._events();
    this._checkMediaQueries();

    /**
     * Fires when the plugin has been successfuly initialized.
     * @event Drilldown#init
     */
     this.$element.trigger('init.zf.menubar');
  }

  MenuBar.prototype.defaults = {};

  /**
   * Initializes the menu bar by parsing the classes from the 'data-menubar' attribute on the element.
   * @function
   * @private
   */
  MenuBar.prototype._init = function() {
    var rulesTree = {};

    // Parse rules from "classes" in data attribute
    var rules = this.rules.split(' ');

    // Iterate through every rule found
    for (var i = 0; i < rules.length; i++) {
      var rule = rules[i].split('-');
      var ruleSize = rule.length > 1 ? rule[0] : 'small';
      var rulePlugin = rule.length > 1 ? rule[1] : rule[0];

      if (menubarPlugins[rulePlugin] !== null) {
        rulesTree[ruleSize] = menubarPlugins[rulePlugin];
      }
    }

    this.rules = rulesTree;
  };

  /**
   * Initializes events for the menu bar.
   * @function
   * @private
   */
  MenuBar.prototype._events = function() {
    var _this = this;

    $(window).on('resize.zf.menubar', function() {
      _this._checkMediaQueries();
    });
  };

  /**
   * Checks the current screen width against available media queries. If the media query has changed, and the plugin needed has changed, the plugins will swap out.
   * @function
   * @private
   */
  MenuBar.prototype._checkMediaQueries = function() {
    var matchedMq, _this = this;

    // Iterate through each rule and find the last matching rule
    $.each(this.rules, function(key, value) {
      if (window.matchMedia(phMedia[key]).matches && key !== _this.currentMq) {
        matchedMq = key;
      }
    });

    // No match? No dice
    if (!matchedMq) return;

    // Plugin already initialized? We good
    if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return;

    // Remove existing plugin-specific CSS classes
    $.each(menubarPlugins, function(key, value) {
      _this.$element.removeClass(value.cssClass);
    });

    // Add the CSS class for the new plugin
    this.$element.addClass(this.rules[matchedMq].cssClass);

    // Create an instance of the new plugin
    if (this.currentPlugin) this.currentPlugin.destroy();
    this.currentPlugin = new this.rules[matchedMq].plugin(this.$element, {});
  }

  /**
   * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out.
   * @function
   */
  MenuBar.prototype.destroy = function() {
    this.currentPlugin.destroy();
    $(window).off('.zf.menubar');
  }

  Foundation.plugin('menubar', MenuBar);

}(Foundation, jQuery)<commit_msg>Add accordion menu to responsive menu bar JS<commit_after>!function(Foundation, $) {
  'use strict';

  // The plugin matches the plugin classes with these plugin instances.
  var menubarPlugins = {
    dropdown: {
      cssClass: 'dropdown',
      plugin: Foundation._plugins['dropdown'] || null
    },
    drilldown: {
      cssClass: 'drilldown',
      plugin: Foundation._plugins['drilldown'] || null
    },
    accordion: {
      cssClass: 'accordion-menu',
      plugin: Foundation._plugins['accordion-menu'] || null
    }
  }

  // [PH] Media queries
  var phMedia = {
    small: '(min-width: 0px)',
    medium: '(min-width: 640px)'
  }

  /**
   * Creates a new instance of Dropdown.
   * @class
   * @fires Dropdown#init
   * @param {jQuery} element - jQuery object to make into a dropdown menu.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  function MenuBar(element, options) {
    this.$element = $(element);
    this.rules = this.$element.data('menubar');
    this.currentMq = null;
    this.currentPlugin = null;

    this._init();
    this._events();
    this._checkMediaQueries();

    /**
     * Fires when the plugin has been successfuly initialized.
     * @event Drilldown#init
     */
     this.$element.trigger('init.zf.menubar');
  }

  MenuBar.prototype.defaults = {};

  /**
   * Initializes the menu bar by parsing the classes from the 'data-menubar' attribute on the element.
   * @function
   * @private
   */
  MenuBar.prototype._init = function() {
    var rulesTree = {};

    // Parse rules from "classes" in data attribute
    var rules = this.rules.split(' ');

    // Iterate through every rule found
    for (var i = 0; i < rules.length; i++) {
      var rule = rules[i].split('-');
      var ruleSize = rule.length > 1 ? rule[0] : 'small';
      var rulePlugin = rule.length > 1 ? rule[1] : rule[0];

      if (menubarPlugins[rulePlugin] !== null) {
        rulesTree[ruleSize] = menubarPlugins[rulePlugin];
      }
    }

    this.rules = rulesTree;
  };

  /**
   * Initializes events for the menu bar.
   * @function
   * @private
   */
  MenuBar.prototype._events = function() {
    var _this = this;

    $(window).on('resize.zf.menubar', function() {
      _this._checkMediaQueries();
    });
  };

  /**
   * Checks the current screen width against available media queries. If the media query has changed, and the plugin needed has changed, the plugins will swap out.
   * @function
   * @private
   */
  MenuBar.prototype._checkMediaQueries = function() {
    var matchedMq, _this = this;

    // Iterate through each rule and find the last matching rule
    $.each(this.rules, function(key, value) {
      if (window.matchMedia(phMedia[key]).matches && key !== _this.currentMq) {
        matchedMq = key;
      }
    });

    // No match? No dice
    if (!matchedMq) return;

    // Plugin already initialized? We good
    if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return;

    // Remove existing plugin-specific CSS classes
    $.each(menubarPlugins, function(key, value) {
      _this.$element.removeClass(value.cssClass);
    });

    // Add the CSS class for the new plugin
    this.$element.addClass(this.rules[matchedMq].cssClass);

    // Create an instance of the new plugin
    if (this.currentPlugin) this.currentPlugin.destroy();
    this.currentPlugin = new this.rules[matchedMq].plugin(this.$element, {});
  }

  /**
   * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out.
   * @function
   */
  MenuBar.prototype.destroy = function() {
    this.currentPlugin.destroy();
    $(window).off('.zf.menubar');
  }

  Foundation.plugin('menubar', MenuBar);

}(Foundation, jQuery)<|endoftext|>


<commit_before>/*global $, jQuery*/

var fm = (function () {

	'use strict';

	var fm_options;

	function applyAnimation() {

		var animation_show = {},
			animation_hide = {};

		animation_show.marginLeft = "+=390px";
		animation_hide.marginLeft = "-=390px";

		if ($("body").attr("dir") === "rtl") {
			animation_show.marginRight = "+=390px";
			animation_hide.marginRight = "-=390px";
		}
		$("#feedback_trigger").click(function (event) {
			if ($("#feedback_trigger").hasClass("feedback_trigger_closed")) {
				$("#feedback_trigger , #feedback_content").animate(
					animation_show,
					500,
					'easeInOutSine',
					function () {
						$("#feedback_trigger").removeClass("feedback_trigger_closed");
					}
				);
			} else {
				$("#feedback_trigger , #feedback_content").animate(
					animation_hide,
					500,
					function () {
						$("#feedback_trigger").addClass("feedback_trigger_closed");
					}
				);
			}
		});
	}

	function appendFeedbackToBody(fm_options) {
		var jQueryUIClasses1 = "",
			jQueryUIClasses2 = "",
			jQueryUIClasses3 = "",
			jQueryUIClasses4 = "",
			email_html = "",
			email_feedback_content_class = "",
			non_jquery_class = "non_jquery_class",
			bootstrap_class = "",
			bootstrap_btn = "",
			bootstrap_hero_unit = "";

		if (fm_options.bootsrtap === true) {
			non_jquery_class = "";
			bootstrap_class = "fm_bootstrap";
			bootstrap_btn = "btn btn-primary";
			bootstrap_hero_unit = "hero-unit";
		}

		if (fm_options.jQueryUI === true) {
			jQueryUIClasses1 = "ui-widget-header ui-corner-all ui-helper-clearfix";
			jQueryUIClasses2 = "ui-dialog ui-widget ui-widget-content ui-corner-all";
			jQueryUIClasses3 = "ui-dialog-titlebar";
			jQueryUIClasses4 = "ui-dialog-title";

			bootstrap_class = "";
			bootstrap_hero_unit = "";
			bootstrap_btn = "";

			non_jquery_class = "";
		}

		if (fm_options.show_email === true) {
			email_html = '
	' + fm_options.email_label + ' <input type="text" id="feedback_email"></input>
';
			email_feedback_content_class = "email_present";
		}

		$('body').append('
'
				+	'' + fm_options.trigger_label
				+	'
');

		$('body').append('
'
							+ '
'
							+	'' + fm_options.title_label + ''
							+ '
'
							+	'
'
							+		'
	' + fm_options.name_label + ' <input type="text" id="feedback_name"></input>
'

							+		 email_html

							+		'
	' + fm_options.message_label + ' <textarea rows="5" id="feedback_message"></textarea>
'
							+		'
	<button id="feedback_submit" onclick="fm.sendFeedback();" class="' + bootstrap_btn + '">' + fm_options.submit_label + '</button>
'
							+	'
'
						+ '
');

		if (fm_options.jQueryUI === true) {
			$('#feedback_submit').button({
				icons: {
					primary: 'ui-icon-mail-closed'
				}
			});
		}

		applyAnimation();
	}

	function sendFeedback() {
		$.ajax({
			type: 'POST',
			url: fm.getFmOptions().feedback_url,
			data: { name: $("#feedback_name").val(), message: $("#feedback_message").val(), email: $("#feedback_email").val() },
			success: function (data) {
				var animation_hide = {};

				animation_hide.marginLeft = "-=390px";
				$("#feedback_trigger , #feedback_content").animate(
					animation_hide,
					500,
					function () {
						$("#feedback_trigger").addClass("feedback_trigger_closed");
						$("#feedback_name").val("");
						$("#feedback_message").val("");
						$("#feedback_email").val("");
					}
				);
			},
			error: function (ob, errStr) {
				alert("Failed to send feedback...");
			}
		});
	}

	function getFmOptions() {
		return fm_options;
	}

	function init(options) {

		var default_options = {
			jQueryUI : true,
			bootsrtap : false,
			show_email : false,
			name_label : "Name",
			email_label : "Email",
			message_label : "Message",
			submit_label : "Send",
			title_label : "Feedback",
			trigger_label : "Feedback"
		};

		fm_options = $.extend(default_options, options);

		appendFeedbackToBody(fm_options);
	}

    return {
		init : init,
		sendFeedback : sendFeedback,
		getFmOptions : getFmOptions
    };

}());<commit_msg>added plugin info<commit_after>/*global $, jQuery*/
/*
*
* jQuery Feedback Plugin
*
* File:        jquery.dataTables.yadcf.js
* Version:     0.1
* Author:      Daniel Reznick
* Info:        https://github.com/vedmack/feedback_me
* Contact:     vedmack@gmail.com
*
* Copyright 2013 Daniel Reznick, all rights reserved.
*
* Copyright 2013 Licensed under the MIT License (just like jQuery itself)
*
* This source file 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 license files for details.
*
*/
var fm = (function () {

	'use strict';

	var fm_options;

	function applyAnimation() {

		var animation_show = {},
			animation_hide = {};

		animation_show.marginLeft = "+=390px";
		animation_hide.marginLeft = "-=390px";

		if ($("body").attr("dir") === "rtl") {
			animation_show.marginRight = "+=390px";
			animation_hide.marginRight = "-=390px";
		}
		$("#feedback_trigger").click(function (event) {
			if ($("#feedback_trigger").hasClass("feedback_trigger_closed")) {
				$("#feedback_trigger , #feedback_content").animate(
					animation_show,
					500,
					'easeInOutSine',
					function () {
						$("#feedback_trigger").removeClass("feedback_trigger_closed");
					}
				);
			} else {
				$("#feedback_trigger , #feedback_content").animate(
					animation_hide,
					500,
					function () {
						$("#feedback_trigger").addClass("feedback_trigger_closed");
					}
				);
			}
		});
	}

	function appendFeedbackToBody(fm_options) {
		var jQueryUIClasses1 = "",
			jQueryUIClasses2 = "",
			jQueryUIClasses3 = "",
			jQueryUIClasses4 = "",
			email_html = "",
			email_feedback_content_class = "",
			non_jquery_class = "non_jquery_class",
			bootstrap_class = "",
			bootstrap_btn = "",
			bootstrap_hero_unit = "";

		if (fm_options.bootsrtap === true) {
			non_jquery_class = "";
			bootstrap_class = "fm_bootstrap";
			bootstrap_btn = "btn btn-primary";
			bootstrap_hero_unit = "hero-unit";
		}

		if (fm_options.jQueryUI === true) {
			jQueryUIClasses1 = "ui-widget-header ui-corner-all ui-helper-clearfix";
			jQueryUIClasses2 = "ui-dialog ui-widget ui-widget-content ui-corner-all";
			jQueryUIClasses3 = "ui-dialog-titlebar";
			jQueryUIClasses4 = "ui-dialog-title";

			bootstrap_class = "";
			bootstrap_hero_unit = "";
			bootstrap_btn = "";

			non_jquery_class = "";
		}

		if (fm_options.show_email === true) {
			email_html = '
	' + fm_options.email_label + ' <input type="text" id="feedback_email"></input>
';
			email_feedback_content_class = "email_present";
		}

		$('body').append('
'
				+	'' + fm_options.trigger_label
				+	'
');

		$('body').append('
'
							+ '
'
							+	'' + fm_options.title_label + ''
							+ '
'
							+	'
'
							+		'
	' + fm_options.name_label + ' <input type="text" id="feedback_name"></input>
'

							+		 email_html

							+		'
	' + fm_options.message_label + ' <textarea rows="5" id="feedback_message"></textarea>
'
							+		'
	<button id="feedback_submit" onclick="fm.sendFeedback();" class="' + bootstrap_btn + '">' + fm_options.submit_label + '</button>
'
							+	'
'
						+ '
');

		if (fm_options.jQueryUI === true) {
			$('#feedback_submit').button({
				icons: {
					primary: 'ui-icon-mail-closed'
				}
			});
		}

		applyAnimation();
	}

	function sendFeedback() {
		$.ajax({
			type: 'POST',
			url: fm.getFmOptions().feedback_url,
			data: { name: $("#feedback_name").val(), message: $("#feedback_message").val(), email: $("#feedback_email").val() },
			success: function (data) {
				var animation_hide = {};

				animation_hide.marginLeft = "-=390px";
				$("#feedback_trigger , #feedback_content").animate(
					animation_hide,
					500,
					function () {
						$("#feedback_trigger").addClass("feedback_trigger_closed");
						$("#feedback_name").val("");
						$("#feedback_message").val("");
						$("#feedback_email").val("");
					}
				);
			},
			error: function (ob, errStr) {
				alert("Failed to send feedback...");
			}
		});
	}

	function getFmOptions() {
		return fm_options;
	}

	function init(options) {

		var default_options = {
			jQueryUI : true,
			bootsrtap : false,
			show_email : false,
			name_label : "Name",
			email_label : "Email",
			message_label : "Message",
			submit_label : "Send",
			title_label : "Feedback",
			trigger_label : "Feedback"
		};

		fm_options = $.extend(default_options, options);

		appendFeedbackToBody(fm_options);
	}

    return {
		init : init,
		sendFeedback : sendFeedback,
		getFmOptions : getFmOptions
    };

}());<|endoftext|>


<commit_before>/*!
 * jQuery Mobile v@VERSION
 * http://jquerymobile.com/
 *
 * Copyright 2010, jQuery Project
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */

(function( $, window, undefined ) {

	//jQuery.mobile configurable options
	$.extend( $.mobile, {

		//namespace used framework-wide for data-attrs
		ns: "jq-",

		//define the url parameter used for referencing widget-generated sub-pages.
		//Translates to to example.html&ui-page=subpageIdentifier
		//hash segment before &ui-page= is used to make Ajax request
		subPageUrlKey: "ui-page",

		//anchor links with a data-jq-rel, or pages with a  data-jq-role, that match these selectors will be untrackable in history
		//(no change in URL, not bookmarkable)
		nonHistorySelectors: "dialog",

		//class assigned to page currently in view, and during transitions
		activePageClass: "ui-page-active",

		//class used for "active" button state, from CSS framework
		activeBtnClass: "ui-btn-active",

		//automatically handle clicks and form submissions through Ajax, when same-domain
		ajaxEnabled: true,

		//automatically load and show pages based on location.hash
		hashListeningEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle link clicks through Ajax, when possible
		ajaxLinksEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle form submissions through Ajax, when possible
		ajaxFormsEnabled: true,

		//set default transition - 'none' for no transitions
		defaultTransition: "slide",

		//show loading message during Ajax requests
		//if false, message will not appear, but loading classes will still be toggled on html el
		loadingMessage: "loading",

		//configure meta viewport tag's content attr:
		metaViewportContent: "width=device-width, minimum-scale=1, maximum-scale=1",

		//support conditions that must be met in order to proceed
		gradeA: function(){
			return $.support.mediaquery;
		},

		//TODO might be useful upstream in jquery itself ?
		keyCode: {
			ALT: 18,
			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			COMMAND: 91,
			COMMAND_LEFT: 91, // COMMAND
			COMMAND_RIGHT: 93,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			MENU: 93, // COMMAND_RIGHT
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38,
			WINDOWS: 91 // COMMAND
		}
	});

	//trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
	$( window.document ).trigger( "mobileinit" );

	//support conditions
	//if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
	//otherwise, proceed with the enhancements
	if ( !$.mobile.gradeA() ) {
		return;
	}

	//extend data() to treat namespaced data-attrs the same as non-namespaced ones
	var jqd = $.fn.data;

    $.fn.data = function( prop, value ){
    	var pu = prop === undefined,
    		vu = value === undefined;

    	if( pu || vu ){
	    	var ret,
	    		nsret;
	    	//if no args are passed, a data hash is expected. Remap non-namespaced props
	    	if( pu ){
	    		ret = jqd.call( this );
	    		$.each( ret, function( i ){
	    			var nsIndex = i.indexOf( $.mobile.ns );
	    			if( nsIndex == 0 ){
	    				ret[ i.substr( $.mobile.ns.length ) ] = ret[ i ];
	    			}
	    		});
	    	}
	    	//if it's a prop get, try namepaced version if prop is undefined
	    	else if( vu ){
	    		ret = jqd.call( this, prop );
	    		if( ret === undefined ){
	    			nsret = jqd.call( this, $.mobile.ns + prop );
	    			if( nsret !== undefined ){
	    				ret = nsret;
	    			}
	    		}
	    	}
	    	return ret;
	    }
    };

	//define vars for interal use
	var $window = $(window),
		$html = $( "html" ),
		$head = $( "head" ),

		//loading div which appears during Ajax requests
		//will not appear if $.mobile.loadingMessage is false
		$loader = $.mobile.loadingMessage ?
			$( "
" +
						"" +
						"
" + $.mobile.loadingMessage + "
" +
					"
" )
			: undefined;

	//add mobile, initial load "rendering" classes to docEl
	$html.addClass( "ui-mobile ui-mobile-rendering" );

	//define & prepend meta viewport tag, if content is defined
	$.mobile.metaViewportContent ? $( "<meta>", { name: "viewport", content: $.mobile.metaViewportContent}).prependTo( $head ) : undefined;

	//expose some core utilities
	$.extend($.mobile, {

		// turn on/off page loading message.
		pageLoading: function ( done ) {
			if ( done ) {
				$html.removeClass( "ui-loading" );
			} else {
				if( $.mobile.loadingMessage ){
					var activeBtn =$( "." + $.mobile.activeBtnClass ).first();

					$loader
						.appendTo( $.mobile.pageContainer )
						//position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
						.css( {
							top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
							activeBtn.length && activeBtn.offset().top || 100
						} );
				}

				$html.addClass( "ui-loading" );
			}
		},

		//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
		silentScroll: function( ypos ) {
			ypos = ypos || 0;
			// prevent scrollstart and scrollstop events
			$.event.special.scrollstart.enabled = false;

			setTimeout(function() {
				window.scrollTo( 0, ypos );
				$(document).trigger( "silentscroll", { x: 0, y: ypos });
			},20);

			setTimeout(function() {
				$.event.special.scrollstart.enabled = true;
			}, 150 );
		},

		// find and enhance the pages in the dom and transition to the first page.
		initializePage: function(){
			//find present pages
			var $pages = $( "[data-" + $.mobile.ns + "role='page']" );

			//add dialogs, set data-url attrs
			$pages.add( "[data-" + $.mobile.ns + "role='dialog']" ).each(function(){
				$(this).attr( "data-" + $.mobile.ns + "url", $(this).attr( "id" ));
			});

			//define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
			$.mobile.firstPage = $pages.first();

			//define page container
			$.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );

			//cue page loading message
			$.mobile.pageLoading();

			// if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
			if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
				$.mobile.changePage( $.mobile.firstPage, false, true, false, true );
			}
			// otherwise, trigger a hashchange to load a deeplink
			else {
				$window.trigger( "hashchange", [ true ] );
			}
		}
	});

	//dom-ready inits
	$($.mobile.initializePage);

	//window load event
	//hide iOS browser chrome on load
	$window.load( $.mobile.silentScroll );
})( jQuery, this );
<commit_msg>better var names<commit_after>/*!
 * jQuery Mobile v@VERSION
 * http://jquerymobile.com/
 *
 * Copyright 2010, jQuery Project
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */

(function( $, window, undefined ) {

	//jQuery.mobile configurable options
	$.extend( $.mobile, {

		//namespace used framework-wide for data-attrs
		ns: "jq-",

		//define the url parameter used for referencing widget-generated sub-pages.
		//Translates to to example.html&ui-page=subpageIdentifier
		//hash segment before &ui-page= is used to make Ajax request
		subPageUrlKey: "ui-page",

		//anchor links with a data-jq-rel, or pages with a  data-jq-role, that match these selectors will be untrackable in history
		//(no change in URL, not bookmarkable)
		nonHistorySelectors: "dialog",

		//class assigned to page currently in view, and during transitions
		activePageClass: "ui-page-active",

		//class used for "active" button state, from CSS framework
		activeBtnClass: "ui-btn-active",

		//automatically handle clicks and form submissions through Ajax, when same-domain
		ajaxEnabled: true,

		//automatically load and show pages based on location.hash
		hashListeningEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle link clicks through Ajax, when possible
		ajaxLinksEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle form submissions through Ajax, when possible
		ajaxFormsEnabled: true,

		//set default transition - 'none' for no transitions
		defaultTransition: "slide",

		//show loading message during Ajax requests
		//if false, message will not appear, but loading classes will still be toggled on html el
		loadingMessage: "loading",

		//configure meta viewport tag's content attr:
		metaViewportContent: "width=device-width, minimum-scale=1, maximum-scale=1",

		//support conditions that must be met in order to proceed
		gradeA: function(){
			return $.support.mediaquery;
		},

		//TODO might be useful upstream in jquery itself ?
		keyCode: {
			ALT: 18,
			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			COMMAND: 91,
			COMMAND_LEFT: 91, // COMMAND
			COMMAND_RIGHT: 93,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			MENU: 93, // COMMAND_RIGHT
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38,
			WINDOWS: 91 // COMMAND
		}
	});

	//trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
	$( window.document ).trigger( "mobileinit" );

	//support conditions
	//if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
	//otherwise, proceed with the enhancements
	if ( !$.mobile.gradeA() ) {
		return;
	}

	//extend data() to treat namespaced data-attrs the same as non-namespaced ones
	var jqd = $.fn.data;

    $.fn.data = function( prop, value ){
    	var pUndef = prop === undefined,
    		vUndef = value === undefined;

    	if( pUndef || vUndef ){
	    	var ret,
	    		nsret;
	    	//if no args are passed, a data hash is expected. Remap non-namespaced props
	    	if( pUndef ){
	    		ret = jqd.call( this );
	    		$.each( ret, function( i ){
	    			var nsIndex = i.indexOf( $.mobile.ns );
	    			if( nsIndex == 0 ){
	    				ret[ i.substr( $.mobile.ns.length ) ] = ret[ i ];
	    			}
	    		});
	    	}
	    	//if it's a prop get, try namepaced version if prop is undefined
	    	else if( vUndef ){
	    		ret = jqd.call( this, prop );
	    		if( ret === undefined ){
	    			nsret = jqd.call( this, $.mobile.ns + prop );
	    			if( nsret !== undefined ){
	    				ret = nsret;
	    			}
	    		}
	    	}
	    	return ret;
	    }
    };

	//define vars for interal use
	var $window = $(window),
		$html = $( "html" ),
		$head = $( "head" ),

		//loading div which appears during Ajax requests
		//will not appear if $.mobile.loadingMessage is false
		$loader = $.mobile.loadingMessage ?
			$( "
" +
						"" +
						"
" + $.mobile.loadingMessage + "
" +
					"
" )
			: undefined;

	//add mobile, initial load "rendering" classes to docEl
	$html.addClass( "ui-mobile ui-mobile-rendering" );

	//define & prepend meta viewport tag, if content is defined
	$.mobile.metaViewportContent ? $( "<meta>", { name: "viewport", content: $.mobile.metaViewportContent}).prependTo( $head ) : undefined;

	//expose some core utilities
	$.extend($.mobile, {

		// turn on/off page loading message.
		pageLoading: function ( done ) {
			if ( done ) {
				$html.removeClass( "ui-loading" );
			} else {
				if( $.mobile.loadingMessage ){
					var activeBtn =$( "." + $.mobile.activeBtnClass ).first();

					$loader
						.appendTo( $.mobile.pageContainer )
						//position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
						.css( {
							top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
							activeBtn.length && activeBtn.offset().top || 100
						} );
				}

				$html.addClass( "ui-loading" );
			}
		},

		//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
		silentScroll: function( ypos ) {
			ypos = ypos || 0;
			// prevent scrollstart and scrollstop events
			$.event.special.scrollstart.enabled = false;

			setTimeout(function() {
				window.scrollTo( 0, ypos );
				$(document).trigger( "silentscroll", { x: 0, y: ypos });
			},20);

			setTimeout(function() {
				$.event.special.scrollstart.enabled = true;
			}, 150 );
		},

		// find and enhance the pages in the dom and transition to the first page.
		initializePage: function(){
			//find present pages
			var $pages = $( "[data-" + $.mobile.ns + "role='page']" );

			//add dialogs, set data-url attrs
			$pages.add( "[data-" + $.mobile.ns + "role='dialog']" ).each(function(){
				$(this).attr( "data-" + $.mobile.ns + "url", $(this).attr( "id" ));
			});

			//define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
			$.mobile.firstPage = $pages.first();

			//define page container
			$.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );

			//cue page loading message
			$.mobile.pageLoading();

			// if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
			if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
				$.mobile.changePage( $.mobile.firstPage, false, true, false, true );
			}
			// otherwise, trigger a hashchange to load a deeplink
			else {
				$window.trigger( "hashchange", [ true ] );
			}
		}
	});

	//dom-ready inits
	$($.mobile.initializePage);

	//window load event
	//hide iOS browser chrome on load
	$window.load( $.mobile.silentScroll );
})( jQuery, this );
<|endoftext|>