<commit_before>angular.module('jnGrid', [])

  .factory('syncService', [function() {
    function get(url) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url, false);
      xhr.send(null);
      return xhr.responseText;
    }

    return {
      get: get
    }

  }])

  .filter('jnfilter', ['$filter', function($filter) {
    return function(value, spec) {

      if(spec) {

        var args = spec.split(/:\s/);
        var filter = $filter(args.shift());
        args.unshift(value);

        return filter.apply(null, args);
      }
      else {
        return value;
      }

    }
  }])

  //======================//
  //    Cell Directive    //
  //======================//
  .directive('jnGridCell', [function() {
    return {
      restrict: 'EA',
      requires: 'jnGrid',
      replace: true,
      scope: {
        value: '=',
        filter: '@?'
      },
      template: '{{ value | jnfilter: filter }}	',
    };
  }])

  //======================//
  //   Header Directive   //
  //======================//
  .directive('jnGridHeader', [function() {

    return {
      restrict: 'EA',
      requires: 'jnGrid',
      replace: true,
      template: '{{ column.displayName || column.field }}	',
      link: function(scope, element) {

        scope.clickFn = function() {
          if(scope.column.sortable) {
            if(scope.$parent.sortCol === scope.column.field) {
              scope.$parent.sortDir = !scope.$parent.sortDir;
            }
            else {

              var selector = '.th-' + scope.$parent.$id + '.sorted';

              angular.element(document.querySelector(selector)).removeClass('sorted');
              element.addClass('sorted');
              scope.$parent.sortCol = scope.column.field;
              scope.$parent.sortDir = false;
            }

            element.removeClass('sort-' + !scope.$parent.sortDir);
            element.addClass('sort-' + scope.$parent.sortDir);
          }
        };
      }
    };

  }])

  //======================//
  //     Row Directive    //
  //======================//
  .directive('jnGridRow', ['$compile', '$rootScope', function($compile, $rootScope) {

    function createAccordion(scope, element, template) {
      var accordion;

      if(template) {

        template(scope, function(el) {
          accordion = el;
          element.after(el);
          element.addClass('clickable');
        });

      }

      element.bind('click', function() { selectRow(scope, element, accordion); });
    }

    function selectRow(scope, element, accordion) {

      if(scope.options.enableRowSelection) {
        // TODO !scope.options.selectByCheckboxOnly
        if(scope.options.selected.rows.indexOf(scope.row) > -1) {
          deselect();
        }
        else {
          select();
        }
      }

      function select() {
        if(scope.options.multiSelect) {
          scope.options.selected.rows.push(scope.row);
        }
        else {
          scope.options.selected.rows[0] = scope.row;

          var parent = element.parent();

          angular.element(parent[0].querySelector('jn-grid-row.selected')).removeClass('selected');
          angular.element(parent[0].querySelector('.jnAccordion.selected')).removeClass('selected');
        }

        element.addClass('selected');

        if(accordion) {
          accordion.addClass('selected');
        }

        scope.options.selected.item = scope.row;
        scope.$emit('jnRowSelect', scope.options.id, scope.row);
      }

      function deselect() {
        if(scope.options.multiSelect) {
          var idx = scope.options.selected.rows.indexOf(scope.row);
          if(idx > -1) {
            scope.options.selected.rows.splice(idx, 1);
          }
        }
        else {
          scope.options.selected.rows[0] = undefined;
        }

        element.removeClass('selected');

        if(accordion) {
          accordion.removeClass('selected');
        }

        scope.options.selected.item = undefined;
        scope.$emit('jnRowDeselect', scope.options.id, scope.row);
      }

      if(accordion) {
        if(scope.options.showAccordionFn) {
          scope.options.showAccordionFn(scope.row);
        }
        else {
          scope.row.show = !scope.row.show;
        }

        scope.$apply();
      }

    }

    function createCells(scope, element) {
      var cols = scope.options.columns;
      for(var i in cols) {
        element.append($compile('

')(scope));
      }
    }

    return {
      restrict: 'EA',
      requires: 'jnGrid',

      link: function(scope, element) {
        var row = scope.row;
        row.show = false;

        scope.$watch('dataset', function() {
          createCells(scope, element);
        });

        createAccordion(scope, element, scope.options.accordion);
      }
    };
  }])

  //======================//
  //    Grid Directive    //
  //======================//
  .directive('jnGrid', ['$compile', '$templateCache', 'syncService', function($compile, $templateCache, sync) {

    function getRemoteTemplate(url) {
      var template = sync.get(url);
      $templateCache.put(url, template);
      return template;
    }

    function createAccordionTemplate(scope) {

      if(scope.options.accordionUrl) {
        scope.options.accordion = $templateCache.get(scope.options.accordionUrl) || getRemoteTemplate(scope.options.accordionUrl);
      }

      if(scope.options.accordion) {
        var el = angular.element('' + scope.options.accordion + '	');

        el.addClass('jnAccordion');
        el.attr('colspan', scope.options.columns.length);
        el.attr('ng-class', '{ jnRowEven: $even, jnRowOdd: $odd }');
        el.attr('ng-show', 'row.show');

        scope.options.accordion = $compile(el);
      }
    }

    function defaultProperties(scope) {
      for(var i in PROPERTIES) {
        var prop = PROPERTIES[i];

        if(scope.options[prop.property] === undefined || scope.options[prop.property] === null) {
          scope.options[prop.property] = prop.default;
        }
      }
    }

    function createColumns(scope) {
      var IGNORED_PROPERTIES = [ '$$hashKey', 'clicked', 'show' ];

      if(scope.dataset && scope.dataset.length > 0) {
        if(!scope.options.columns) {
          scope.options.columns = [];
          var temp = Object.keys(scope.dataset[0]);

          for(var i in temp) {
            var key = temp[i];

            if(IGNORED_PROPERTIES.indexOf(key) === -1) {
              scope.options.columns.push({ field: key });
            }
          }
        }
      }
    }

    var PROPERTIES = [
      { property: 'enableRowSelection', default: true },
      { property: 'selectByCheckboxOnly', default: false },
      { property: 'enableCheckbox', default:false },
      { property: 'multiSelect', default:false }
    ];

    return {
      restrict: 'EA',
      scope: {
        dataset: '=',
        options: '=?',
      },
      template: '
'+
                  '
<jn-grid-header ng-repeat="column in options.columns"></jn-grid-header>
'+
                  '<jn-grid-row '+
                      'ng-class="{ jnRowEven: $even, jnRowOdd: $odd }"' +
                      'ng-repeat="row in dataset | orderBy:sortCol:sortDir">' +
                  '</jn-grid-row>'+
                '
',
      link: function(scope) {
        scope.options = scope.options || {}

        defaultProperties(scope);

        scope.options.selected = {};
        scope.options.selected.rows = [];

        if(!scope.options.columns) {
          scope.$watch('dataset', function() {
            createColumns(scope);
          });
        }

        createColumns(scope);
        createAccordionTemplate(scope);
      }
    }
  }]);
<commit_msg>Added select by checkbox functionalilty<commit_after>angular.module('jnGrid', [])

.run(['$templateCache', function($templateCache) {
  $templateCache.put('jnGrid.html',
    '
'+
      '
' +
        '<jn-grid-header ng-repeat="column in options.columns"></jn-grid-header>' +
      '
' +
      '<jn-grid-row '+
        'ng-class="{ jnRowEven: $even, jnRowOdd: $odd }"' +
        'ng-repeat="row in dataset | orderBy:sortCol:sortDir">' +
      '</jn-grid-row>'+
    '
');
}])

.factory('syncService', [function() {
  function get(url) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, false);
    xhr.send(null);
    return xhr.responseText;
  }

  return {
    get: get
  }

}])

.filter('jnfilter', ['$filter', function($filter) {
  return function(value, spec) {

    if(spec) {

      var args = spec.split(/:\s/);
      var filter = $filter(args.shift());
      args.unshift(value);

      return filter.apply(null, args);
    }
    else {
      return value;
    }

  }
}])

//======================//
//    Cell Directive    //
//======================//
.directive('jnGridCell', [function() {
  return {
    restrict: 'EA',
    requires: 'jnGrid',
    replace: true,
    scope: {
      value: '=',
      filter: '@?'
    },
    template: '{{ value | jnfilter: filter }}	',
  };
}])

//======================//
//   Header Directive   //
//======================//
.directive('jnGridHeader', [function() {

  return {
    restrict: 'EA',
    requires: 'jnGrid',
    replace: true,
    template: '{{ column.displayName || column.field }}	',
    link: function(scope, element) {

      if(scope.$first && scope.options.enableCheckbox) {
        element.parent().prepend('	');
      }

      scope.clickFn = function() {
        if(scope.column.sortable) {
          if(scope.$parent.sortCol === scope.column.field) {
            scope.$parent.sortDir = !scope.$parent.sortDir;
          }
          else {

            var selector = '.th-' + scope.$parent.$id + '.sorted';

            angular.element(document.querySelector(selector)).removeClass('sorted');
            element.addClass('sorted');
            scope.$parent.sortCol = scope.column.field;
            scope.$parent.sortDir = false;
          }

          element.removeClass('sort-' + !scope.$parent.sortDir);
          element.addClass('sort-' + scope.$parent.sortDir);
        }
      };
    }
  };

}])

//======================//
//     Row Directive    //
//======================//
.directive('jnGridRow', ['$compile', '$rootScope', function($compile, $rootScope) {

  function createAccordion(scope, element, template) {

    var accordion;

    if(template) {

      template(scope, function(el) {
        accordion = el;
        element.after(el);
        element.addClass('clickable');
      });

    }

    return accordion;

  }

  var selector = function(scope, element, accordion) {

    function select() {

      var CHECKBOX = element[0].querySelector('input[type="checkbox"]');

      if(scope.options.multiSelect) {
        scope.options.selected.rows.push(scope.row);
      }
      else {
        scope.options.selected.rows[0] = scope.row;

        var parent = element.parent();

        angular.element(parent[0].querySelector('jn-grid-row.selected')).removeClass('selected');
        angular.element(parent[0].querySelector('.jnAccordion.selected')).removeClass('selected');

        if(CHECKBOX) {
          checkboxes = parent[0].querySelectorAll('input[type="checkbox"]');

          for(i in checkboxes) {
            if(checkboxes[i] !== CHECKBOX) {
              checkboxes[i].checked = false;
            }
          }

        }
      }

      element.addClass('selected');

      if(CHECKBOX && CHECKBOX.checked === false) {
        CHECKBOX.checked = true;
      }

      if(accordion) {
        accordion.addClass('selected');
      }

      scope.options.selected.item = scope.row;
      scope.$emit('jnRowSelect', scope.options.id, scope.row);
    }

    function deselect() {

      if(scope.options.multiSelect) {
        var idx = scope.options.selected.rows.indexOf(scope.row);
        if(idx > -1) {
          scope.options.selected.rows.splice(idx, 1);
        }
      }
      else {
        scope.options.selected.rows[0] = undefined;
      }

      element.removeClass('selected');

      if(accordion) {
        accordion.removeClass('selected');
      }

      scope.options.selected.item = undefined;
      scope.$emit('jnRowDeselect', scope.options.id, scope.row);
    }

    return {
      selectFn: function(checkbox, event) {

        if(checkbox === true) {
          event.stopPropagation();
        }

        if(scope.options.enableRowSelection) {
          if(!scope.options.selectByCheckboxOnly || checkbox === true) {

            if(scope.options.selected.rows.indexOf(scope.row) > -1) {
              deselect(checkbox);
            }
            else {
              select(checkbox);
            }
          }
        }

        if(accordion) {
          if(scope.options.showAccordionFn) {
            scope.options.showAccordionFn(scope.row);
          }
          else {
            scope.row.show = !scope.row.show;
          }

          setTimeout(function() { scope.$apply(); }, 0);

        }
      }
    }
  }

  function createCells(scope, element) {
    var cols = scope.options.columns;

    if(scope.options.enableCheckbox) {
      element.append($compile('<input type="checkbox" ng-click="selectRow(true, $event)"/>	')(scope));
    }

    for(var i in cols) {
      element.append($compile('

')(scope));
    }
  }

  return {
    restrict: 'EA',
    requires: 'jnGrid',

    link: function(scope, element) {
      var row = scope.row;
      row.show = false;

      scope.$watch('dataset', function() {
        createCells(scope, element);
      });

      var accordion = createAccordion(scope, element, scope.options.accordion);
      scope.selectRow = selector(scope, element, accordion).selectFn;

      element.bind('click', scope.selectRow);

    }
  };

}])

//======================//
//    Grid Directive    //
//======================//
.directive('jnGrid', ['$compile', '$templateCache', 'syncService', function($compile, $templateCache, sync) {

  function getRemoteTemplate(url) {
    var template = sync.get(url);
    $templateCache.put(url, template);
    return template;
  }

  function createAccordionTemplate(scope) {

    if(scope.options.accordionUrl) {
      scope.options.accordion = $templateCache.get(scope.options.accordionUrl) || getRemoteTemplate(scope.options.accordionUrl);
    }

    if(scope.options.accordion) {
      var el = angular.element('' + scope.options.accordion + '	');

      el.addClass('jnAccordion');
      el.attr('colspan', scope.options.columns.length + (scope.options.enableCheckbox ? 1 : 0));
      el.attr('ng-class', '{ jnRowEven: $even, jnRowOdd: $odd }');
      el.attr('ng-show', 'row.show');

      scope.options.accordion = $compile(el);
    }
  }

  function defaultProperties(scope) {
    for(var i in PROPERTIES) {
      var prop = PROPERTIES[i];

      if(scope.options[prop.property] === undefined || scope.options[prop.property] === null) {
        scope.options[prop.property] = prop.default;
      }
    }
  }

  function createColumns(scope) {
    var IGNORED_PROPERTIES = [ '$$hashKey', 'clicked', 'show' ];

    if(scope.dataset && scope.dataset.length > 0) {
      if(!scope.options.columns) {
        scope.options.columns = [];
        var temp = Object.keys(scope.dataset[0]);

        for(var i in temp) {
          var key = temp[i];

          if(IGNORED_PROPERTIES.indexOf(key) === -1) {
            scope.options.columns.push({ field: key });
          }
        }
      }
    }
  }

  var PROPERTIES = [
    { property: 'enableRowSelection', default: true },
    { property: 'selectByCheckboxOnly', default: false },
    { property: 'enableCheckbox', default:false },
    { property: 'multiSelect', default:false }
  ];

  return {
    restrict: 'EA',
    scope: {
      dataset: '=',
      options: '=?',
    },
    templateUrl: 'jnGrid.html',
    link: function(scope) {
      scope.options = scope.options || {}

      defaultProperties(scope);

      scope.options.selected = {};
      scope.options.selected.rows = [];

      if(!scope.options.columns) {
        scope.$watch('dataset', function() {
          createColumns(scope);
        });
      }

      createColumns(scope);
      createAccordionTemplate(scope);
    }
  };

}]);
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: See license.txt

frappe.provide("frappe.activity");

frappe.pages['activity'].on_page_load = function(wrapper) {
	var me = this;

	frappe.ui.make_app_page({
		parent: wrapper,
		single_column: true
	});

	me.page = wrapper.page;
	me.page.set_title(__("Activity"));

	frappe.model.with_doctype("Communication", function() {
		me.page.list = new frappe.views.Activity({
			doctype: 'Communication',
			parent: wrapper
		});
	});

	frappe.activity.render_heatmap(me.page);

	me.page.main.on("click", ".activity-message", function() {
		var link_doctype = $(this).attr("data-link-doctype"),
			link_name = $(this).attr("data-link-name"),
			doctype = $(this).attr("data-doctype"),
			docname = $(this).attr("data-docname");

		var [link_doctype, link_name, doctype, docname] =
			[link_doctype, link_name, doctype, docname].map(decodeURIComponent);

		link_doctype = link_doctype && link_doctype !== 'null' ? link_doctype : null;
		link_name = link_name && link_name !== 'null' ? link_name : null;

		if (doctype && docname) {
			if (link_doctype && link_name) {
				frappe.route_options = {
					scroll_to: { "doctype": doctype, "name": docname }
				}
			}

			frappe.set_route(["Form", link_doctype || doctype, link_name || docname]);
		}
	});

	// Build Report Button
	if(frappe.boot.user.can_get_report.indexOf("Feed")!=-1) {
		this.page.add_menu_item(__('Build Report'), function() {
			frappe.set_route("List", "Feed", "Report");
		}, 'fa fa-th')
	}

	this.page.add_menu_item(__('Activity Log'), function() {
		frappe.route_options = {
			"user": frappe.session.user
		}

		frappe.set_route("List", "Activity Log", "Report");
	}, 'fa fa-th');
};

frappe.pages['activity'].on_page_show = function() {
	frappe.breadcrumbs.add("Desk");
}

frappe.activity.last_feed_date = false;
frappe.activity.Feed = Class.extend({
	init: function(row, data) {
		this.scrub_data(data);
		this.add_date_separator(row, data);
		if(!data.add_class)
			data.add_class = "label-default";

		data.link = "";
		if (data.link_doctype && data.link_name) {
			data.link = frappe.format(data.link_name, {fieldtype: "Link", options: data.link_doctype},
				{label: __(data.link_doctype) + " " + __(data.link_name)});

		} else if (data.feed_type==="Comment" && data.comment_type==="Comment") {
			// hack for backward compatiblity
			data.link_doctype = data.reference_doctype;
			data.link_name = data.reference_name;
			data.reference_doctype = "Communication";
			data.reference_name = data.name;

			data.link = frappe.format(data.link_name, {fieldtype: "Link", options: data.link_doctype},
				{label: __(data.link_doctype) + " " + __(data.link_name)});

		} else if (data.reference_doctype && data.reference_name) {
			data.link = frappe.format(data.reference_name, {fieldtype: "Link", options: data.reference_doctype},
				{label: __(data.reference_doctype) + " " + __(data.reference_name)});
		}

		$(row)
			.append(frappe.render_template("activity_row", data))
			.find("a").addClass("grey");
	},
	scrub_data: function(data) {
		data.by = frappe.user.full_name(data.owner);
		data.avatar = frappe.avatar(data.owner);

		data.icon = "fa fa-flag";

		// color for comment
		data.add_class = {
			"Comment": "label-danger",
			"Assignment": "label-warning",
			"Login": "label-default"
		}[data.comment_type || data.communication_medium] || "label-info"

		data.when = comment_when(data.creation);
		data.feed_type = data.comment_type || data.communication_medium;
	},
	add_date_separator: function(row, data) {
		var date = frappe.datetime.str_to_obj(data.creation);
		var last = frappe.activity.last_feed_date;

		if((last && frappe.datetime.obj_to_str(last) != frappe.datetime.obj_to_str(date)) || (!last)) {
			var diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date));
			var pdate;
			if(diff < 1) {
				pdate = 'Today';
			} else if(diff < 2) {
				pdate = 'Yesterday';
			} else {
				pdate = frappe.datetime.global_date_format(date);
			}
			data.date_sep = pdate;
			data.date_class = pdate=='Today' ? "date-indicator blue" : "date-indicator";
		} else {
			data.date_sep = null;
			data.date_class = "";
		}
		frappe.activity.last_feed_date = date;
	}
});

frappe.activity.render_heatmap = function(page) {
	var me = this;
	$('
\

\

').prependTo(page.main);

	frappe.call({
		method: "frappe.desk.page.activity.activity.get_heatmap_data",
		callback: function(r) {
			if(r.message) {
				var heatmap = new frappe.Chart(".heatmap", {
					type: 'heatmap',
					start: new Date(moment().subtract(1, 'year').toDate()),
					countLabel: "actions",
					discreteDomains: 0,
					data: {}
				});

				heatmap.update(r.message);
			}
		}
	})
}

frappe.views.Activity = class Activity extends frappe.views.BaseList {
	constructor(opts) {
		super(opts);
		this.show();
	}

	setup_defaults() {
		super.setup_defaults();

		this.page_title = __('Activity');
		this.doctype = 'Communication';
		this.method = 'frappe.desk.page.activity.activity.get_feed';

	}

	setup_filter_area() {
		//
	}

	setup_sort_selector() {

	}

	setup_side_bar() {

	}

	get_args() {
		return {
			start: this.start,
			page_length: this.page_length
		};
	}

	update_data(r) {
		let data = r.message || [];

		if (this.start === 0) {
			this.data = data;
		} else {
			this.data = this.data.concat(data);
		}
	}

	render() {
		this.data.map(value => {
			const row = $('
').data("data", value).appendTo(this.$result).get(0);
			new frappe.activity.Feed(row, value);
		});
	}
};
<commit_msg>fix: Remove declaration<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: See license.txt

frappe.provide("frappe.activity");

frappe.pages['activity'].on_page_load = function(wrapper) {
	var me = this;

	frappe.ui.make_app_page({
		parent: wrapper,
		single_column: true
	});

	me.page = wrapper.page;
	me.page.set_title(__("Activity"));

	frappe.model.with_doctype("Communication", function() {
		me.page.list = new frappe.views.Activity({
			doctype: 'Communication',
			parent: wrapper
		});
	});

	frappe.activity.render_heatmap(me.page);

	me.page.main.on("click", ".activity-message", function() {
		var link_doctype = $(this).attr("data-link-doctype"),
			link_name = $(this).attr("data-link-name"),
			doctype = $(this).attr("data-doctype"),
			docname = $(this).attr("data-docname");

		[link_doctype, link_name, doctype, docname] =
			[link_doctype, link_name, doctype, docname].map(decodeURIComponent);

		link_doctype = link_doctype && link_doctype !== 'null' ? link_doctype : null;
		link_name = link_name && link_name !== 'null' ? link_name : null;

		if (doctype && docname) {
			if (link_doctype && link_name) {
				frappe.route_options = {
					scroll_to: { "doctype": doctype, "name": docname }
				}
			}

			frappe.set_route(["Form", link_doctype || doctype, link_name || docname]);
		}
	});

	// Build Report Button
	if(frappe.boot.user.can_get_report.indexOf("Feed")!=-1) {
		this.page.add_menu_item(__('Build Report'), function() {
			frappe.set_route("List", "Feed", "Report");
		}, 'fa fa-th')
	}

	this.page.add_menu_item(__('Activity Log'), function() {
		frappe.route_options = {
			"user": frappe.session.user
		}

		frappe.set_route("List", "Activity Log", "Report");
	}, 'fa fa-th');
};

frappe.pages['activity'].on_page_show = function() {
	frappe.breadcrumbs.add("Desk");
}

frappe.activity.last_feed_date = false;
frappe.activity.Feed = Class.extend({
	init: function(row, data) {
		this.scrub_data(data);
		this.add_date_separator(row, data);
		if(!data.add_class)
			data.add_class = "label-default";

		data.link = "";
		if (data.link_doctype && data.link_name) {
			data.link = frappe.format(data.link_name, {fieldtype: "Link", options: data.link_doctype},
				{label: __(data.link_doctype) + " " + __(data.link_name)});

		} else if (data.feed_type==="Comment" && data.comment_type==="Comment") {
			// hack for backward compatiblity
			data.link_doctype = data.reference_doctype;
			data.link_name = data.reference_name;
			data.reference_doctype = "Communication";
			data.reference_name = data.name;

			data.link = frappe.format(data.link_name, {fieldtype: "Link", options: data.link_doctype},
				{label: __(data.link_doctype) + " " + __(data.link_name)});

		} else if (data.reference_doctype && data.reference_name) {
			data.link = frappe.format(data.reference_name, {fieldtype: "Link", options: data.reference_doctype},
				{label: __(data.reference_doctype) + " " + __(data.reference_name)});
		}

		$(row)
			.append(frappe.render_template("activity_row", data))
			.find("a").addClass("grey");
	},
	scrub_data: function(data) {
		data.by = frappe.user.full_name(data.owner);
		data.avatar = frappe.avatar(data.owner);

		data.icon = "fa fa-flag";

		// color for comment
		data.add_class = {
			"Comment": "label-danger",
			"Assignment": "label-warning",
			"Login": "label-default"
		}[data.comment_type || data.communication_medium] || "label-info"

		data.when = comment_when(data.creation);
		data.feed_type = data.comment_type || data.communication_medium;
	},
	add_date_separator: function(row, data) {
		var date = frappe.datetime.str_to_obj(data.creation);
		var last = frappe.activity.last_feed_date;

		if((last && frappe.datetime.obj_to_str(last) != frappe.datetime.obj_to_str(date)) || (!last)) {
			var diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date));
			var pdate;
			if(diff < 1) {
				pdate = 'Today';
			} else if(diff < 2) {
				pdate = 'Yesterday';
			} else {
				pdate = frappe.datetime.global_date_format(date);
			}
			data.date_sep = pdate;
			data.date_class = pdate=='Today' ? "date-indicator blue" : "date-indicator";
		} else {
			data.date_sep = null;
			data.date_class = "";
		}
		frappe.activity.last_feed_date = date;
	}
});

frappe.activity.render_heatmap = function(page) {
	var me = this;
	$('
\

\

').prependTo(page.main);

	frappe.call({
		method: "frappe.desk.page.activity.activity.get_heatmap_data",
		callback: function(r) {
			if(r.message) {
				var heatmap = new frappe.Chart(".heatmap", {
					type: 'heatmap',
					start: new Date(moment().subtract(1, 'year').toDate()),
					countLabel: "actions",
					discreteDomains: 0,
					data: {}
				});

				heatmap.update(r.message);
			}
		}
	})
}

frappe.views.Activity = class Activity extends frappe.views.BaseList {
	constructor(opts) {
		super(opts);
		this.show();
	}

	setup_defaults() {
		super.setup_defaults();

		this.page_title = __('Activity');
		this.doctype = 'Communication';
		this.method = 'frappe.desk.page.activity.activity.get_feed';

	}

	setup_filter_area() {
		//
	}

	setup_sort_selector() {

	}

	setup_side_bar() {

	}

	get_args() {
		return {
			start: this.start,
			page_length: this.page_length
		};
	}

	update_data(r) {
		let data = r.message || [];

		if (this.start === 0) {
			this.data = data;
		} else {
			this.data = this.data.concat(data);
		}
	}

	render() {
		this.data.map(value => {
			const row = $('
').data("data", value).appendTo(this.$result).get(0);
			new frappe.activity.Feed(row, value);
		});
	}
};
<|endoftext|>


<commit_before>frappe.provide("frappe.ui.form");

frappe.ui.form.PrintPreview = Class.extend({
	init: function(opts) {
		$.extend(this, opts);
		this.make();
		this.bind_events();
	},
	make: function() {
		this.wrapper = this.frm.page.add_view("print", frappe.render_template("print_layout", {}));

		// only system manager can edit
		this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager"));
	},
	bind_events: function() {
		var me = this;
		this.wrapper.find(".btn-print-close").click(function() {
			me.frm.hide_print();
		});

		// hide print view on pressing escape, only if there is no focus on any input
		$(document).on("keydown", function(e) {
			if (e.which===27 && me.frm && e.target===document.body) {
				me.frm.hide_print();
			}
		});

		this.print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
		this.print_letterhead = this.wrapper
			.find(".print-letterhead")
			.on("change", function() { me.print_sel.trigger("change"); })
			.prop("checked", cint(
				(frappe.model.get_doc(":Print Settings", "Print Settings")
					|| {with_letterhead: 1}).with_letterhead) ? true : false);
		this.print_sel = this.wrapper
			.find(".print-preview-select")
			.on("change", function() {
				me.multilingual_preview()
			});

		//On selection of language get code and pass it to preview method
		this.language_sel = this.wrapper
			.find(".languages")
			.on("change", function(){
				me.lang_code = me.language_sel.val()
				me.multilingual_preview()
			});

		this.wrapper.find(".btn-print-print").click(function() {
			if(me.is_old_style()) {
				me.print_old_style();
			} else {
				me.printit();
			}
		});

		this.wrapper.find(".btn-print-preview").click(function() {
			if(me.is_old_style()) {
				me.new_page_preview_old_style();
			} else {
				me.new_page_preview();
			}
		});

		this.wrapper.find(".btn-download-pdf").click(function() {
			if(!me.is_old_style()) {
				var w = window.open("/api/method/frappe.templates.pages.print.download_pdf?"
					+"doctype="+encodeURIComponent(me.frm.doc.doctype)
					+"&name="+encodeURIComponent(me.frm.doc.name)
					+"&format="+me.selected_format()
					+"&no_letterhead="+(me.with_letterhead() ? "0" : "1")
					+(me.lang_code ? ("&_lang="+me.lang_code) : ""));
				if(!w) {
					msgprint(__("Please enable pop-ups")); return;
				}
			}
		});

		this.wrapper.find(".btn-print-edit").on("click", function() {
			var print_format = me.get_print_format();
			if(print_format && print_format.name) {
				if(print_format.print_format_builder) {
					frappe.route_options = {"doc": print_format, "make_new": false};
					frappe.set_route("print-format-builder");
				} else {
					frappe.set_route("Form", "Print Format", print_format.name);
				}
			} else {
				// start a new print format
				frappe.prompt({fieldname:"print_format_name", fieldtype:"Data", reqd: 1,
					label:"New Print Format Name"}, function(data) {
						frappe.route_options = {
							make_new: true,
							doctype: me.frm.doctype,
							name: data.print_format_name
						};
						frappe.set_route("print-format-builder");
				}, __("New Custom Print Format"), __("Start"));
			}
		});
	},
	set_user_lang: function(){
		this.lang_code = this.frm.doc.language;
		// Load all languages in the field
		this.language_sel.empty()
			.add_options(frappe.get_languages())
			.val(this.lang_code);
		this.preview();
	},
	multilingual_preview: function(){
		var me = this;
		if(this.is_old_style()) {
			me.wrapper.find(".btn-download-pdf").toggle(false);
			me.set_style();
			me.preview_old_style();
		} else {
			me.wrapper.find(".btn-download-pdf").toggle(true);
			me.preview();
		}
	},
	preview: function() {
		var me = this;
		this.get_print_html(function(out) {
			me.wrapper.find(".print-format").html(out.html);
			me.set_style(out.style);
		});
	},
	printit: function() {
		this.new_page_preview(true);
	},
	new_page_preview: function(printit) {
		var me = this;
		var w = window.open("/print?"
			+"doctype="+encodeURIComponent(me.frm.doc.doctype)
			+"&name="+encodeURIComponent(me.frm.doc.name)
			+(printit ? "&trigger_print=1" : "")
			+"&format="+me.selected_format()
			+"&no_letterhead="+(me.with_letterhead() ? "0" : "1")
			+(me.lang_code ? ("&_lang="+me.lang_code) : ""));
		if(!w) {
			msgprint(__("Please enable pop-ups")); return;
		}
	},
	get_print_html: function(callback) {
		frappe.call({
			method: "frappe.templates.pages.print.get_html_and_style",
			args: {
				doc: this.frm.doc,
				print_format: this.selected_format(),
				no_letterhead: !this.with_letterhead() ? 1 : 0,
				_lang: this.lang_code
			},
			callback: function(r) {
				if(!r.exc) {
					callback(r.message);
				}
			}
		});
	},
	preview_old_style: function() {
		var me = this;
		this.with_old_style({
			format: me.print_sel.val(),
			callback: function(html) {
				me.wrapper.find(".print-format").html('
'
					+__("Warning: This Print Format is in old style and cannot be generated via the API.")
					+'
'
					+ html);
			},
			no_letterhead: !this.with_letterhead(),
			only_body: true,
			no_heading: true
		});
	},
	refresh_print_options: function() {
		this.print_formats = frappe.meta.get_print_formats(this.frm.doctype);
		return this.print_sel
			.empty().add_options(this.print_formats);
	},
	with_old_style: function(opts) {
		var me = this;
		frappe.require("/assets/js/print_format_v3.min.js");
		_p.build(opts.format, opts.callback, opts.no_letterhead, opts.only_body, opts.no_heading);
	},
	print_old_style: function() {
		frappe.require("/assets/js/print_format_v3.min.js");
		_p.build(this.print_sel.val(), _p.go,
			!this.with_letterhead());
	},
	new_page_preview_old_style: function() {
		frappe.require("/assets/js/print_format_v3.min.js");
		_p.build(this.print_sel.val(), _p.preview,
			!this.with_letterhead());
	},
	selected_format: function() {
		return this.print_sel.val() || this.frm.meta.default_print_format || "Standard";
	},
	is_old_style: function(format) {
		return this.get_print_format(format).print_format_type==="Client";
	},
	get_print_format: function(format) {
		if (!format) {
			format = this.selected_format();
		}

		if(locals["Print Format"] && locals["Print Format"][format]) {
			return locals["Print Format"][format]
		} else {
			return {}
		}
	},
	with_letterhead: function() {
		return this.print_letterhead.is(":checked") ? 1 : 0;
	},
	set_style: function(style) {
		frappe.dom.set_style(style || frappe.boot.print_css, "print-style");
	}
})
<commit_msg>[fix] use full-urls for print for mobile app, fixes frappe/erpnext#5030<commit_after>frappe.provide("frappe.ui.form");

frappe.ui.form.PrintPreview = Class.extend({
	init: function(opts) {
		$.extend(this, opts);
		this.make();
		this.bind_events();
	},
	make: function() {
		this.wrapper = this.frm.page.add_view("print", frappe.render_template("print_layout", {}));

		// only system manager can edit
		this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager"));
	},
	bind_events: function() {
		var me = this;
		this.wrapper.find(".btn-print-close").click(function() {
			me.frm.hide_print();
		});

		// hide print view on pressing escape, only if there is no focus on any input
		$(document).on("keydown", function(e) {
			if (e.which===27 && me.frm && e.target===document.body) {
				me.frm.hide_print();
			}
		});

		this.print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
		this.print_letterhead = this.wrapper
			.find(".print-letterhead")
			.on("change", function() { me.print_sel.trigger("change"); })
			.prop("checked", cint(
				(frappe.model.get_doc(":Print Settings", "Print Settings")
					|| {with_letterhead: 1}).with_letterhead) ? true : false);
		this.print_sel = this.wrapper
			.find(".print-preview-select")
			.on("change", function() {
				me.multilingual_preview()
			});

		//On selection of language get code and pass it to preview method
		this.language_sel = this.wrapper
			.find(".languages")
			.on("change", function(){
				me.lang_code = me.language_sel.val()
				me.multilingual_preview()
			});

		this.wrapper.find(".btn-print-print").click(function() {
			if(me.is_old_style()) {
				me.print_old_style();
			} else {
				me.printit();
			}
		});

		this.wrapper.find(".btn-print-preview").click(function() {
			if(me.is_old_style()) {
				me.new_page_preview_old_style();
			} else {
				me.new_page_preview();
			}
		});

		this.wrapper.find(".btn-download-pdf").click(function() {
			if(!me.is_old_style()) {
				var w = window.open(
					frappe.urllib.get_full_url("/api/method/frappe.templates.pages.print.download_pdf?"
					+"doctype="+encodeURIComponent(me.frm.doc.doctype)
					+"&name="+encodeURIComponent(me.frm.doc.name)
					+"&format="+me.selected_format()
					+"&no_letterhead="+(me.with_letterhead() ? "0" : "1")
					+(me.lang_code ? ("&_lang="+me.lang_code) : "")));
				if(!w) {
					msgprint(__("Please enable pop-ups")); return;
				}
			}
		});

		this.wrapper.find(".btn-print-edit").on("click", function() {
			var print_format = me.get_print_format();
			if(print_format && print_format.name) {
				if(print_format.print_format_builder) {
					frappe.route_options = {"doc": print_format, "make_new": false};
					frappe.set_route("print-format-builder");
				} else {
					frappe.set_route("Form", "Print Format", print_format.name);
				}
			} else {
				// start a new print format
				frappe.prompt({fieldname:"print_format_name", fieldtype:"Data", reqd: 1,
					label:"New Print Format Name"}, function(data) {
						frappe.route_options = {
							make_new: true,
							doctype: me.frm.doctype,
							name: data.print_format_name
						};
						frappe.set_route("print-format-builder");
				}, __("New Custom Print Format"), __("Start"));
			}
		});
	},
	set_user_lang: function(){
		this.lang_code = this.frm.doc.language;
		// Load all languages in the field
		this.language_sel.empty()
			.add_options(frappe.get_languages())
			.val(this.lang_code);
		this.preview();
	},
	multilingual_preview: function(){
		var me = this;
		if(this.is_old_style()) {
			me.wrapper.find(".btn-download-pdf").toggle(false);
			me.set_style();
			me.preview_old_style();
		} else {
			me.wrapper.find(".btn-download-pdf").toggle(true);
			me.preview();
		}
	},
	preview: function() {
		var me = this;
		this.get_print_html(function(out) {
			me.wrapper.find(".print-format").html(out.html);
			me.set_style(out.style);
		});
	},
	printit: function() {
		this.new_page_preview(true);
	},
	new_page_preview: function(printit) {
		var me = this;
		var w = window.open(frappe.urllib.get_full_url("/print?"
			+"doctype="+encodeURIComponent(me.frm.doc.doctype)
			+"&name="+encodeURIComponent(me.frm.doc.name)
			+(printit ? "&trigger_print=1" : "")
			+"&format="+me.selected_format()
			+"&no_letterhead="+(me.with_letterhead() ? "0" : "1")
			+(me.lang_code ? ("&_lang="+me.lang_code) : "")));
		if(!w) {
			msgprint(__("Please enable pop-ups")); return;
		}
	},
	get_print_html: function(callback) {
		frappe.call({
			method: "frappe.templates.pages.print.get_html_and_style",
			args: {
				doc: this.frm.doc,
				print_format: this.selected_format(),
				no_letterhead: !this.with_letterhead() ? 1 : 0,
				_lang: this.lang_code
			},
			callback: function(r) {
				if(!r.exc) {
					callback(r.message);
				}
			}
		});
	},
	preview_old_style: function() {
		var me = this;
		this.with_old_style({
			format: me.print_sel.val(),
			callback: function(html) {
				me.wrapper.find(".print-format").html('
'
					+__("Warning: This Print Format is in old style and cannot be generated via the API.")
					+'
'
					+ html);
			},
			no_letterhead: !this.with_letterhead(),
			only_body: true,
			no_heading: true
		});
	},
	refresh_print_options: function() {
		this.print_formats = frappe.meta.get_print_formats(this.frm.doctype);
		return this.print_sel
			.empty().add_options(this.print_formats);
	},
	with_old_style: function(opts) {
		var me = this;
		frappe.require("/assets/js/print_format_v3.min.js");
		_p.build(opts.format, opts.callback, opts.no_letterhead, opts.only_body, opts.no_heading);
	},
	print_old_style: function() {
		frappe.require("/assets/js/print_format_v3.min.js");
		_p.build(this.print_sel.val(), _p.go,
			!this.with_letterhead());
	},
	new_page_preview_old_style: function() {
		frappe.require("/assets/js/print_format_v3.min.js");
		_p.build(this.print_sel.val(), _p.preview,
			!this.with_letterhead());
	},
	selected_format: function() {
		return this.print_sel.val() || this.frm.meta.default_print_format || "Standard";
	},
	is_old_style: function(format) {
		return this.get_print_format(format).print_format_type==="Client";
	},
	get_print_format: function(format) {
		if (!format) {
			format = this.selected_format();
		}

		if(locals["Print Format"] && locals["Print Format"][format]) {
			return locals["Print Format"][format]
		} else {
			return {}
		}
	},
	with_letterhead: function() {
		return this.print_letterhead.is(":checked") ? 1 : 0;
	},
	set_style: function(style) {
		frappe.dom.set_style(style || frappe.boot.print_css, "print-style");
	}
})
<|endoftext|>


<commit_before>;(function(){
    'use strict';
    var modalCtrl = function($scope, $uibModalInstance, $http, messageParts){
        $scope.modalTitle = messageParts.title;
        $scope.modalHeading = messageParts.heading;
        $scope.message = messageParts.message;
        $scope.messageTemplate = messageParts.messageTemplate;
        $scope.valid = messageParts.valid;
        $scope.buttonSet = messageParts.buttonSet;
        $scope.fields = {};

        $scope.ok = ok;
        $scope.cancel = cancel;
        $scope.dismiss = dismiss;
        $scope.submit = submit;

        // Functions
        function ok() {
            $uibModalInstance.close(true);
        }

        function cancel() {
            $uibModalInstance.close(false);
        }

        function dismiss() {
            $uibModalInstance.dismiss();
        }

        function submit() {
            console.log('Submitted');
            console.log($scope.fields);

            $http.post(
                'http://api.waypoints.local/api/bookmarks/bookmarks/',
                $scope.fields
            ).then(function success(response){
                console.log('Success');
                $scope.ok();
            }, function error(response){
                console.log('Error');
            });
        }
    };

    module.exports = modalCtrl;
})();
<commit_msg>Use env var for API URL when adding bookmarks<commit_after>;(function(){
    'use strict';
    var modalCtrl = function($scope, $uibModalInstance, $http, messageParts){
        $scope.modalTitle = messageParts.title;
        $scope.modalHeading = messageParts.heading;
        $scope.message = messageParts.message;
        $scope.messageTemplate = messageParts.messageTemplate;
        $scope.valid = messageParts.valid;
        $scope.buttonSet = messageParts.buttonSet;
        $scope.fields = {};
        $scope.apiBaseUrl = process.env.API_BASE_URL;

        $scope.ok = ok;
        $scope.cancel = cancel;
        $scope.dismiss = dismiss;
        $scope.submit = submit;

        // Functions
        function ok() {
            $uibModalInstance.close(true);
        }

        function cancel() {
            $uibModalInstance.close(false);
        }

        function dismiss() {
            $uibModalInstance.dismiss();
        }

        function submit() {
            console.log('Submitted');
            console.log($scope.fields);

            $http.post(
                $scope.apiBaseUrl + 'api/bookmarks/bookmarks/',
                $scope.fields
            ).then(function success(response){
                console.log('Success');
                $scope.ok();
            }, function error(response){
                console.log('Error');
            });
        }
    };

    module.exports = modalCtrl;
})();
<|endoftext|>


<commit_before>function greet (name) {
    var formattedOutput = `Hello, my name is ${name}`;
    console.log(formattedOutput);
}

greet('Wes');<commit_msg>templates<commit_after>function greet (name) {
    var formattedOutput = `Hello, my name is ${name}`;
    console.log(formattedOutput);
}

greet('Wes');

var string1 = 'This is line 1\n\
    This is line 2';

console.log(string1);

console.log('--------------------------------------------------------');
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
//            (c) 2011 panacoda GmbH. All rights reserved.
// Creator:   Dominik
// Date:      02.12.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

/**
 * @class
 *
 * M.LoaderView is the prototype for a loader a.k.a. activity indicator. This very simple
 * view can be used to show the user that something is happening, e.g. while the application
 * is waiting for a request to return some data.
 *
 * @extends M.View
 */
M.LoaderView = M.View.extend(
/** @scope M.LoaderView.prototype */ {

    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.LoaderView',

    /**
     * This property states whether the loader has already been initialized or not.
     *
     * @type Boolean
     */
    isInitialized: NO,

    /**
     * This property counts the loader calls to show
     *
     * @type Number
     */
    refCount: 0,

    /**
     * This property can be used to specify the default title of a loader.
     *
     * @type String
     */
    defaultTitle: 'loading',

    /**
     * This method initializes the loader by loading it once.
     *
     * @private
     */
    initialize: function() {
        if(!this.isInitialized) {
            this.refCount = 0;
            this.isInitialized = YES;
        }
    },

    /**
     * This method shows the default loader. You can specify the displayed label with the
     * title parameter.
     *
     * @param {String} title The title for this loader.
     */
    show: function(title) {
        this.refCount++;
        var title = title && typeof(title) === 'string' ? title : this.defaultTitle;
        $.mobile.loadingMessage = title;
        if(this.refCount == 1){
            $.mobile.pageLoading();

            /* position alert in the center of the possibly scrolled viewport */
            var loader = $('.ui-loader');
            var screenSize = M.Environment.getSize();
            var scrollYOffset = window.pageYOffset;
            var loaderHeight = loader.outerHeight();

            var yPos = scrollYOffset + (screenSize[1]/2);
            loader.css('top', yPos + 'px');
            loader.css('margin-top', '-' + (loaderHeight/2) + 'px');
        }
    },

    /**
     * This method hides the loader.
     *
     * @param {Boolean} force Determines whether to force the hide of the loader.
     */
    hide: function(force) {
        if(force || this.refCount <= 0) {
            this.refCount = 0;
        } else {
            this.refCount--;
        }
        if(this.refCount == 0){
            $.mobile.pageLoading(true);
        }
    }

});<commit_msg>add changeTitle function replaced $.mobile.loadingMessage = title; with the new function M.LoaderView.changeTitle(title); Changing the title by modifing the DOM.<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
//            (c) 2011 panacoda GmbH. All rights reserved.
// Creator:   Dominik
// Date:      02.12.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

/**
 * @class
 *
 * M.LoaderView is the prototype for a loader a.k.a. activity indicator. This very simple
 * view can be used to show the user that something is happening, e.g. while the application
 * is waiting for a request to return some data.
 *
 * @extends M.View
 */
M.LoaderView = M.View.extend(
/** @scope M.LoaderView.prototype */ {

    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.LoaderView',

    /**
     * This property states whether the loader has already been initialized or not.
     *
     * @type Boolean
     */
    isInitialized: NO,

    /**
     * This property counts the loader calls to show
     *
     * @type Number
     */
    refCount: 0,

    /**
     * This property can be used to specify the default title of a loader.
     *
     * @type String
     */
    defaultTitle: 'loading',

    /**
     * This method initializes the loader by loading it once.
     *
     * @private
     */
    initialize: function() {
        if(!this.isInitialized) {
            this.refCount = 0;
            this.isInitialized = YES;
        }
    },

    /**
     * This method shows the default loader. You can specify the displayed label with the
     * title parameter.
     *
     * @param {String} title The title for this loader.
     */
    show: function(title) {
        this.refCount++;
        var title = title && typeof(title) === 'string' ? title : this.defaultTitle;
        this.changeTitle(title);
        if(this.refCount == 1){
            $.mobile.pageLoading();

            /* position alert in the center of the possibly scrolled viewport */
            var loader = $('.ui-loader');
            var screenSize = M.Environment.getSize();
            var scrollYOffset = window.pageYOffset;
            var loaderHeight = loader.outerHeight();

            var yPos = scrollYOffset + (screenSize[1]/2);
            loader.css('top', yPos + 'px');
            loader.css('margin-top', '-' + (loaderHeight/2) + 'px');
        }
    },

    /**
     * This method changes the current title.
     *
     * @param {String} title The title for this loader.
     */

    changeTitle: function(title){
        $('.ui-loader h1').html(title);
    },

    /**
     * This method hides the loader.
     *
     * @param {Boolean} force Determines whether to force the hide of the loader.
     */
    hide: function(force) {
        if(force || this.refCount <= 0) {
            this.refCount = 0;
        } else {
            this.refCount--;
        }
        if(this.refCount == 0){
            $.mobile.pageLoading(true);
        }
    }

});<|endoftext|>


<commit_before>// Native
const {resolve} = require('path');

// Packages
const minimist = require('minimist');

// Ours
const {abort, error} = require('../error');
const {getLogo} = require('../logo');
const {abc, cmd, hvy, opt, req, sec} = require('../text');
const pkg = require('../../package');

const OPTIONS = {
  boolean: [
    'help',
    'version'
  ],
  alias: {
    help: 'h',
    version: 'v'
  }
};

const USAGE = `
Usage: ${cmd('aunty')} ${req('<command>')} ${opt('[options]')} ${opt('[command_options]')}

${sec('Options')}

${opt('-h')}, ${opt('--help')}     Display this help message and exit
${opt('-v')}, ${opt('--version')}  Print ${hvy('aunty')}'s version

${sec('Commands')}

${cmd('aunty config')}
  Output the current project's known configuration.

${cmd('aunty deploy')}
  Deploy the project in the current directory.

${cmd('aunty release')}
  Tag and deploy the project in the current directory.

${cmd('aunty help')} ${req('<command>')}
  Display complete help for ${req('command')}.
`;

const COMMANDS = [
  'config',
  'deploy',
  'help',
  'release',
  'c',
  'd',
  'r'
];

const COMMANDS_ALIASES = {
  c: 'config',
  d: 'deploy',
  r: 'release'
};

const help = code => {
  console.log(getLogo());
  console.log(USAGE);
  process.exit(code || 0);
}

const args = process.argv.slice(2);
const argv = minimist(args, OPTIONS);

if (argv.version) {
  console.log(`${hvy('aunty')} v${pkg.version}`);
  process.exit(0);
}

if (argv._.length === 0 || argv._.length === 1 && argv._[0] === 'help') {
  help();
}

let command = argv._[0];
let isHelpOnly;

if (command === 'help') {
  isHelpOnly = true;
  command = argv._[1];
}

if (COMMANDS.indexOf(command) < 0) {
  help(1);
}

command = COMMANDS_ALIASES[command] || command;

const commandPath = resolve(__dirname, './commands/' + command);

require(commandPath)(isHelpOnly ? ['--help'] : args.slice(1));
<commit_msg>Logos on all commands (except aunty v1.5.0).<commit_after>// Native
const {resolve} = require('path');

// Packages
const minimist = require('minimist');

// Ours
const {abort, error} = require('../error');
const {getLogo} = require('../logo');
const {abc, cmd, hvy, opt, req, sec} = require('../text');
const pkg = require('../../package');

const OPTIONS = {
  boolean: [
    'help',
    'version'
  ],
  alias: {
    help: 'h',
    version: 'v'
  }
};

const USAGE = `
Usage: ${cmd('aunty')} ${req('<command>')} ${opt('[options]')} ${opt('[command_options]')}

${sec('Options')}

${opt('-h')}, ${opt('--help')}     Display this help message and exit
${opt('-v')}, ${opt('--version')}  Print ${hvy('aunty')}'s version

${sec('Commands')}

${cmd('aunty config')}
  Output the current project's known configuration.

${cmd('aunty deploy')}
  Deploy the project in the current directory.

${cmd('aunty release')}
  Tag and deploy the project in the current directory.

${cmd('aunty help')} ${req('<command>')}
  Display complete help for ${req('command')}.
`;

const COMMANDS = [
  'config',
  'deploy',
  'help',
  'release',
  'c',
  'd',
  'r'
];

const COMMANDS_ALIASES = {
  c: 'config',
  d: 'deploy',
  r: 'release'
};

const help = code => {
  console.log(USAGE);
  process.exit(code || 0);
}

const args = process.argv.slice(2);
const argv = minimist(args, OPTIONS);

if (argv.version) {
  console.log(`${hvy('aunty')} v${pkg.version}`);
  process.exit(0);
}

console.log(getLogo());

if (argv._.length === 0 || argv._.length === 1 && argv._[0] === 'help') {
  help();
}

let command = argv._[0];
let isHelpOnly;

if (command === 'help') {
  isHelpOnly = true;
  command = argv._[1];
}

if (COMMANDS.indexOf(command) < 0) {
  help(1);
}

command = COMMANDS_ALIASES[command] || command;

const commandPath = resolve(__dirname, './commands/' + command);

require(commandPath)(isHelpOnly ? ['--help'] : args.slice(1));
<|endoftext|>


<commit_before>import * as d3 from 'd3';
import _ from 'lodash';
import { rebind } from '../util/rebind';
import { getSetValue } from '../util/get_set_value';
import { d3combobox } from '../lib/d3.combobox.js';
import { t } from '../util/locale';
import { Browse } from '../modes/index';
import { Disclosure } from './disclosure';
import { Icon } from '../svg/index';
import { TagReference } from './tag_reference';
import { fields } from './fields/index';

export function preset(context) {
    var dispatch = d3.dispatch('change'),
        state,
        fieldsArr,
        preset,
        tags,
        id;

    function UIField(field, entity, show) {
        field = _.clone(field);

        field.input = fields[field.type](field, context)
            .on('change', dispatch.change);

        if (field.input.entity) field.input.entity(entity);

        field.keys = field.keys || [field.key];

        field.show = show;

        field.shown = function() {
            return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
        };

        field.modified = function() {
            var original = context.graph().base().entities[entity.id];
            return _.some(field.keys, function(key) {
                return original ? tags[key] !== original.tags[key] : tags[key];
            });
        };

        field.revert = function() {
            var original = context.graph().base().entities[entity.id],
                t = {};
            field.keys.forEach(function(key) {
                t[key] = original ? original.tags[key] : undefined;
            });
            return t;
        };

        field.present = function() {
            return _.some(field.keys, function(key) {
                return tags[key];
            });
        };

        field.remove = function() {
            var t = {};
            field.keys.forEach(function(key) {
                t[key] = undefined;
            });
            return t;
        };

        return field;
    }

    function fieldKey(field) {
        return field.id;
    }

    function presets(selection) {
        selection.call(Disclosure()
            .title(t('inspector.all_fields'))
            .expanded(context.storage('preset_fields.expanded') !== 'false')
            .on('toggled', toggled)
            .content(content));

        function toggled(expanded) {
            context.storage('preset_fields.expanded', expanded);
        }
    }

    function content(selection) {
        if (!fieldsArr) {
            var entity = context.entity(id),
                geometry = context.geometry(id);

            fieldsArr = [UIField(context.presets().field('name'), entity)];

            preset.fields.forEach(function(field) {
                if (field.matchGeometry(geometry)) {
                    fieldsArr.push(UIField(field, entity, true));
                }
            });

            if (entity.isHighwayIntersection(context.graph())) {
                fieldsArr.push(UIField(context.presets().field('restrictions'), entity, true));
            }

            context.presets().universal().forEach(function(field) {
                if (preset.fields.indexOf(field) < 0) {
                    fieldsArr.push(UIField(field, entity));
                }
            });
        }

        var shown = fieldsArr.filter(function(field) { return field.shown(); }),
            notShown = fieldsArr.filter(function(field) { return !field.shown(); });

        var form = selection.selectAll('.preset-form')
            .data([0]);

        form = form.enter()
            .append('div')
            .attr('class', 'preset-form inspector-inner fillL3')
            .merge(form);

        var fields = form.selectAll('.form-field')
            .data(shown, fieldKey);

        fields.exit()
            .remove();

        // Enter
        var enter = fields.enter()
            .append('div')
            .attr('class', function(field) {
                return 'form-field form-field-' + field.id;
            });

        var label = enter
            .append('label')
            .attr('class', 'form-label')
            .attr('for', function(field) { return 'preset-input-' + field.id; })
            .text(function(field) { return field.label(); });

        var wrap = label
            .append('div')
            .attr('class', 'form-label-button-wrap');

        wrap.append('button')
            .attr('class', 'remove-icon')
            .attr('tabindex', -1)
            .call(Icon('#operation-delete'));

        wrap.append('button')
            .attr('class', 'modified-icon')
            .attr('tabindex', -1)
            .call(Icon('#icon-undo'));

        // Update
        fields = fields
            .merge(enter);

        fields.selectAll('.form-label-button-wrap .remove-icon')
            .on('click', remove);

        fields.selectAll('.modified-icon')
            .on('click', revert);

        fields
            .order()
            .classed('modified', function(field) { return field.modified(); })
            .classed('present', function(field) { return field.present(); })
            .each(function(field) {
                var reference = TagReference(field.reference || {key: field.key}, context);

                if (state === 'hover') {
                    reference.showing(false);
                }

                d3.select(this)
                    .call(field.input)
                    .selectAll('input')
                    .on('keydown', function() {
                        // if user presses enter, and combobox is not active, accept edits..
                        if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
                            context.enter(Browse(context));
                        }
                    })
                    .call(reference.body)
                    .select('.form-label-button-wrap')
                    .call(reference.button);

                field.input.tags(tags);
            });

        notShown = notShown.map(function(field) {
            return {
                title: field.label(),
                value: field.label(),
                field: field
            };
        });

        var more = selection.selectAll('.more-fields')
            .data((notShown.length > 0) ? [0] : []);

        more.exit()
            .remove();

        more = more.enter()
            .append('div')
            .attr('class', 'more-fields')
            .append('label')
            .text(t('inspector.add_fields'))
            .merge(more);

        var input = more.selectAll('.value')
            .data([0]);

        input.exit()
            .remove();

        input = input.enter()
            .append('input')
            .attr('class', 'value')
            .attr('type', 'text')
            .merge(input);

        input
            .call(getSetValue, '')
            .attr('placeholder', function() {
                var placeholder = [];
                for (var field in notShown) {
                    placeholder.push(notShown[field].title);
                }
                return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
            })
            .call(d3combobox().data(notShown)
                .minItems(1)
                .on('accept', show));

        function show(field) {
            field = field.field;
            field.show = true;
            content(selection);
            field.input.focus();
        }

        function revert(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field.revert());
        }

        function remove(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field.remove());
        }
    }

    presets.preset = function(_) {
        if (!arguments.length) return preset;
        if (preset && preset.id === _.id) return presets;
        preset = _;
        fieldsArr = null;
        return presets;
    };

    presets.state = function(_) {
        if (!arguments.length) return state;
        state = _;
        return presets;
    };

    presets.tags = function(_) {
        if (!arguments.length) return tags;
        tags = _;
        // Don't reset fieldsArr here.
        return presets;
    };

    presets.entityID = function(_) {
        if (!arguments.length) return id;
        if (id === _) return presets;
        id = _;
        fieldsArr = null;
        return presets;
    };

    return rebind(presets, dispatch, 'on');
}
<commit_msg>Fix propagation of change events<commit_after>import * as d3 from 'd3';
import _ from 'lodash';
import { rebind } from '../util/rebind';
import { getSetValue } from '../util/get_set_value';
import { d3combobox } from '../lib/d3.combobox.js';
import { t } from '../util/locale';
import { Browse } from '../modes/index';
import { Disclosure } from './disclosure';
import { Icon } from '../svg/index';
import { TagReference } from './tag_reference';
import { fields } from './fields/index';

export function preset(context) {
    var dispatch = d3.dispatch('change'),
        state,
        fieldsArr,
        preset,
        tags,
        id;

    function UIField(field, entity, show) {
        field = _.clone(field);

        field.input = fields[field.type](field, context)
            .on('change', function(t, onInput) {
                dispatch.call('change', field, t, onInput);
            });

        if (field.input.entity) field.input.entity(entity);

        field.keys = field.keys || [field.key];

        field.show = show;

        field.shown = function() {
            return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
        };

        field.modified = function() {
            var original = context.graph().base().entities[entity.id];
            return _.some(field.keys, function(key) {
                return original ? tags[key] !== original.tags[key] : tags[key];
            });
        };

        field.revert = function() {
            var original = context.graph().base().entities[entity.id],
                t = {};
            field.keys.forEach(function(key) {
                t[key] = original ? original.tags[key] : undefined;
            });
            return t;
        };

        field.present = function() {
            return _.some(field.keys, function(key) {
                return tags[key];
            });
        };

        field.remove = function() {
            var t = {};
            field.keys.forEach(function(key) {
                t[key] = undefined;
            });
            return t;
        };

        return field;
    }

    function fieldKey(field) {
        return field.id;
    }

    function presets(selection) {
        selection.call(Disclosure()
            .title(t('inspector.all_fields'))
            .expanded(context.storage('preset_fields.expanded') !== 'false')
            .on('toggled', toggled)
            .content(content));

        function toggled(expanded) {
            context.storage('preset_fields.expanded', expanded);
        }
    }

    function content(selection) {
        if (!fieldsArr) {
            var entity = context.entity(id),
                geometry = context.geometry(id);

            fieldsArr = [UIField(context.presets().field('name'), entity)];

            preset.fields.forEach(function(field) {
                if (field.matchGeometry(geometry)) {
                    fieldsArr.push(UIField(field, entity, true));
                }
            });

            if (entity.isHighwayIntersection(context.graph())) {
                fieldsArr.push(UIField(context.presets().field('restrictions'), entity, true));
            }

            context.presets().universal().forEach(function(field) {
                if (preset.fields.indexOf(field) < 0) {
                    fieldsArr.push(UIField(field, entity));
                }
            });
        }

        var shown = fieldsArr.filter(function(field) { return field.shown(); }),
            notShown = fieldsArr.filter(function(field) { return !field.shown(); });

        var form = selection.selectAll('.preset-form')
            .data([0]);

        form = form.enter()
            .append('div')
            .attr('class', 'preset-form inspector-inner fillL3')
            .merge(form);

        var fields = form.selectAll('.form-field')
            .data(shown, fieldKey);

        fields.exit()
            .remove();

        // Enter
        var enter = fields.enter()
            .append('div')
            .attr('class', function(field) {
                return 'form-field form-field-' + field.id;
            });

        var label = enter
            .append('label')
            .attr('class', 'form-label')
            .attr('for', function(field) { return 'preset-input-' + field.id; })
            .text(function(field) { return field.label(); });

        var wrap = label
            .append('div')
            .attr('class', 'form-label-button-wrap');

        wrap.append('button')
            .attr('class', 'remove-icon')
            .attr('tabindex', -1)
            .call(Icon('#operation-delete'));

        wrap.append('button')
            .attr('class', 'modified-icon')
            .attr('tabindex', -1)
            .call(Icon('#icon-undo'));

        // Update
        fields = fields
            .merge(enter);

        fields.selectAll('.form-label-button-wrap .remove-icon')
            .on('click', remove);

        fields.selectAll('.modified-icon')
            .on('click', revert);

        fields
            .order()
            .classed('modified', function(field) { return field.modified(); })
            .classed('present', function(field) { return field.present(); })
            .each(function(field) {
                var reference = TagReference(field.reference || {key: field.key}, context);

                if (state === 'hover') {
                    reference.showing(false);
                }

                d3.select(this)
                    .call(field.input)
                    .selectAll('input')
                    .on('keydown', function() {
                        // if user presses enter, and combobox is not active, accept edits..
                        if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
                            context.enter(Browse(context));
                        }
                    })
                    .call(reference.body)
                    .select('.form-label-button-wrap')
                    .call(reference.button);

                field.input.tags(tags);
            });

        notShown = notShown.map(function(field) {
            return {
                title: field.label(),
                value: field.label(),
                field: field
            };
        });

        var more = selection.selectAll('.more-fields')
            .data((notShown.length > 0) ? [0] : []);

        more.exit()
            .remove();

        more = more.enter()
            .append('div')
            .attr('class', 'more-fields')
            .append('label')
            .text(t('inspector.add_fields'))
            .merge(more);

        var input = more.selectAll('.value')
            .data([0]);

        input.exit()
            .remove();

        input = input.enter()
            .append('input')
            .attr('class', 'value')
            .attr('type', 'text')
            .merge(input);

        input
            .call(getSetValue, '')
            .attr('placeholder', function() {
                var placeholder = [];
                for (var field in notShown) {
                    placeholder.push(notShown[field].title);
                }
                return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
            })
            .call(d3combobox().data(notShown)
                .minItems(1)
                .on('accept', show));

        function show(field) {
            field = field.field;
            field.show = true;
            content(selection);
            field.input.focus();
        }

        function revert(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field, field.revert());
        }

        function remove(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field, field.remove());
        }
    }

    presets.preset = function(_) {
        if (!arguments.length) return preset;
        if (preset && preset.id === _.id) return presets;
        preset = _;
        fieldsArr = null;
        return presets;
    };

    presets.state = function(_) {
        if (!arguments.length) return state;
        state = _;
        return presets;
    };

    presets.tags = function(_) {
        if (!arguments.length) return tags;
        tags = _;
        // Don't reset fieldsArr here.
        return presets;
    };

    presets.entityID = function(_) {
        if (!arguments.length) return id;
        if (id === _) return presets;
        id = _;
        fieldsArr = null;
        return presets;
    };

    return rebind(presets, dispatch, 'on');
}
<|endoftext|>


<commit_before>import * as moment from 'moment-timezone';
import { countryCodes } from '../../constants/countries.js';
import { firestore } from 'firebase';

/**
 * Format a timestamp (in milliseconds) into a pretty string with just the time.
 * Example: '10:19 AM'.
 *
 * @param {int} msTimestamp Timestamp in milliseconds of desired date.
 * @param {string} timezone Timezone in which to convert.
 * @return {string} Formatted time.
 */
export function timestampToTimeFormatted(msTimestamp, timezone = 'America/New_York') {
  // Formats from https://momentjs.com/docs/#/displaying/format/
  // LT = Localized time
  return moment.tz(parseFloat(msTimestamp), timezone).format('LT');

}

/**
 * Format a timestamp (in milliseconds) into a pretty string with just the date.
 * Example: 'Monday, January 19, 1970'.
 *
 * @param {int} msTimestamp Timestamp in milliseconds of desired date.
 * @param {string} timezone Timezone in which to convert.
 * @return {string} Formatted time.
 */
export function timestampToDateFormatted(msTimestamp, timezone='America/New_York') {
  // Formats from https://momentjs.com/docs/#/displaying/format/.
  // dddd = Day of the week (i.e. Monday)
  // LL = "January 19, 1970"
  return moment.tz(parseFloat(msTimestamp), timezone).format('dddd, LL');
}

/**
 * Format a timestamp (in milliseconds) into a pretty string.
 * Example: 'Monday, January 19, 1970 02:48 AM PST'.
 *
 * @param {int} msTimestamp Timestamp in milliseconds of desired date.
 * @param {string} timezone Timezone in which to convert.
 * @returns {string} Formatted time.
 */
export function timestampToFormatted(msTimestamp, timezone = 'America/New_York') {
  // Formats from https://momentjs.com/docs/#/displaying/format/.
  // LLLL = "Monday, January 19, 1970 2:48 AM"
  // z = "PST"
  return moment.tz(parseFloat(msTimestamp), timezone).format('LLLL z');

}

/**
 * Return a Firestore Timestamp corresponding to the date in `dateStr`.
 *
 * @param {string} dateStr String containing a date in the form 'YYYY-MM-DD'.
 * @return {firestore.Timestamp} Firestore timestamp object created.
 */
export function getTimestampFromDateString(dateStr) {
  const dateParts = dateStr.split('-').map(str => +str);
  if (dateParts.length === 1 && dateParts[0] === 0) {
    return firestore.Timestamp.now();
  }

  const date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
  return firestore.Timestamp.fromDate(date);
}

/**
 * Formats a Firestore timestamp into a date string in ISO format.
 *
 * @param {firestore.Timestamp} timestamp Firestore timestamp object.
 * @return {string} ISO formatted date string: "YYYY-MM-DD or 2020-05-12".
 */
export function timestampToISOString(timestamp) {
  return timestamp.toDate().toISOString().substring(0,10);
}

/**
 * Returns all the time zones in a country (in displayable format).
 *
 * @param {string} countryName The name of the country for which to get the time zones.
 * @return {string[]} The list of time zones in the provided country.
 */
export function timezonesForCountry(countryName) {
  let zones;
  try {
    const countryCode = countryCodes[countryName];
    zones = moment.tz.zonesForCountry(countryCode);
  } catch (e) {
    zones = moment.tz.names(); // List of all timezones.
  }
  return zones.map(e => {
    return e.replace(/[_]/g, ' ');
  });
}

/**
 * Get a date in 'YYYY-MM-DD' format.
 *
 * @param {number} msTimestamp Timestamp, in milliseconds since epoch.
 * @param {string} timezone The timezone which the string should be returned in.
 * @return {string} The date in 'YYYY-MM-DD' format.
 */
export function getISODate(msTimestamp, timezone=null) {
  if (timezone === null) {
    timezone = ''; // Use GMT.
  }
  return moment.tz(parseFloat(msTimestamp), timezone).format(moment.HTML5_FMT.DATE);
}

/**
 * Get a time in 24-hour ('HH:mm') format.
 *
 * @param {number} msTimestamp Timestamp, in milliseconds since epoch.
 * @param {string} timezone The timezone which the string should be returned in.
 * @return {string} The time in 24-hour (HH:mm) format.
 */
export function get24hTime(msTimestamp, timezone = null) {
  if (timezone === null) {
    timezone = ''; // Use GMT.
  }
  return moment.tz(parseFloat(msTimestamp), timezone).format(moment.HTML5_FMT.TIME);
}

/**
 * Get a Firebase Timestamp object for time.
 *
 * @param {string} time The time in 'HH:mm' format.
 * @param {string} date The date in 'YYYY-MM-DD' format.
 * @param {string} tz The timezone in which the date takes place.
 * @return {firestore.Timestamp} Firestore timestamp object at the same time.
 */
export function firebaseTsFromISO(time, date, tz) {
  const mtzDate = moment.tz(time + " " + date, "HH:mm YYYY-MM-DD", tz);
  return new firestore.Timestamp(mtzDate.valueOf() / 1000, 0);
}
<commit_msg>Remove spaces from timezone entry.<commit_after>import * as moment from 'moment-timezone';
import { countryCodes } from '../../constants/countries.js';
import { firestore } from 'firebase';

/**
 * Format a timestamp (in milliseconds) into a pretty string with just the time.
 * Example: '10:19 AM'.
 *
 * @param {int} msTimestamp Timestamp in milliseconds of desired date.
 * @param {string} timezone Timezone in which to convert.
 * @return {string} Formatted time.
 */
export function timestampToTimeFormatted(msTimestamp, timezone = '') {
  // Formats from https://momentjs.com/docs/#/displaying/format/
  // LT = Localized time
  timezone = timezone != null ? timezone.replace(' ', '_') // Reformat date.
                              : ''; // Use GMT.
  return moment.tz(parseFloat(msTimestamp), timezone).format('LT');

}

/**
 * Format a timestamp (in milliseconds) into a pretty string with just the date.
 * Example: 'Monday, January 19, 1970'.
 *
 * @param {int} msTimestamp Timestamp in milliseconds of desired date.
 * @param {string} timezone Timezone in which to convert.
 * @return {string} Formatted time.
 */
export function timestampToDateFormatted(msTimestamp, timezone='') {
  // Formats from https://momentjs.com/docs/#/displaying/format/.
  // dddd = Day of the week (i.e. Monday)
  // LL = "January 19, 1970"
  timezone = timezone != null ? timezone.replace(' ', '_') // Reformat date.
                              : ''; // Use GMT.
  return moment.tz(parseFloat(msTimestamp), timezone).format('dddd, LL');
}

/**
 * Format a timestamp (in milliseconds) into a pretty string.
 * Example: 'Monday, January 19, 1970 02:48 AM PST'.
 *
 * @param {int} msTimestamp Timestamp in milliseconds of desired date.
 * @param {string} timezone Timezone in which to convert.
 * @returns {string} Formatted time.
 */
export function timestampToFormatted(msTimestamp, timezone = '') {
  // Formats from https://momentjs.com/docs/#/displaying/format/.
  // LLLL = "Monday, January 19, 1970 2:48 AM"
  // z = "PST"
  timezone = timezone != null ? timezone.replace(' ', '_') // Reformat date.
                              : ''; // Use GMT.
  return moment.tz(parseFloat(msTimestamp), timezone).format('LLLL z');

}

/**
 * Return a Firestore Timestamp corresponding to the date in `dateStr`.
 *
 * @param {string} dateStr String containing a date in the form 'YYYY-MM-DD'.
 * @return {firestore.Timestamp} Firestore timestamp object created.
 */
export function getTimestampFromDateString(dateStr) {
  const dateParts = dateStr.split('-').map(str => +str);
  if (dateParts.length === 1 && dateParts[0] === 0) {
    return firestore.Timestamp.now();
  }

  const date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
  return firestore.Timestamp.fromDate(date);
}

/**
 * Formats a Firestore timestamp into a date string in ISO format.
 *
 * @param {firestore.Timestamp} timestamp Firestore timestamp object.
 * @return {string} ISO formatted date string: "YYYY-MM-DD or 2020-05-12".
 */
export function timestampToISOString(timestamp) {
  return timestamp.toDate().toISOString().substring(0,10);
}

/**
 * Returns all the time zones in a country (in displayable format).
 *
 * @param {string} countryName The name of the country for which to get the time zones.
 * @return {string[]} The list of time zones in the provided country.
 */
export function timezonesForCountry(countryName) {
  let zones;
  try {
    const countryCode = countryCodes[countryName];
    zones = moment.tz.zonesForCountry(countryCode);
  } catch (e) {
    zones = moment.tz.names(); // List of all timezones.
  }
  return zones.map(e => {
    return e.replace(/[_]/g, ' ');
  });
}

/**
 * Get a date in 'YYYY-MM-DD' format.
 *
 * @param {number} msTimestamp Timestamp, in milliseconds since epoch.
 * @param {string} timezone The timezone which the string should be returned in.
 * @return {string} The date in 'YYYY-MM-DD' format.
 */
export function getISODate(msTimestamp, timezone=null) {
  timezone = timezone != null ? timezone.replace(' ', '_') // Reformat date.
                              : ''; // Use GMT.
  return moment.tz(parseFloat(msTimestamp), timezone).format(moment.HTML5_FMT.DATE);
}

/**
 * Get a time in 24-hour ('HH:mm') format.
 *
 * @param {number} msTimestamp Timestamp, in milliseconds since epoch.
 * @param {string} timezone The timezone which the string should be returned in.
 * @return {string} The time in 24-hour (HH:mm) format.
 */
export function get24hTime(msTimestamp, timezone = null) {
  if (timezone === null) {
    timezone = ''; // Use GMT.
  }
  timezone = timezone.replace(' ', '_');
  return moment.tz(parseFloat(msTimestamp), timezone).format(moment.HTML5_FMT.TIME);
}

/**
 * Get a Firebase Timestamp object for time.
 *
 * @param {string} time The time in 'HH:mm' format.
 * @param {string} date The date in 'YYYY-MM-DD' format.
 * @param {string} tz The timezone in which the date takes place.
 * @return {firestore.Timestamp} Firestore timestamp object at the same time.
 */
export function firebaseTsFromISO(time, date, tz) {
  tz = tz.replace(' ', '_');
  const mtzDate = moment.tz(time + " " + date, "HH:mm YYYY-MM-DD", tz);
  return new firestore.Timestamp(mtzDate.valueOf() / 1000, 0);
}
<|endoftext|>


<commit_before>import {Observable} from 'rxjs/Observable'
import {_do} from 'rxjs/operator/do'
import {_finally} from 'rxjs/operator/finally'
import {share} from 'rxjs/operator/share'
import {startWith} from 'rxjs/operator/startwith'

// A cacheable observable needs to add itself to the cache on subscription
// and remove itself on unsubscribe.
function createCacheableObservable(source, cache, request) {
  const {url} = request

  return Observable.create(observer => {
    // If there is nothing in the cache, add it.
    if (!cache[url]) {
      // Get observable from wrapped source.
      cache[url] = {
        observable: source(request)
          ::_do(v => {cache[url].lastValue = v})
          ::_finally(() => {delete cache[url]})
          ::share()
      }
    }

    // Start with last value if possible.
    if (cache[url].hasOwnProperty('lastValue')) {
      return startWith(cache[url].observable, cache[url].lastValue)
        .subscribe(observer)
    }
    else {
      return cache[url].observable
        .subscribe(observer)
    }
  })
}

export default function wrapCache(source) {
  const c = {}

  return function cache(request) {
    if (request.method === 'OBSERVE') {
      // The request isn't completed until subscription.
      return createCacheableObservable(source, c, request)
    }
    else {
      return source(request)
    }
  }
}
<commit_msg>Fix cache<commit_after>import {Observable} from 'rxjs/Observable'
import {_do} from 'rxjs/operator/do'
import {_finally} from 'rxjs/operator/finally'
import {share} from 'rxjs/operator/share'
import {startWith} from 'rxjs/operator/startwith'

// A cacheable observable needs to add itself to the cache on subscription
// and remove itself on unsubscribe.
function createCacheableObservable(source, cache, request) {
  const {url} = request

  return Observable.create(observer => {
    // If there is nothing in the cache, add it.
    if (!cache[url]) {
      // Get observable from wrapped source.
      cache[url] = {
        observable: source(request)
          ::_do(v => {cache[url].lastValue = v})
          ::_finally(() => {delete cache[url]})
          ::share()
      }
    }

    // Start with last value if possible.
    if (cache[url].hasOwnProperty('lastValue')) {
      return cache[url].observable
        ::startWith(cache[url].lastValue)
        .subscribe(observer)
    }
    else {
      return cache[url].observable
        .subscribe(observer)
    }
  })
}

export default function wrapCache(source) {
  const c = {}

  return function cache(request) {
    if (request.method === 'OBSERVE') {
      // The request isn't completed until subscription.
      return createCacheableObservable(source, c, request)
    }
    else {
      return source(request)
    }
  }
}
<|endoftext|>


<commit_before>/** @jsx m */

"use strict";
require("./BookmarksPage.scss");

var _ = require("underscore");
var m = require("mithril");

var Layout = require("../layouts/DefaultLayout.js");
var OnUnload = require("../utils/OnUnload.js");

var BookmarksPage = {};

BookmarksPage.controller = function(options) {
  OnUnload(this);
  options = _.extend({id: "BookmarksPage"}, options);
  this.user = options.user;
  if (this.user.get("id")) {
    this.user.get("bookmarks").fetch();
  }
  this.controllers.layout = new Layout.controller(options);
};

BookmarksPage.view = function(ctrl) {
  var content;
  var bookmarks = ctrl.user.get("bookmarks");

  if (bookmarks.length > 0) {
    var list = bookmarks.map(function(bookmark) {
      return BookmarksPage.views[bookmark.get("bookmarkable_type")](bookmark.get("bookmarkable"));
      // return
{bookmark.get("bookmarkable_id")}
;
    });

    content = (

Bookmarks

          {list}

    );
  } else {
    content = (

Bookmarks

You do not have any bookmarks

    );
  }

  return new Layout.view(ctrl.controllers.layout, content);
};

BookmarksPage.views = {};

BookmarksPage.views.Article = function(article) {
  return

    {article.get("title")}

;
};

module.exports = BookmarksPage;
<commit_msg>BookmarksPage: render toggle button, year and authors<commit_after>/** @jsx m */

"use strict";
require("./BookmarksPage.scss");

var _ = require("underscore");
var m = require("mithril");

var Layout = require("../layouts/DefaultLayout.js");
var OnUnload = require("../utils/OnUnload.js");

var BookmarksPage = {};

BookmarksPage.controller = function(options) {
  OnUnload(this);
  options = _.extend({id: "BookmarksPage"}, options);
  this.user = options.user;
  if (this.user.get("id")) {
    this.user.get("bookmarks").fetch();
  }
  this.controllers.layout = new Layout.controller(options);
};

BookmarksPage.view = function(ctrl) {
  var content;
  var bookmarks = ctrl.user.get("bookmarks");

  if (bookmarks.length > 0) {
    var list = bookmarks.map(function(bookmark) {
      return BookmarksPage.views[bookmark.get("bookmarkable_type")](bookmark.get("bookmarkable"), ctrl.user);
      // return
{bookmark.get("bookmarkable_id")}
;
    });

    content = (

Bookmarks

          {list}

    );
  } else {
    content = (

Bookmarks

You do not have any bookmarks

    );
  }

  return new Layout.view(ctrl.controllers.layout, content);
};

BookmarksPage.views = {};

BookmarksPage.views.Article = function(article, user) {
  return

    {article.get("title")}

      <button type="button" className={"btn btn_subtle bookmark " + (user.hasBookmarked("Article", article.get("id")) ? "active" : "")} onclick={user.toggleBookmark("Article", article)}>

      </button>
      ({article.get("year")}) {article.authors().etAl(3)}

;
};

module.exports = BookmarksPage;
<|endoftext|>


<commit_before>var webpack = require('webpack');
var path = require('path');

module.exports = {
    entry: [
        './src/index.js',
    ],
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'bundle.js',
    },
    module: {
        loaders: [{
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['react', 'es2015', 'stage-1'],
            },
        }],
    },
    resolve: {
        extensions: ['', '.js', '.jsx'],
    },
    devServer: {
        historyApiFallback: true,
        contentBase: './',
    },
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                // This has effect on the react lib size
                NODE_ENV: JSON.stringify('production'),
            },
        }),
        new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.UglifyJsPlugin({
            beautify: false,
            mangle: {
                screw_ie8: true,
            },
            compress: {
                screw_ie8: true,
            },
            comments: false,
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.AggressiveMergingPlugin(),
    ],
};
<commit_msg>DedupePlugin lead to crash, removed<commit_after>var webpack = require('webpack');
var path = require('path');

module.exports = {
    entry: [
        './src/index.js',
    ],
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'bundle.js',
    },
    module: {
        loaders: [{
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['react', 'es2015', 'stage-1'],
            },
        }],
    },
    resolve: {
        extensions: ['', '.js', '.jsx'],
    },
    devServer: {
        historyApiFallback: true,
        contentBase: './',
    },
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                // This has effect on the react lib size
                NODE_ENV: JSON.stringify('production'),
            },
        }),
        new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
        new webpack.optimize.UglifyJsPlugin({
            beautify: false,
            mangle: {
                screw_ie8: true,
            },
            compress: {
                screw_ie8: true,
            },
            comments: false,
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.AggressiveMergingPlugin(),
    ],
};
<|endoftext|>


<commit_before>Template.game.events({
  "submit .end-turn": function(event) {
    Meteor.call("endTurn");
    return false;
  },
  "submit .end-game": function(event) {
    Meteor.call("endGame");
    return false;
  },
  "submit .attack" : function(event) {
    var attackFromVal = $(event.target).find("[name=attackFrom]").val();
    var targetVal = $(event.target).find("[name=target]").val();
    var attackFrom = Occupation.findOne({
      territory: attackFromVal
    });
    var target = Occupation.findOne({
      territory: targetVal
    });

    var defendingPlayer = Player.findOne({_id: target.player});

    Occupation.update(attackFrom._id, {
      $inc: { armies: -3 }
    });

    Occupation.update(target._id, {
      $set: { armies: 3, player: attackFrom.player }
    });

    if (Occupation.find({player: defendingPlayer._id}).count() === 0) {
      Meteor.call("newMessage", defendingPlayer.name + " defeated!");
      Player.remove({_id: defendingPlayer._id});
    }

    return false;
  }
});

Template.game.helpers({
  launchTerritories: function() {
    var occupations = Occupation.find({
      player: this.currentPlayer._id,
      armies: {$gt: 1}
    });
    return occupations.map(function (occupation) {
      return Territory.findOne(occupation.territory);
    });
  },
  targets: function() {
    var targets = Occupation.find({
      player: { $not: this.currentPlayer._id },
      armies: {$gt: 1}
    });
    return targets.map(function (target) {
      return Territory.findOne(target.territory);
    });
  },
  occupations: function() { return Occupation.find(); },
  players: function() { return Player.find(); },
  territories: function() { return Territory.find(); },
  gameOver: function() { return Player.find().count() == 1; },
  winningPlayer: function() { return Player.findOne(); },
});
<commit_msg>Attacking with rolls<commit_after>Template.game.events({
  "submit .end-turn": function(event) {
    Meteor.call("endTurn");
    return false;
  },
  "submit .end-game": function(event) {
    Meteor.call("endGame");
    return false;
  },
  "submit .attack" : function(event) {
    event.preventDefault();

    // Who is fighting?
    var attackFromVal = $(event.target).find("[name=attackFrom]").val();
    var targetVal = $(event.target).find("[name=target]").val();
    var attackFrom = Occupation.findOne({
      territory: attackFromVal
    });
    var target = Occupation.findOne({
      territory: targetVal
    });
    var defendingPlayer = Player.findOne({_id: target.player});

    // Pit them
    var attackingRoll = rollDice();
    var defendingRoll = rollDice();
    fight(attackingRoll, defendingRoll);

    // Occupation.update(target._id, {
    //   $set: { armies: 3, player: attackFrom.player}
    // });

    if (Occupation.find({player: defendingPlayer._id}).count() === 0) {
      Meteor.call("newMessage", defendingPlayer.name + " defeated!");
      Player.remove({_id: defendingPlayer._id});
    }

    function rollDice() {
      var die1 = rollDie();
      var die2 = rollDie();
      var diceRollValues = [die1, die2].sort();
      return diceRollValues;
    }

    function rollDie(){
      return Math.floor((Math.random()* 6) + 1);
    }

    function fight(attacker, defender) {
      for( n = 0; n < attacker.length; n++ ) {
        if(attacker[n] > defender[n]) {
          kill(target);
          console.log("Attacker wins!");
        } else {
          kill(attackFrom);
          console.log("Defender wins!");
        }
      }
    }

    function kill(occupation) {
      Occupation.update(occupation._id, {
        $inc: { armies: -1 }
      });
    }
  }
});

Template.game.helpers({
  launchTerritories: function() {
    var occupations = Occupation.find({
      player: this.currentPlayer._id,
      armies: {$gt: 1}
    });
    return occupations.map(function (occupation) {
      return Territory.findOne(occupation.territory);
    });
  },
  targets: function() {
    var targets = Occupation.find({
      player: { $not: this.currentPlayer._id },
      armies: {$gt: 1}
    });
    return targets.map(function (target) {
      return Territory.findOne(target.territory);
    });
  },
  occupations: function() { return Occupation.find(); },
  players: function() { return Player.find(); },
  territories: function() { return Territory.find(); },
  gameOver: function() { return Player.find().count() == 1; },
  winningPlayer: function() { return Player.findOne(); },
});
<|endoftext|>


<commit_before>const functions = require('firebase-functions')
const counting = require('../../utils/counting')

exports = module.exports = functions.database.ref('/public_tasks/{taskUid}').onWrite((data, context) => {
  return Promise.all([
    counting.handleListChange(data.after, context, 'public_tasks_count')
  ])
})
<commit_msg>Fixed bug in functions<commit_after>const functions = require('firebase-functions')
const counting = require('../../utils/counting')

exports = module.exports = functions.database.ref('/public_tasks/{taskUid}').onWrite((data, context) => {
  return Promise.all([
    counting.handleListChange(data, context, 'public_tasks_count')
  ])
})
<|endoftext|>


<commit_before>/*
	Version : 0.0.1
	Created On : 11.03.2015

	-- hoverr_tera.js load this js
	-- It get data set by hoverr_tera.js
*/
(function() {
	var $isMobile = !!((/android|webos|iphone|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()))),
		$onceCalled = false,
		jqueryLink = '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
		debugRequired = true,
		$,
		_window_dataObject = {};

  if(window.hoverrneo === undefined) window.hoverrneo = {};

	// var Debugger = function () { };
	// Debugger.log = function (message) {
	// 	try {
	// 		if(debugRequired) console.log(message);
	// 	} catch (exception) {}
	// };

	var findContainer = function(callback){
		var tempObject = [];

		var inlineContainer = undefined,
		intr = window.setInterval(function(){
			if($(_window_dataObject.selector).length != 0){
				window.clearInterval(intr);

				$(_window_dataObject.selector).each(function(){
					var containerDiv = $('

');
					$(this).after(containerDiv);

					tempObject.push({
						containerDiv: containerDiv,
						width: containerDiv.width(),
						position: $(this).offset()
					});
				});

				if(typeof(callback) === "function" && callback !== undefined) callback(tempObject);
				else return tempObject;
			}
		}, 100);
	};

	// Set attribute for elements
	var setAttributes = function(el, attrs) {
		for(var key in attrs) { if (attrs.hasOwnProperty(key)) el.setAttribute(key, attrs[key]); }
	};

	var putAd = function(container){
		var iframe = document.createElement('iframe'),
		$width = container.width,
		$iframeWidth = _window_dataObject.dimension.width,
		$iframeHeight = _window_dataObject.dimension.height,

		$scale = (($width / $iframeWidth) <= 1) ? ($width / $iframeWidth) : 1,
		$left = "left: "+ (($width - $iframeWidth)/2) +"px;",
		$bottom = Math.ceil((($iframeHeight * $scale) - $iframeHeight)/2),
		$cssText,
		$top,
		$adTag = _window_dataObject.tag,
		$key = [window.hoverrneo.host, window.hoverrneo.section, window.hoverrneo.web_or_mobile, _window_dataObject.id, _window_dataObject.is_default],
		$pixelPingHtml = '';

		$cssText = "height:"+ $iframeHeight +"px !important; min-height:"+ $iframeHeight +"px !important; width:"+ $iframeWidth +"px !important; overflow:hidden;"+ $left +"bottom:"+ $bottom +"px;margin:0 auto; position:absolute; background: transparent; z-index: 2; -moz-transform: scale("+ $scale +"); -o-transform: scale("+ $scale +"); -webkit-transform: scale("+ $scale +"); transform: scale("+ $scale +"); max-width:initial !important;";

		setAttributes(iframe, {"height": $iframeHeight, "scrolling": "no", "frameBorder": 0, "allowtransparency": "true", "class": "_adSenceImagePush", "width": $iframeWidth, "loadStatus": 0, "data-width": $iframeWidth, "data-height": $iframeHeight, "style":$cssText});

		container.containerDiv.append(iframe);

		try{
			console.log('Log : Setting html content in try block !!');
			var doc = iframe.contentDocument || iframe.contentWindow.document;
			doc.open();
			doc.write('