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

  $('.tabs .tabs-nav-link').on('click', function(e) {
    var tabs, link, navItem;
    e.preventDefault();

    link = $(e.target);
    navItem = link.closest('.tabs-nav-item');
    tabs = link.closest('.tabs');

    tabs.find('.tabs-item, .tabs-nav-item').removeClass('active');
    navItem.addClass('active');
    tabs.find(link.attr('href')).addClass('active')
  });

  var OffCanvasNav = function(nav, content) {
    if (!nav) {
      console.error("Off-Canvas Navigation not found", nav);
    }

    if (!content) {
      console.error("Off-Canvas Content not found", content);
    }

    this.nav = nav.jquery ? nav : $(nav);
    this.content = content.jquery ? content : $(content);
  };

  OffCanvasNav.prototype.showNav = function() {
    var navWidth = this.nav.width();

    this.content
    .addClass('active')
    .css('-moz-transform', `translateX(${ navWidth }px)`)
    .css('-webkit-transform', `translateX(${ navWidth }px)`)
    .css('-o-transform', `translateX(${ navWidth }px)`)
    .css('-ms-transform', `translateX(${ navWidth }px)`)
    .css('transform', `translateX(${ navWidth }px)`);
  };

  OffCanvasNav.prototype.hideNav = function() {
    this.content
    .removeClass('active')
    .css('-moz-transform', `translateX(0px)`)
    .css('-webkit-transform', `translateX(0px)`)
    .css('-o-transform', `translateX(0px)`)
    .css('-ms-transform', `translateX(0px)`)
    .css('transform', `translateX(0px)`);
  };

  OffCanvasNav.prototype.toggleNav = function() {
    console.log('toggle')
    if (this.content.hasClass('active')) {
      this.hideNav();
    } else {
      this.showNav();
    }
  };

  var ocContent = $('.off-canvas-content')[0];
  var ocNav = $('.off-canvas-nav')[0];

  var offCanvasNav = new OffCanvasNav(ocNav, ocContent);

  $('.nav-toggle').on('click', function(e) {
    offCanvasNav.toggleNav();
  });

  var touchContent = new Hammer.Manager(ocContent);
  var touchNav = new Hammer.Manager(ocNav);

  // var the pan gesture support all directions.
  // this will block the vertical scrolling on a touch-device while on the element
  // mc.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL })
  touchContent.add( new Hammer.Swipe({ direction: Hammer.DIRECTION_HORIZONTAL }) );
  touchNav.add( new Hammer.Swipe({ direction: Hammer.DIRECTION_HORIZONTAL }) );

  touchContent.on("swiperight", function(ev) {
    offCanvasNav.showNav();
  });

  touchContent.on("swipeleft", function(ev) {
    offCanvasNav.hideNav();
  });

  touchNav.on("swipeleft", function(ev) {
    offCanvasNav.hideNav();
  });

// preview-breakpoints-button
//
  $('.preview-breakpoints-button').on('click', function(e) {
    var link, links, root, preview, linkItem, alreadyActive, parent, newWidth, parentWidth, offset;
    e.preventDefault();

    link = $(e.target);
    linkItem = link.closest('.preview-breakpoints-item');
    root = link.closest('.preview-breakpoints');
    parent = root.parent();
    links = root.find('.preview-breakpoints-item');
    preview = root.find('.preview');

    alreadyActive = linkItem.hasClass('active') ? true : false;

    links.removeClass('active');
    preview.css('margin-left', '0px');

    linkItem.toggleClass('active');

    if (alreadyActive) {
      linkItem.toggleClass('active');
    }

    if (linkItem.hasClass('active')) {
      newWidth = link.data('width');
      parentWidth = parent.innerWidth();
      preview.css("width", newWidth + 'px');

      if (newWidth > parentWidth) {
        offset = ((newWidth - parentWidth) / 2 * -1);

        preview.css('margin-left', offset + 'px');
      };
    } else {
      preview.css("width", "100%");
    }
  });

  var IFrameHeightObserver = function(iframe, index) {
    this.iframe = iframe;
    this.index = index;
    this.checkCount = 0;
    // lets memoize the access on the jquery element of our iframe
    this.$iframe = $(iframe);

    this.iframeBody = null;
    this.$iframeBody = null;
  };

  IFrameHeightObserver.prototype.checkDelay = 1500;
  IFrameHeightObserver.prototype.reCheckThreshold = 30;
  IFrameHeightObserver.prototype.defaultMinHeight = 100;

  IFrameHeightObserver.prototype.setFrameHeight = function(height) {
    this.$iframe.height(height + 'px');
    setTimeout(this.check.bind(this), this.checkDelay);
  };

  IFrameHeightObserver.prototype.getFrameHeight = function() {
    var frameHeight, bodyHeight, resultHeight = 0;

    if (this.$iframeBody.length > 0) {
      frameHeight = this.$iframeBody.attr('data-frame-height') || 0;
      // bodyHeight = Math.max(0, this.iframeBody.$.outerHeight(true) || 0);
      resultHeight = frameHeight; // Math.max(bodyHeight, frameHeight);

      if (this.$iframeBody.attr('data-frame-height') === undefined) {
        this.iframeBody = null;
        this.$iframeBody = null;
      }
    }
    return resultHeight > 0 ? resultHeight : this.defaultMinHeight;
  };

  IFrameHeightObserver.prototype.check = function() {
    if (Boolean(this.iframeBody) === false || this.$iframeBody.length < 1) {

      // seems that the iframe is not ready yet, and we don't have a reference to our desired content
      this.iframeDoc = this.iframe.contentWindow.document;
      this.iframeBody = this.iframeDoc.body;

      if (this.iframeBody) {

        this.$iframeBody = $(this.iframeBody);
        var currentHeight = this.getFrameHeight();
        this.setFrameHeight(currentHeight);

        this.checkCount = 0;

      } else {
        console.log('cannot get iframe body', this.index)
        if (this.checkCount <= this.reCheckThreshold) {
          this.checkCount++;
          setTimeout(this.check.bind(this), this.checkDelay);
          return;
        } else {
          console.error('IframeObserver reached Checkcount', this.index)
        }

      }

    } else {
      this.setFrameHeight(this.getFrameHeight());
    }

    return this;
  };

  $.each($('.preview > iframe'), function(i, iframe) {
    new IFrameHeightObserver(iframe, i).check();
  });
}(window && window.jQuery))
<commit_msg>re-enabled tab behavior<commit_after>(function($){
  "use strict";

  $('.content-group .content-group-nav-link').on('click', function(e) {
    var tabs, link, navItem;
    e.preventDefault();

    link = $(e.target);
    navItem = link.closest('.content-group-nav-item');
    tabs = link.closest('.content-group');

    tabs.find('.content-group-item, .content-group-nav-item').removeClass('active');
    navItem.addClass('active');
    tabs.find(link.attr('href')).addClass('active')
  });

  var OffCanvasNav = function(nav, content) {
    if (!nav) {
      console.error("Off-Canvas Navigation not found", nav);
    }

    if (!content) {
      console.error("Off-Canvas Content not found", content);
    }

    this.nav = nav.jquery ? nav : $(nav);
    this.content = content.jquery ? content : $(content);
  };

  OffCanvasNav.prototype.showNav = function() {
    var navWidth = this.nav.width();

    this.content
    .addClass('active')
    .css('-moz-transform', `translateX(${ navWidth }px)`)
    .css('-webkit-transform', `translateX(${ navWidth }px)`)
    .css('-o-transform', `translateX(${ navWidth }px)`)
    .css('-ms-transform', `translateX(${ navWidth }px)`)
    .css('transform', `translateX(${ navWidth }px)`);
  };

  OffCanvasNav.prototype.hideNav = function() {
    this.content
    .removeClass('active')
    .css('-moz-transform', `translateX(0px)`)
    .css('-webkit-transform', `translateX(0px)`)
    .css('-o-transform', `translateX(0px)`)
    .css('-ms-transform', `translateX(0px)`)
    .css('transform', `translateX(0px)`);
  };

  OffCanvasNav.prototype.toggleNav = function() {
    console.log('toggle')
    if (this.content.hasClass('active')) {
      this.hideNav();
    } else {
      this.showNav();
    }
  };

  var ocContent = $('.off-canvas-content')[0];
  var ocNav = $('.off-canvas-nav')[0];

  var offCanvasNav = new OffCanvasNav(ocNav, ocContent);

  $('.nav-toggle').on('click', function(e) {
    offCanvasNav.toggleNav();
  });

  var touchContent = new Hammer.Manager(ocContent);
  var touchNav = new Hammer.Manager(ocNav);

  // var the pan gesture support all directions.
  // this will block the vertical scrolling on a touch-device while on the element
  // mc.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL })
  touchContent.add( new Hammer.Swipe({ direction: Hammer.DIRECTION_HORIZONTAL }) );
  touchNav.add( new Hammer.Swipe({ direction: Hammer.DIRECTION_HORIZONTAL }) );

  touchContent.on("swiperight", function(ev) {
    offCanvasNav.showNav();
  });

  touchContent.on("swipeleft", function(ev) {
    offCanvasNav.hideNav();
  });

  touchNav.on("swipeleft", function(ev) {
    offCanvasNav.hideNav();
  });

// preview-breakpoints-button
//
  $('.preview-breakpoints-button').on('click', function(e) {
    var link, links, root, preview, linkItem, alreadyActive, parent, newWidth, parentWidth, offset;
    e.preventDefault();

    link = $(e.target);
    linkItem = link.closest('.preview-breakpoints-item');
    root = link.closest('.preview-breakpoints');
    parent = root.parent();
    links = root.find('.preview-breakpoints-item');
    preview = root.find('.preview');

    alreadyActive = linkItem.hasClass('active') ? true : false;

    links.removeClass('active');
    preview.css('margin-left', '0px');

    linkItem.toggleClass('active');

    if (alreadyActive) {
      linkItem.toggleClass('active');
    }

    if (linkItem.hasClass('active')) {
      newWidth = link.data('width');
      parentWidth = parent.innerWidth();
      preview.css("width", newWidth + 'px');

      if (newWidth > parentWidth) {
        offset = ((newWidth - parentWidth) / 2 * -1);

        preview.css('margin-left', offset + 'px');
      };
    } else {
      preview.css("width", "100%");
    }
  });

  var IFrameHeightObserver = function(iframe, index) {
    this.iframe = iframe;
    this.index = index;
    this.checkCount = 0;
    // lets memoize the access on the jquery element of our iframe
    this.$iframe = $(iframe);

    this.iframeBody = null;
    this.$iframeBody = null;
  };

  IFrameHeightObserver.prototype.checkDelay = 1500;
  IFrameHeightObserver.prototype.reCheckThreshold = 30;
  IFrameHeightObserver.prototype.defaultMinHeight = 100;

  IFrameHeightObserver.prototype.setFrameHeight = function(height) {
    this.$iframe.height(height + 'px');
    setTimeout(this.check.bind(this), this.checkDelay);
  };

  IFrameHeightObserver.prototype.getFrameHeight = function() {
    var frameHeight, bodyHeight, resultHeight = 0;

    if (this.$iframeBody.length > 0) {
      frameHeight = this.$iframeBody.attr('data-frame-height') || 0;
      // bodyHeight = Math.max(0, this.iframeBody.$.outerHeight(true) || 0);
      resultHeight = frameHeight; // Math.max(bodyHeight, frameHeight);

      if (this.$iframeBody.attr('data-frame-height') === undefined) {
        this.iframeBody = null;
        this.$iframeBody = null;
      }
    }
    return resultHeight > 0 ? resultHeight : this.defaultMinHeight;
  };

  IFrameHeightObserver.prototype.check = function() {
    if (Boolean(this.iframeBody) === false || this.$iframeBody.length < 1) {

      // seems that the iframe is not ready yet, and we don't have a reference to our desired content
      this.iframeDoc = this.iframe.contentWindow.document;
      this.iframeBody = this.iframeDoc.body;

      if (this.iframeBody) {

        this.$iframeBody = $(this.iframeBody);
        var currentHeight = this.getFrameHeight();
        this.setFrameHeight(currentHeight);

        this.checkCount = 0;

      } else {
        console.log('cannot get iframe body', this.index)
        if (this.checkCount <= this.reCheckThreshold) {
          this.checkCount++;
          setTimeout(this.check.bind(this), this.checkDelay);
          return;
        } else {
          console.error('IframeObserver reached Checkcount', this.index)
        }

      }

    } else {
      this.setFrameHeight(this.getFrameHeight());
    }

    return this;
  };

  $.each($('.preview > iframe'), function(i, iframe) {
    new IFrameHeightObserver(iframe, i).check();
  });
}(window && window.jQuery))
<|endoftext|>


<commit_before>'use strict';

var forEachIcon = require('./for-each-icon');

var writeCssScss = function(iconPaths, scssPath) {

	var iconInfos = [];

	var fs = require('fs');
	var scss = fs.createWriteStream(scssPath);

	scss.write('@import \'icons.scss\';\n\n');

	scss.write('[class*=" d2l-icon-"],\n');
	scss.write('[class^="d2l-icon-"] { \n');
	scss.write('	@include d2l-icon();\n');
	scss.write('}\n\n');

	return forEachIcon(iconPaths, function(iconInfo) {

		if (!iconInfo.isRtl) {
			iconInfos.push(iconInfo);
		}

	}).then( function() {

		iconInfos.sort(function(a,b) {
			if (a.className > b.className) {
				return 1;
			}
			if (a.className < b.className) {
				return -1;
			}
			return 0;
		});

		for(var i=0; i<iconInfos.length; i++) {
			var iconInfo = iconInfos[i];
			if (!iconInfo.isRtl) {
				scss.write('.' + iconInfo.className + ' {\n');
				scss.write('	@include ' + iconInfo.mixin + ';\n');
				scss.write('}\n');
			}
		}

	}).then( function() {

		var deferred = require('q').defer();

		scss.on('finish', function() {
			deferred.resolve();
		});

		scss.end();

		return deferred.promise;

	});

};

module.exports = writeCssScss;
<commit_msg>still outputting icon CSS for "vui-" based icons<commit_after>'use strict';

var forEachIcon = require('./for-each-icon');

var writeCssScss = function(iconPaths, scssPath) {

	var iconInfos = [];

	var fs = require('fs');
	var scss = fs.createWriteStream(scssPath);

	scss.write('@import \'icons.scss\';\n\n');

	scss.write('[class*=" d2l-icon-"],\n');
	scss.write('[class^="d2l-icon-"], { \n');
	scss.write('[class*=" vui-icon-"],\n');
	scss.write('[class^="vui-icon-"] { \n');
	scss.write('	@include d2l-icon();\n');
	scss.write('}\n\n');

	return forEachIcon(iconPaths, function(iconInfo) {

		if (!iconInfo.isRtl) {
			iconInfos.push(iconInfo);
		}

	}).then( function() {

		iconInfos.sort(function(a,b) {
			if (a.className > b.className) {
				return 1;
			}
			if (a.className < b.className) {
				return -1;
			}
			return 0;
		});

		for(var i=0; i<iconInfos.length; i++) {
			var iconInfo = iconInfos[i];
			if (!iconInfo.isRtl) {
				scss.write('.' + iconInfo.className + ' {\n');
				scss.write('	@include ' + iconInfo.mixin + ';\n');
				scss.write('}\n');
			}
		}

	}).then( function() {

		var deferred = require('q').defer();

		scss.on('finish', function() {
			deferred.resolve();
		});

		scss.end();

		return deferred.promise;

	});

};

module.exports = writeCssScss;
<|endoftext|>


<commit_before>/**
* @license
* Copyright 2019 The FOAM Authors. All Rights Reserved.
* http://www.apache.org/licenses/LICENSE-2.0
*/

foam.CLASS({
  package: 'org.chartjs',
  name: 'AbstractChartView',
  extends: 'foam.u2.View',
  requires: [
    'foam.dao.FnSink',
    'org.chartjs.ChartCView'
  ],
  properties: [
    {
      class: 'foam.dao.DAOProperty',
      name: 'data'
    },
    {
      class: 'Map',
      name: 'config',
    },
    {
      class: 'Int',
      name: 'width',
      value: 750
    },
    {
      class: 'Int',
      name: 'height',
      value: 750
    }
  ],

  methods: [
    function initE() {
      this.onDetach(this.data$proxy.listen(this.FnSink.create({ fn: this.dataUpdate })));
      this.dataUpdate();
      this.style({
        display: 'inline-block',
        width: this.width$,
        height: this.height$
      });
      this.add(this.ChartCView.create({ config$: this.config$, width$: this.width$, height$: this.height$ }));
    }
  ],

  listeners: [
    {
      name: 'dataUpdate',
      isFramed: true,
      code: function() {
        // Template function.
      }
    }
  ]
});
<commit_msg>Make chart view handle resizing better<commit_after>/**
* @license
* Copyright 2019 The FOAM Authors. All Rights Reserved.
* http://www.apache.org/licenses/LICENSE-2.0
*/

foam.CLASS({
  package: 'org.chartjs',
  name: 'AbstractChartView',
  extends: 'foam.u2.View',
  requires: [
    'foam.dao.FnSink',
    'org.chartjs.ChartCView'
  ],
  properties: [
    {
      class: 'foam.dao.DAOProperty',
      name: 'data'
    },
    {
      class: 'Map',
      name: 'config',
      preSet: function(_, n) {
        // We do the responsiveness so don't rely on chartjs.
        n.options.responsive = false;
        return n;
      }
    },
    {
      name: 'parentEl_',
    },
    {
      name: 'chart_',
      factory: function() {
        var el = this.parentEl_ && this.parentEl_.el();
        if ( ! el ) return null;
        return this.ChartCView.create({
          config$: this.config$,
          height: el.clientHeight,
          width: el.clientWidth
        })
      }
    }
  ],

  methods: [
    function initE() {
      this.onDetach(this.data$proxy.listen(this.FnSink.create({ fn: this.dataUpdate })));
      this.dataUpdate();
      window.addEventListener('resize', this.onResize);
      this
        .start('div', null, this.parentEl_$)
          .style({
            width: '100%',
            height: '100%'
          })
          .add(this.chart_$)
        .end();

    }
  ],
  reactions: [
    ['parentEl_', 'onload', 'onResize']
  ],
  listeners: [
    {
      name: 'onResize',
      isFramed: true,
      code: function() {
        this.chart_ = undefined;
      }
    },
    {
      name: 'dataUpdate',
      isFramed: true,
      code: function() {
        // Template function.
      }
    }
  ]
});<|endoftext|>


<commit_before>function onSwaggerButtonClick()
{
    window.swagger = new SwaggerClient
        (
            {
                url: "http://api.gra.fit:5000/swagger.json",
                useJQuery: true,
                success: function()
                {
                    // upon connect, fetch a pet and set contents to element "mydata"
                    // swagger.apis.metrics.get_metric_resource_list
                    swagger.apis.default.get_metric_resource_list
                    (
                        {responseContentType: 'application/json'},
                        function(data)
                        {
                            document.getElementById("mydata").innerHTML = JSON.stringify(data.obj);
                        }
                    );
                }
            }
        );
}
<commit_msg>Removed confusing comment<commit_after>function onSwaggerButtonClick()
{
    window.swagger = new SwaggerClient
        (
            {
                url: "http://api.gra.fit:5000/swagger.json",
                useJQuery: true,
                success: function()
                {
                    // swagger.apis.metrics.get_metric_resource_list
                    swagger.apis.default.get_metric_resource_list
                    (
                        {responseContentType: 'application/json'},
                        function(data)
                        {
                            document.getElementById("mydata").innerHTML = JSON.stringify(data.obj);
                        }
                    );
                }
            }
        );
}
<|endoftext|>


<commit_before>/*
* 2013 Jakub Siemiatkowski
* @sasklacz
* jsiemiatkowski at gmail.com
*
*/
(function(){
    /*
    * Array storing events to be rendered in the calendar
    */
    var EVENTS_TO_RENDER = [];

    /*
    * Object storing events as keys, and array of their overlapping events as values
    */
    var EVENTS_OVERLAPPING = {};

    /*
    * Object storing events with position and width already set
    */
    var EVENTS_READY = {};

    /*
    * Template of a single event in the calendar
    */
    var EVENT_TEMPLATE = [
        '
',
            '

',
            '
',
                '
',
                    'Sample Item',
                    'Sample Location',
                '
',
            '
',
        '
'
    ].join('');

    /*
    * ID selector for the calendar DOM element where events are to be added
    */
    var CALENDAR_SELECTOR = 'scheduler';

    /*
    * Function for sorting array of event objects by their start and position paremeters. Added to prototype
    * for better readability
    */
    Array.prototype.sortArray = function () {
        this.sort(function(a, b) {
            if (a.start > b.start){
                return 1;
            } else if (a.start  b.position){
                    return 1;
                } else if (a.position < b.position){
                    return -1;
                }
                return 0;
            }
        });
    };

    /*
    * Fill string template with data using simple regexes
    */
    var fillTemplate = function (data) {
        var _template = EVENT_TEMPLATE,
            key, regex;

        for (key in data) {
            regex     = new RegExp('{{' + key + '}}', 'ig');
            _template = (_template).replace(regex, data[key]);
        }

        return _template;
    };

    /*
    * Check all events against themselves if they're start/end values overlap.
    */
    var getEventsOverlapping = function(){
        var currentStart,
            currentEnd,
            objectKey,
            overlappingEvent;

        for (var i=0, l=EVENTS_TO_RENDER.length; i<l; i+=1){
            currentStart = EVENTS_TO_RENDER[i].start;
            currentEnd   = EVENTS_TO_RENDER[i].end;
            objectKey    = currentStart+'*'+currentEnd+'*'+EVENTS_TO_RENDER[i].position;

            EVENTS_OVERLAPPING[objectKey] = {items: {}, length: 0};

            for (var j=0; j<l; j+=1){
                if (j !== i){
                    overlappingEvent = EVENTS_TO_RENDER[j];
                    if ((overlappingEvent.start < currentStart && overlappingEvent.end > currentStart) ||
                        (overlappingEvent.start > currentStart && overlappingEvent.start < currentEnd) ||
                        overlappingEvent.start === currentStart && overlappingEvent.end > currentStart){
                        EVENTS_OVERLAPPING[objectKey].items[overlappingEvent.start+'*'+overlappingEvent.end+'*'+
                            overlappingEvent.position]       = 1;
                        EVENTS_OVERLAPPING[objectKey].length += 1;
                    }
                }
            }

            if (!overlappingEvent){
                EVENTS_OVERLAPPING[objectKey] = null;
            }
        }
    };

    /*
    * This function performs few operations. It accepts object with overlapping events of event to be rendered (let's call it E).
    * First of all it checks if E has any overlapping events. If not - then we know that it can take the full available width
    * and will be positioned at x=0. If there are overlapping events we check if they overlap with each other, because if they don't
    * then one event from each pair doesn't influence the width of E, but still it's x position can be influenced (e2) :

    ********
    *  e1  *  *******
    ********  *  E  *
    ********  *******
    *  e2  *
    ********

    * Finally we find the x position of E using the positions of events that were already positioned.
    */
    var checkCollidingOverlapping = function (overlapObject, eventKey){
        var width                   = null,
            left                    = 0,
            startingLefts           = {},
            overlappingEventsAmount = overlapObject.length,
            collidingEvents         = {},
            collidingEventsPairs    = 0,
            overlappingIEvents,
            overlapReadyIEvent;

        if (overlapObject){
            for(var i in overlapObject.items){
                //added for jshint
                if (overlapObject.items.hasOwnProperty(i)){
                    overlapReadyIEvent = EVENTS_READY[i];
                    overlappingIEvents = EVENTS_OVERLAPPING[i].items;

                    for (var m in overlapObject.items){
                        if (overlapObject.items.hasOwnProperty(m) && collidingEvents[m] !== i &&
                            collidingEvents[i] !== m && !overlappingIEvents[m] && m !== i &&
                            m !== eventKey && i !== eventKey){
                            collidingEvents[i]   = m;
                            collidingEvents[m]   = i;
                            collidingEventsPairs += 1;
                        }
                    }
                    if (overlapReadyIEvent){
                        startingLefts[overlapReadyIEvent.left] = 1;
                        //overlapping events should have the same width so we can use the value of an already
                        //rendered event
                        width = overlapReadyIEvent.width;
                    }
                }
            }

            overlappingEventsAmount -= collidingEventsPairs;
            if (!width){
                width = 600 / (overlappingEventsAmount + 1);
            }

            for (var k in startingLefts){
                if (startingLefts[left]){
                    left += width;
                }
            }
        } else {
            width = 600;
        }

        return {
            width: width,
            left : left
        };
    };

    /*
    * Function that adds additional properties to events in `EVENTS_TO_RENDER` array, so that they can be
    * positioned properly in the calendar. Events with calculated position are added to `EVENTS_READY` object.
    */
    var prepareRenderData = function(){
        var currentEvent,
            overlappingEvents,
            eventKey,
            width,
            left;

        EVENTS_READY = {};
        EVENTS_TO_RENDER.sortArray();

        for (var i=0, l=EVENTS_TO_RENDER.length; i<l; i+=1){
            currentEvent      = EVENTS_TO_RENDER[i];
            eventKey          = currentEvent.start+'*'+currentEvent.end+'*'+currentEvent.position;
            overlappingEvents = checkCollidingOverlapping(EVENTS_OVERLAPPING[eventKey], eventKey);

            width = overlappingEvents.width;
            left  = overlappingEvents.left;

            currentEvent.top          = currentEvent.start;
            currentEvent.width        = width;
            currentEvent.left         = left;
            currentEvent.height       = currentEvent.end - currentEvent.start;
            currentEvent.contentWidth = currentEvent.width - 4;

            EVENTS_READY[eventKey]    = {
                left: left,
                width : width
            };
        }
    };

    /*
    * Function generating HTML for the calendar DOM element using a predefined template. I've chosen template
    * in place of DOM elements, as for each event I'm setting values for 2 elements and even when a DOM Fragment
    * was used it would still be slower and more tedious in my oppinion.
    */
    var renderEvents = function () {
        var calendarElement = document.getElementById(CALENDAR_SELECTOR),
            renderHTML      = '';

        for (var i=0, l=EVENTS_TO_RENDER.length; i<l; i+=1){
            renderHTML += fillTemplate(EVENTS_TO_RENDER[i]);
        }
        calendarElement.innerHTML = renderHTML;
    };

    /*
    * Function responsible for adding new events to `EVENTS_TO_RENDER` array. Also checks validity of input data.
    */
    var addEvents = function (events) {
        var modifiedEvents = 0,
            //in modern browsers caching prototype chain like this doesn't help but in older IE's it still does
            cachedToString = Object.prototype.toString,
            eventsData,
            eventEnd,
            eventStart;

        //today is tuesday so I choose this method of testing Array/Object
        if (cachedToString.call(events) === "[object Array]"){
            eventsData = events;
        } else if (cachedToString.call(events) === "[object Object]"){
            eventsData = [];
            eventsData.push(events);
        } else {
            throw 'Wrong data type';
        }

        for (var i=0, l=eventsData.length; i<l; i+=1){
            eventStart = eventsData[i].start;
            eventEnd   = eventsData[i].end;

            //check if event object has the required properties. I'm skipping test for numerical value.
            if (eventStart != null && eventEnd != null && eventStart < eventEnd &&
                eventStart >= 0 && eventEnd <= 720){

                //creating new object in case the original had any additional properties
                EVENTS_TO_RENDER.push({
                    start : eventStart,
                    end   : eventEnd,
                    position : EVENTS_TO_RENDER.length
                });
                modifiedEvents = 1;
            }
        }

        //we don't want to refresh the DOM if nothing changed
        if (modifiedEvents){
            getEventsOverlapping();
            prepareRenderData();
            renderEvents();

            return true;
        }
        //return value tells us if the view was refreshed
        return false;
    };

    //we need this function in the global scope
    window.addEvents = addEvents;
})();

//as required in the doc
function layOutDay (events) {
    return addEvents(events);
};<commit_msg>- get the simple version running<commit_after>/*
* 2013 Jakub Siemiatkowski
* @sasklacz
* jsiemiatkowski at gmail.com
*
*/
import './app.scss';

(function(){
    /*
    * Array storing events to be rendered in the calendar
    */
    var EVENTS_TO_RENDER = [];

    /*
    * Object storing events as keys, and array of their overlapping events as values
    */
    var EVENTS_OVERLAPPING = {};

    /*
    * Object storing events with position and width already set
    */
    var EVENTS_READY = {};

    /*
    * Template of a single event in the calendar
    */
    var EVENT_TEMPLATE = [
        '
',
            '

',
            '
',
                '
',
                    'Sample Item',
                    'Sample Location',
                '
',
            '
',
        '
'
    ].join('');

    /*
    * ID selector for the calendar DOM element where events are to be added
    */
    var CALENDAR_SELECTOR = 'scheduler';

    /*
    * Function for sorting array of event objects by their start and position paremeters. Added to prototype
    * for better readability
    */
    Array.prototype.sortArray = function () {
        this.sort(function(a, b) {
            if (a.start > b.start){
                return 1;
            } else if (a.start  b.position){
                    return 1;
                } else if (a.position < b.position){
                    return -1;
                }
                return 0;
            }
        });
    };

    /*
    * Fill string template with data using simple regexes
    */
    var fillTemplate = function (data) {
        var _template = EVENT_TEMPLATE,
            key, regex;

        for (key in data) {
            regex     = new RegExp('{{' + key + '}}', 'ig');
            _template = (_template).replace(regex, data[key]);
        }

        return _template;
    };

    /*
    * Check all events against themselves if they're start/end values overlap.
    */
    var getEventsOverlapping = function(){
        var currentStart,
            currentEnd,
            objectKey,
            overlappingEvent;

        for (var i=0, l=EVENTS_TO_RENDER.length; i<l; i+=1){
            currentStart = EVENTS_TO_RENDER[i].start;
            currentEnd   = EVENTS_TO_RENDER[i].end;
            objectKey    = currentStart+'*'+currentEnd+'*'+EVENTS_TO_RENDER[i].position;

            EVENTS_OVERLAPPING[objectKey] = {items: {}, length: 0};

            for (var j=0; j<l; j+=1){
                if (j !== i){
                    overlappingEvent = EVENTS_TO_RENDER[j];
                    if ((overlappingEvent.start < currentStart && overlappingEvent.end > currentStart) ||
                        (overlappingEvent.start > currentStart && overlappingEvent.start < currentEnd) ||
                        overlappingEvent.start === currentStart && overlappingEvent.end > currentStart){
                        EVENTS_OVERLAPPING[objectKey].items[overlappingEvent.start+'*'+overlappingEvent.end+'*'+
                            overlappingEvent.position]       = 1;
                        EVENTS_OVERLAPPING[objectKey].length += 1;
                    }
                }
            }

            if (!overlappingEvent){
                EVENTS_OVERLAPPING[objectKey] = null;
            }
        }
    };

    /*
    * This function performs few operations. It accepts object with overlapping events of event to be rendered (let's call it E).
    * First of all it checks if E has any overlapping events. If not - then we know that it can take the full available width
    * and will be positioned at x=0. If there are overlapping events we check if they overlap with each other, because if they don't
    * then one event from each pair doesn't influence the width of E, but still it's x position can be influenced (e2) :

    ********
    *  e1  *  *******
    ********  *  E  *
    ********  *******
    *  e2  *
    ********

    * Finally we find the x position of E using the positions of events that were already positioned.
    */
    var checkCollidingOverlapping = function (overlapObject, eventKey){
        var width                   = null,
            left                    = 0,
            startingLefts           = {},
            overlappingEventsAmount = overlapObject.length,
            collidingEvents         = {},
            collidingEventsPairs    = 0,
            overlappingIEvents,
            overlapReadyIEvent;

        if (overlapObject){
            for(var i in overlapObject.items){
                //added for jshint
                if (overlapObject.items.hasOwnProperty(i)){
                    overlapReadyIEvent = EVENTS_READY[i];
                    overlappingIEvents = EVENTS_OVERLAPPING[i].items;

                    for (var m in overlapObject.items){
                        if (overlapObject.items.hasOwnProperty(m) && collidingEvents[m] !== i &&
                            collidingEvents[i] !== m && !overlappingIEvents[m] && m !== i &&
                            m !== eventKey && i !== eventKey){
                            collidingEvents[i]   = m;
                            collidingEvents[m]   = i;
                            collidingEventsPairs += 1;
                        }
                    }
                    if (overlapReadyIEvent){
                        startingLefts[overlapReadyIEvent.left] = 1;
                        //overlapping events should have the same width so we can use the value of an already
                        //rendered event
                        width = overlapReadyIEvent.width;
                    }
                }
            }

            overlappingEventsAmount -= collidingEventsPairs;
            if (!width){
                width = 600 / (overlappingEventsAmount + 1);
            }

            for (var k in startingLefts){
                if (startingLefts[left]){
                    left += width;
                }
            }
        } else {
            width = 600;
        }

        return {
            width: width,
            left : left
        };
    };

    /*
    * Function that adds additional properties to events in `EVENTS_TO_RENDER` array, so that they can be
    * positioned properly in the calendar. Events with calculated position are added to `EVENTS_READY` object.
    */
    var prepareRenderData = function(){
        var currentEvent,
            overlappingEvents,
            eventKey,
            width,
            left;

        EVENTS_READY = {};
        EVENTS_TO_RENDER.sortArray();

        for (var i=0, l=EVENTS_TO_RENDER.length; i<l; i+=1){
            currentEvent      = EVENTS_TO_RENDER[i];
            eventKey          = currentEvent.start+'*'+currentEvent.end+'*'+currentEvent.position;
            overlappingEvents = checkCollidingOverlapping(EVENTS_OVERLAPPING[eventKey], eventKey);

            width = overlappingEvents.width;
            left  = overlappingEvents.left;

            currentEvent.top          = currentEvent.start;
            currentEvent.width        = width;
            currentEvent.left         = left;
            currentEvent.height       = currentEvent.end - currentEvent.start;
            currentEvent.contentWidth = currentEvent.width - 4;

            EVENTS_READY[eventKey]    = {
                left: left,
                width : width
            };
        }
    };

    /*
    * Function generating HTML for the calendar DOM element using a predefined template. I've chosen template
    * in place of DOM elements, as for each event I'm setting values for 2 elements and even when a DOM Fragment
    * was used it would still be slower and more tedious in my oppinion.
    */
    var renderEvents = function () {
        var calendarElement = document.getElementById(CALENDAR_SELECTOR),
            renderHTML      = '';

        for (var i=0, l=EVENTS_TO_RENDER.length; i<l; i+=1){
            renderHTML += fillTemplate(EVENTS_TO_RENDER[i]);
        }
        calendarElement.innerHTML = renderHTML;
    };

    /*
    * Function responsible for adding new events to `EVENTS_TO_RENDER` array. Also checks validity of input data.
    */
    var addEvents = function (events) {
        var modifiedEvents = 0,
            //in modern browsers caching prototype chain like this doesn't help but in older IE's it still does
            cachedToString = Object.prototype.toString,
            eventsData,
            eventEnd,
            eventStart;

        //today is tuesday so I choose this method of testing Array/Object
        if (cachedToString.call(events) === "[object Array]"){
            eventsData = events;
        } else if (cachedToString.call(events) === "[object Object]"){
            eventsData = [];
            eventsData.push(events);
        } else {
            throw 'Wrong data type';
        }

        for (var i=0, l=eventsData.length; i<l; i+=1){
            eventStart = eventsData[i].start;
            eventEnd   = eventsData[i].end;

            //check if event object has the required properties. I'm skipping test for numerical value.
            if (eventStart != null && eventEnd != null && eventStart < eventEnd &&
                eventStart >= 0 && eventEnd <= 720){

                //creating new object in case the original had any additional properties
                EVENTS_TO_RENDER.push({
                    start : eventStart,
                    end   : eventEnd,
                    position : EVENTS_TO_RENDER.length
                });
                modifiedEvents = 1;
            }
        }

        //we don't want to refresh the DOM if nothing changed
        if (modifiedEvents){
            getEventsOverlapping();
            prepareRenderData();
            renderEvents();

            return true;
        }
        //return value tells us if the view was refreshed
        return false;
    };

    //we need this function in the global scope
    window.addEvents = addEvents;
})();

//as required in the doc
window.layOutDay = function (events) {
    return addEvents(events);
};<|endoftext|>


<commit_before>(function (NS) {
    "use strict";

    var links = NS.links,
        $ = NS.jQuery,
        moment = NS.moment,
        data,
        resources = {
            "atti": ["/json/test.json"]
        },
        options = {
            'width': '100%',
            'height': '300px',
            'editable': false,   // enable dragging and editing events
            'style': 'box'
        };

    function parsePayload(payload) {
        var idx,
            data = [],
            start,
            end,
            content,
            each,
            item;

        for (idx = 0; idx < payload.length; idx++) {
            each = payload[idx];
            start = each.start;
            content = each.content;

            item = {
                "start": moment(start),
                "content": content.title + ": " + content.count
            };
            end = each.end;
            if (end) {
                item.end = moment(end);
            }
            data.push(item);
        }

        return data;
    }

    function timelineRender(payload, renderer) {
        data = parsePayload(payload);
        renderer.draw(data);
    }

    var drawVisualization = function (targetDatasetName, callback) {
        var elem = NS.document.getElementById(targetDatasetName),
            timelineRenderer = new links.Timeline(elem, options),
            resourceUrl = resources[targetDatasetName],
            cb = function (data) {
                callback(data, timelineRenderer);
            };

        $.get(resourceUrl, null, cb, "json");

        // attach an event listener using the links events handler
        //links.events.addListener(timeline, 'rangechanged', onRangeChanged);
    };

    drawVisualization("atti", timelineRender);

}(this));<commit_msg>Setup the timeline graph.<commit_after>(function (NS) {
    "use strict";

    var links = NS.links,
        $ = NS.jQuery,
        moment = NS.moment,
        data,
        resources = {
            "atti": [
                "json/data_cluster_mensile.json",
                "json/data_legislature.json"
            ]
        },
        options = {
            width: '100%',
            height: 'auto',
            layout: "box",
            eventMargin: 0,  // minimal margin between events
            eventMarginAxis: 0, // minimal margin beteen events and the axis
            editable: false,   // enable dragging and editing events
            style: 'box',
            stackEvents: false
        };

    function parsePayload(payload) {
        var idx,
            data = [],
            start,
            end,
            content,
            each,
            item;

        for (idx = 0; idx < payload.length; idx++) {
            each = payload[idx];
            start = each.start;
            content = each.content;

            item = {
                "start": moment(start),
                "content": content.count
            };
            end = each.end;
            if (end) {
                item.end = moment(end);
            }
            data.push(item);
        }

        return data;
    }

    function timelineRender(payload, renderer) {
        data = parsePayload(payload);
        renderer.draw(data);
    }

    var drawVisualization = function (targetDatasetName, callback) {
        var elem = NS.document.getElementById(targetDatasetName),
            timelineRenderer = new links.Timeline(elem, options),
            resourceUrl = resources[targetDatasetName][0],
            cb = function (data) {
                callback(data, timelineRenderer);
            };

        $.get(resourceUrl, null, cb, "json");

        // attach an event listener using the links events handler
        //links.events.addListener(timeline, 'rangechanged', onRangeChanged);
    };

    drawVisualization("atti", timelineRender);

}(this));<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on views, and components
angular.module('baikalApp', [
  'ngRoute',
  'baikalApp.home',
  'baikalApp.about',
  'baikalApp.photo',
  'baikalApp.version',
  'baikalApp.services',
  'baikalApp.controllers',
  'baikalApp.filters',
  'pascalprecht.translate',
  'ngCookies',
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.otherwise({redirectTo: '/home'});
}])
.filter('to_trusted', ['$sce', function($sce){
    return function(text) {
        return $sce.trustAsHtml(text);
    };
}])
.config(function ($translateProvider) {
  $translateProvider.translations('ru', {
    TITLE: 'Лига Байкальских Капитанов',
    COPYRIGHT_TEXT: 'Все права защищены',
    COPYRIGHT_AUTHOR: 'Александр Бурмейстер',
    PHOTO: 'Фото',
    SPRING: 'Весна',
    SUMMER: 'Лето',
    AUTUMN: 'Осень',
    WINTER: 'Зима',
    ABOUT_US: 'О нас',
    FAMILY: 'Семья',
    MEDIA: 'СМИ',
    CREATIVE: 'Творчество',
    YOGA: 'Йога',
    OUR_GUESTS: 'Наши гости',
    JOURNEY: 'Путешествия',
    VOLUNTEERS: 'Волонтёры',
    CONTACTS: 'Контакты',
    FILMS: 'Фильмы',
    SPRING_BAIKAL_FILM: 'Байкал весной',
    SUMMER_BAIKAL_FILM: 'Байкал летом',
    AUTUMN_BAIKAL_FILM: 'Осенний байкал',
    WINTER_BAIKAL_FILM: 'Байкал зимой',
    WRITE_TO_YOU_FROM_BAIKAL: 'Пишу тебе с Байкала',
    SACRED_PLACES_OF_LAKE_BAIKAL: 'Сакральные места Байкала',
    BAIKAL_JOURNEY_TITLE: 'ЛИГА БАЙКАЛЬСКИХ ЛЕДОВЫХ КАПИТАНОВ им. А. Ю. БУРМЕЙСТЕРА',
    BAIKAL_JOURNEY_DESCRIPTION: 'У нас, в Сибири, говорят: «Тот, кто испил воды из священного озера Байкал, тот будет жить долго и счастливо». Здесь, на Байкале, существует и по сегодняшний день древнейшая культура общения Человека и Природы. Байкал завораживает, дает мудрость, истинное понимание красоты и раскрывает внутренние способности. Посвященным Байкал дает возможность пережить разные стихии: ураганный ветер, жесткие шторма, зеркальный штиль и чистейший лед!  Байкал формирует духовную культуру и истинные отношения между людьми. Дни, проведенные на Байкале, Господь не засчитывает в счет прожитых лет.',
    BAIKAL_JOURNEY_AUTHOR: 'Александр Бурмейстер',
    BAIKAL_JOURNEY_BUTTON: 'Отправиться в путешествие »',
    OUR_CONTACTS: 'Наши контакты',
    ADDRESS: 'Адрес',
    ADDRESS_TEXT: 'г. Иркутск, ул. Лермонтова, д. 777, кв. 7',
    PHONE: 'Телефон',
    PHONE_TEXT: '+7 (3952) 33-44-55',
    MUSIC_PLAY: 'Включить музыку'
  });
  $translateProvider.translations('en', {
    TITLE: 'Baikal Captain Ligue',
    COPYRIGHT_TEXT: 'All rights reserved',
    COPYRIGHT_AUTHOR: 'Alexander Burmeister',
    PHOTO: 'Photo',
    SPRING: 'Spring',
    SUMMER: 'Summer',
    AUTUMN: 'Autumn',
    WINTER: 'Winter',
    ABOUT_US: 'About us',
    FAMILY: 'Family',
    MEDIA: 'Media',
    CREATIVE: 'Creative',
    YOGA: 'Yoga',
    OUR_GUESTS: 'Our guests',
    JOURNEY: 'Journey',
    VOLUNTEERS: 'Volunteers',
    CONTACTS: 'Contacts',
    FILMS: 'Films',
    SPRING_BAIKAL_FILM: 'Spring Baikal',
    SUMMER_BAIKAL_FILM: 'Summer Baikal',
    AUTUMN_BAIKAL_FILM: 'Autumn Baikal',
    WINTER_BAIKAL_FILM: 'Winter Baikal',
    WRITE_TO_YOU_FROM_BAIKAL: 'Write to you from Baikal',
    SACRED_PLACES_OF_LAKE_BAIKAL: 'Sacred places of Lake Baikal',
    BAIKAL_JOURNEY_TITLE: 'BAIKAL LEAGUE of ICE CAPTAINS named after A.BURMEISTER',
    BAIKAL_JOURNEY_DESCRIPTION: 'In Siberia we say: «One that has tried water from the sacred lake Baikal, will live a long and happy life». There is still an ancient culture of communication between a Man and Nature. Baikal charms, gives wisdom, the real understanding of beauty, and reveals inner powers. Baikal gives initiated an opportunity to experiense different elements: storms, savage gales, smooth calm, and the cristal-clear ice! Baikal forms spiritual culture and true relationship between people. Days spent on the lake Baikal, the Lord doesn\'t count against past years.',
    BAIKAL_JOURNEY_AUTHOR: 'Aleksander Burmeister',
    BAIKAL_JOURNEY_BUTTON: 'Make a step to my adventure »',
    OUR_CONTACTS: 'Our contacts',
    ADDRESS: 'Address',
    ADDRESS_TEXT: 'Irkutsk, ul. Lermontova, 777, 7',
    PHONE: 'Phone',
    PHONE_TEXT: '+7 (3952) 33-44-55',
    MUSIC_PLAY: 'Play music'
  });
  $translateProvider.preferredLanguage('ru');
  $translateProvider.useLocalStorage();
});
<commit_msg>changes from home<commit_after>'use strict';

// Declare app level module which depends on views, and components
angular.module('baikalApp', [
  'ngRoute',
  'baikalApp.home',
  'baikalApp.about',
  'baikalApp.photo',
  'baikalApp.version',
  'baikalApp.services',
  'baikalApp.controllers',
  'baikalApp.filters',
  'pascalprecht.translate',
  'ngCookies',
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.otherwise({redirectTo: '/home'});
}])
.filter('to_trusted', ['$sce', function($sce){
    return function(text) {
        return $sce.trustAsHtml(text);
    };
}])
.config(function ($translateProvider) {
  $translateProvider.translations('ru', {
    TITLE: 'Лига Байкальских Капитанов',
    COPYRIGHT_TEXT: 'Все права защищены',
    COPYRIGHT_AUTHOR: 'Александр Бурмейстер',
    PHOTO: 'Фото',
    SPRING: 'Весна',
    SUMMER: 'Лето',
    AUTUMN: 'Осень',
    WINTER: 'Зима',
    ABOUT_US: 'О нас',
    FAMILY: 'Семья',
    MEDIA: 'СМИ',
    CREATIVE: 'Творчество',
    YOGA: 'Йога',
    OUR_GUESTS: 'Наши гости',
    JOURNEY: 'Путешествия',
    VOLUNTEERS: 'Волонтёры',
    CONTACTS: 'Контакты',
    FILMS: 'Фильмы',
    SPRING_BAIKAL: 'Байкал весной',
    SUMMER_BAIKAL: 'Байкал летом',
    AUTUMN_BAIKAL: 'Осенний байкал',
    WINTER_BAIKAL: 'Байкал зимой',
    WRITE_TO_YOU_FROM_BAIKAL: 'Пишу тебе с Байкала',
    SACRED_PLACES_OF_LAKE_BAIKAL: 'Сакральные места Байкала',
    BAIKAL_JOURNEY_TITLE: 'ЛИГА БАЙКАЛЬСКИХ ЛЕДОВЫХ КАПИТАНОВ им. А. Ю. БУРМЕЙСТЕРА',
    BAIKAL_JOURNEY_DESCRIPTION: 'У нас, в Сибири, говорят: «Тот, кто испил воды из священного озера Байкал, тот будет жить долго и счастливо». Здесь, на Байкале, существует и по сегодняшний день древнейшая культура общения Человека и Природы. Байкал завораживает, дает мудрость, истинное понимание красоты и раскрывает внутренние способности. Посвященным Байкал дает возможность пережить разные стихии: ураганный ветер, жесткие шторма, зеркальный штиль и чистейший лед!  Байкал формирует духовную культуру и истинные отношения между людьми. Дни, проведенные на Байкале, Господь не засчитывает в счет прожитых лет.',
    BAIKAL_JOURNEY_AUTHOR: 'Александр Бурмейстер',
    BAIKAL_JOURNEY_BUTTON: 'Отправиться в путешествие »',
    OUR_CONTACTS: 'Наши контакты',
    ADDRESS: 'Адрес',
    ADDRESS_TEXT: 'г. Иркутск, ул. Лермонтова, д. 777, кв. 7',
    PHONE: 'Телефон',
    PHONE_TEXT: '+7 (3952) 33-44-55',
    MUSIC_PLAY: 'Включить музыку'
  });
  $translateProvider.translations('en', {
    TITLE: 'Baikal Captain Ligue',
    COPYRIGHT_TEXT: 'All rights reserved',
    COPYRIGHT_AUTHOR: 'Alexander Burmeister',
    PHOTO: 'Photo',
    SPRING: 'Spring',
    SUMMER: 'Summer',
    AUTUMN: 'Autumn',
    WINTER: 'Winter',
    ABOUT_US: 'About us',
    FAMILY: 'Family',
    MEDIA: 'Media',
    CREATIVE: 'Creative',
    YOGA: 'Yoga',
    OUR_GUESTS: 'Our guests',
    JOURNEY: 'Journey',
    VOLUNTEERS: 'Volunteers',
    CONTACTS: 'Contacts',
    FILMS: 'Films',
    SPRING_BAIKAL: 'Spring Baikal',
    SUMMER_BAIKAL: 'Summer Baikal',
    AUTUMN_BAIKAL: 'Autumn Baikal',
    WINTER_BAIKAL: 'Winter Baikal',
    WRITE_TO_YOU_FROM_BAIKAL: 'Write to you from Baikal',
    SACRED_PLACES_OF_LAKE_BAIKAL: 'Sacred places of Lake Baikal',
    BAIKAL_JOURNEY_TITLE: 'BAIKAL LEAGUE of ICE CAPTAINS named after A.BURMEISTER',
    BAIKAL_JOURNEY_DESCRIPTION: 'In Siberia we say: «One that has tried water from the sacred lake Baikal, will live a long and happy life». There is still an ancient culture of communication between a Man and Nature. Baikal charms, gives wisdom, the real understanding of beauty, and reveals inner powers. Baikal gives initiated an opportunity to experiense different elements: storms, savage gales, smooth calm, and the cristal-clear ice! Baikal forms spiritual culture and true relationship between people. Days spent on the lake Baikal, the Lord doesn\'t count against past years.',
    BAIKAL_JOURNEY_AUTHOR: 'Aleksander Burmeister',
    BAIKAL_JOURNEY_BUTTON: 'Make a step to my adventure »',
    OUR_CONTACTS: 'Our contacts',
    ADDRESS: 'Address',
    ADDRESS_TEXT: 'Irkutsk, ul. Lermontova, 777, 7',
    PHONE: 'Phone',
    PHONE_TEXT: '+7 (3952) 33-44-55',
    MUSIC_PLAY: 'Play music'
  });
  $translateProvider.preferredLanguage('ru');
  $translateProvider.useLocalStorage();
});
<|endoftext|>


<commit_before>/*global require, Promise, console*/

var HeaderView = Backbone.View.extend({
    el: '#headerContainer',
    template: function() {
        return React.createClass({
            render: function () {
                return (

                        {this.props.model.brand}

                )
            }
        })
    },
    render: function() {
        var Template = this.template();
        React.render(
            <Template model={this.model.attributes}/>,
            $(this.el)[0]
        );
    }
});

$('document').ready(function() {

    $('select').material_select();

    var headerView = new HeaderView({
        model: new Backbone.Model()
    });
    headerView.model.set({
        brand: 'IssueTime'
    });
    headerView.render();

});<commit_msg>Added HeaderView events<commit_after>/*global require, Promise, console*/

var HeaderLink = React.createClass({
    clickEvent: function(e) {
        e.preventDefault();
        this.props.callback(this.props.page);
    },
    render: function() {
        return (

        )
    }
});

var HeaderView = React.createClass({
    headerLinkClicked: function(page) {
        this.props.callback(page);
    },
    brandClicked: function(e) {
        e.preventDefault();
    },
    render: function () {
        return (

                {this.props.model.brand}

                    <HeaderLink page="timer" iconClass="mdi-action-alarm" title="Timer" callback={this.headerLinkClicked} />
                    <HeaderLink page="projects" iconClass="mdi-action-description" title="Projects" callback={this.headerLinkClicked} />
                    <HeaderLink page="settings" iconClass="mdi-action-settings" title="Settings" callback={this.headerLinkClicked} />

        )
    }
});

var AppController = {

    headerModel: new Backbone.Model(),
    headerContainer: $('#headerContainer')[0],
    renderHeader: function() {
        React.render(
            <HeaderView model={this.headerModel.attributes} callback={this.headerLinkClick} />,
            this.headerContainer
        );
    },
    headerLinkClick: function(page) {
        console.log(page);
    },

    appContainer: $('#appContainer')[0],
    appModel: new Backbone.Model(),

    create: function() {
        return Object.create(this);
    },
    start: function() {
        this.headerModel.set('brand', 'IssueTime');
        this.renderHeader();
        return this;
    }
};

$('document').ready(function() {

    var appController = AppController.create().start();

    $('select').material_select();

    $('button').on({
        click: function(e) {
            e.preventDefault();
            appController.headerModel.set('brand', 'TissueTime');
            appController.renderHeader();
        }
    })

});<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on filters, and services
var myApp = angular.module('myApp', [
  'ngRoute',
  'myApp.filters',
  'socialTradeServices',
  'myApp.directives',
  'socialTradeControllers',
  'socialTradeAnimations',
  'login',
  'auth',
  'register',
  'newtrade',
  'angulartics',
  'angulartics.google.analytics',
  'firebaseService',
  'loginServices',
  'waitForAuth',
  'routeSecurity',
  'fblogin'
]);
/* FAKE login
myApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/trades', {templateUrl: 'partials/article-list.html', controller: 'ArticleListCtrl' });
  $routeProvider.when('/trades/:tradeId', {templateUrl: 'partials/article-detail.html', controller: 'ArticleDetailCtrl', requireLogin: true});
  $routeProvider.when('/login', {templateUrl: "partials/login.tpl.html", controller: "LoginCtrl", requireLogin: false });
  $routeProvider.when('/mytrades', {templateUrl: "partials/mytrades.html", controller: "ArticleListCtrl", requireLogin: true });
  $routeProvider.when('/myprofile', {templateUrl: "partials/myprofile.html", requireLogin: true });
  $routeProvider.when('/editprofile', {templateUrl: "partials/editprofile.html", controller: "UserEditCtrl", requireLogin: true });
  //$routeProvider.when('/logout',  {templateUrl: "partials/logout.html"});
  $routeProvider.when("/signup", {templateUrl: "partials/signup.html", controller: "SignUpCtrl", requireLogin: false });
  $routeProvider.when("/users", {templateUrl: "partials/user-list.html", controller: "UserListCtrl", requireLogin: true });
  $routeProvider.when("/users/:userId", {templateUrl: "partials/user-view.html", controller: "UserDetailCtrl", requireLogin: true });
  $routeProvider.when("/newtrade", {templateUrl: "partials/addlisting-view.html", controller: "AddListingCtrl", requireLogin: true });
  $routeProvider.otherwise({redirectTo: '/trades'});
}]).constant('FBURL', 'https://socialtrade.firebaseio.com').constant('loginRedirectPath', '/login')
; */
myApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/trades', {templateUrl: 'partials/article-list.html', controller: 'ArticleListCtrl' });
  $routeProvider.when('/trades/:tradeId', {templateUrl: 'partials/article-detail.html', controller: 'ArticleDetailCtrl', authRequired: true});
  $routeProvider.when('/login', {templateUrl: "partials/login.tpl.html", controller: "LoginCtrl"});
  $routeProvider.when('/mytrades', {templateUrl: "partials/mytrades.html", controller: "ArticleListCtrl", authRequired: true});
  $routeProvider.when('/myprofile', {templateUrl: "partials/myprofile.html", authRequired: true});
  $routeProvider.when('/editprofile', {templateUrl: "partials/editprofile.html", controller: "UserEditCtrl", authRequired: true });
  //$routeProvider.when('/logout',  {templateUrl: "partials/logout.html"});
  $routeProvider.when("/signup", {templateUrl: "partials/signup.html", controller: "SignUpCtrl"});
  $routeProvider.when("/users", {templateUrl: "partials/user-list.html", controller: "UserListCtrl", authRequired: true });
  $routeProvider.when("/users/:userId", {templateUrl: "partials/user-view.html", controller: "UserDetailCtrl", authRequired: true });
  $routeProvider.when("/newtrade", {templateUrl: "partials/addlisting-view.html", controller: "AddListingCtrl", authRequired: true });
  $routeProvider.otherwise({redirectTo: '/trades'});
}]).constant('FBURL', 'https://socialtrade.firebaseio.com').constant('loginRedirectPath', '/login')
;
/* FAKE login - Testing user's rights to access a url
myApp.run(['$rootScope', 'AuthService', '$location', function($rootScope, AuthService, $location){
    // Everytime the route in our app changes check auth status
    $rootScope.$on("$routeChangeStart", function(event, next, current) {
        // if you're logged out send to login page.
        if (next.requireLogin && !AuthService.getUserAuthenticated()) {
            $location.path('/login');
            event.preventDefault();
        }
    });
}]); */
myApp.run(['loginService', '$rootScope', 'FBURL', function(loginService, $rootScope, FBURL) {
   // establish authentication
   $rootScope.auth = loginService.init('/login');
   $rootScope.FBURL = FBURL;
}]);

/* Main App controller - used for "fake" authentication
 myApp.controller('MainCtrl', ['$scope', 'AuthService', '$location', function($scope, AuthService, $location) {

 	// check if user is authenticated on every page and return them
 	$scope.$on('$viewContentLoaded', function() {

		$scope.user = AuthService.getAuthenticatedUser();

	});
    $scope.logoutUser = function() {
        // run a logout function to your api
        AuthService.setUserAuthenticated(false);
        AuthService.setAuthenticatedUser(null);
        $location.path('/login');
    };

    $scope.isLoggedIn = function() {
        return AuthService.getUserAuthenticated();
    };
    $scope.isActive = function(url) {
    	return url == $location.$$url;
    };
}]);
*/
myApp.controller('MainCtrl', ['$scope', 'loginService', 'syncData', '$location', 'AuthService', 'firebaseRef', '$rootScope',
 function($scope, loginService, syncData, $location, AuthService, firebaseRef, $rootScope) {

      $scope.$on('$viewContentLoaded', function() {
        // $scope.user = AuthService.getAuthenticatedUser();
        if($scope.auth.user != null && $scope.auth.user.provider !== "google") {
          var id = parseInt($scope.auth.user.id);
          $scope.user =  syncData(['users', id-1]);
         // firebaseRef('users/'+$scope.user.id).update({online: true});
        }
      });
       $rootScope.$on("glogin", function(event, user) {
            // do login things
            //$scope.user = user;
            $scope.$apply;
            //find user by email
            //TODO: izboljsava - avtomatska registracija, ce ga se ni!
            console.log(user.email);
            $scope.tu = syncData('users');
            $scope.tu.$on("loaded", function() {
              var keys = $scope.tu.$getIndex();
              var reg = false;
              var id = 0;
               angular.forEach(keys, function(key) {
                 if($scope.tu[key].email === user.email) {
                    reg = true;
                    id = key;
                 }

                 //onsole.log(key, $scope.tu[key].email);
              });
              if(!reg) {

                  //TODO: automatically register user
                 $scope.logout();
                 $location.path("/signup");
              } else {
                //Get user
                $scope.user = syncData(["users", id]);
              }

            });

        });
        $rootScope.$on("fblogin", function(event, user) {
            // do login things
            //$scope.user = user;
            $scope.$apply;
            //find user by email
            //TODO: izboljsava - avtomatska registracija, ce ga se ni!
            //console.log(user.thirdPartyUserData.email);
            $scope.tu = syncData('users');
            $scope.tu.$on("loaded", function() {
              var keys = $scope.tu.$getIndex();
              var reg = false;
              var id = 0;
               angular.forEach(keys, function(key) {
                 if($scope.tu[key].email === user.thirdPartyUserData.email) {
                    reg = true;
                    id = key;
                 }

                 //onsole.log(key, $scope.tu[key].email);
              });
              if(!reg) {

                  //TODO: automatically register user
                 $scope.logout();
                 $location.path("/signup");
              } else {
                //Get user
                $scope.user = syncData(["users", id]);
              }

            });

        });

      //online = false v logoutu! - http://stackoverflow.com/questions/15982215/firebase-count-online-users
      $scope.logout = function() {
       //  AuthService.setUserAuthenticated(false);
      //   AuthService.setAuthenticatedUser(null);
        /*  $("#lgin").css("display","");
          $("#reg").css("display","");
          $("#lgout").css("display","none");
          $("#lginfo").css("display","none"); */
          if($scope.user != null) {
          $scope.user.online = false;
          $scope.user.last_active = ISODateString(new Date());
          firebaseRef('users/'+$scope.user.id).update({online: false, last_active: $scope.user.last_active});
          }
         loginService.logout();
      };
  }]);
function ISODateString(d){
 function pad(n){return n<10 ? '0'+n : n}
 return d.getUTCFullYear()+'-'
      + pad(d.getUTCMonth()+1)+'-'
      + pad(d.getUTCDate())+'T'
      + pad(d.getUTCHours())+':'
      + pad(d.getUTCMinutes())+':'
      + pad(d.getUTCSeconds())+'Z'}<commit_msg>Fixed bug with user data disappearing when connected via facebook<commit_after>'use strict';

// Declare app level module which depends on filters, and services
var myApp = angular.module('myApp', [
  'ngRoute',
  'myApp.filters',
  'socialTradeServices',
  'myApp.directives',
  'socialTradeControllers',
  'socialTradeAnimations',
  'login',
  'auth',
  'register',
  'newtrade',
  'angulartics',
  'angulartics.google.analytics',
  'firebaseService',
  'loginServices',
  'waitForAuth',
  'routeSecurity',
  'fblogin'
]);
/* FAKE login
myApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/trades', {templateUrl: 'partials/article-list.html', controller: 'ArticleListCtrl' });
  $routeProvider.when('/trades/:tradeId', {templateUrl: 'partials/article-detail.html', controller: 'ArticleDetailCtrl', requireLogin: true});
  $routeProvider.when('/login', {templateUrl: "partials/login.tpl.html", controller: "LoginCtrl", requireLogin: false });
  $routeProvider.when('/mytrades', {templateUrl: "partials/mytrades.html", controller: "ArticleListCtrl", requireLogin: true });
  $routeProvider.when('/myprofile', {templateUrl: "partials/myprofile.html", requireLogin: true });
  $routeProvider.when('/editprofile', {templateUrl: "partials/editprofile.html", controller: "UserEditCtrl", requireLogin: true });
  //$routeProvider.when('/logout',  {templateUrl: "partials/logout.html"});
  $routeProvider.when("/signup", {templateUrl: "partials/signup.html", controller: "SignUpCtrl", requireLogin: false });
  $routeProvider.when("/users", {templateUrl: "partials/user-list.html", controller: "UserListCtrl", requireLogin: true });
  $routeProvider.when("/users/:userId", {templateUrl: "partials/user-view.html", controller: "UserDetailCtrl", requireLogin: true });
  $routeProvider.when("/newtrade", {templateUrl: "partials/addlisting-view.html", controller: "AddListingCtrl", requireLogin: true });
  $routeProvider.otherwise({redirectTo: '/trades'});
}]).constant('FBURL', 'https://socialtrade.firebaseio.com').constant('loginRedirectPath', '/login')
; */
myApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/trades', {templateUrl: 'partials/article-list.html', controller: 'ArticleListCtrl' });
  $routeProvider.when('/trades/:tradeId', {templateUrl: 'partials/article-detail.html', controller: 'ArticleDetailCtrl', authRequired: true});
  $routeProvider.when('/login', {templateUrl: "partials/login.tpl.html", controller: "LoginCtrl"});
  $routeProvider.when('/mytrades', {templateUrl: "partials/mytrades.html", controller: "ArticleListCtrl", authRequired: true});
  $routeProvider.when('/myprofile', {templateUrl: "partials/myprofile.html", authRequired: true});
  $routeProvider.when('/editprofile', {templateUrl: "partials/editprofile.html", controller: "UserEditCtrl", authRequired: true });
  //$routeProvider.when('/logout',  {templateUrl: "partials/logout.html"});
  $routeProvider.when("/signup", {templateUrl: "partials/signup.html", controller: "SignUpCtrl"});
  $routeProvider.when("/users", {templateUrl: "partials/user-list.html", controller: "UserListCtrl", authRequired: true });
  $routeProvider.when("/users/:userId", {templateUrl: "partials/user-view.html", controller: "UserDetailCtrl", authRequired: true });
  $routeProvider.when("/newtrade", {templateUrl: "partials/addlisting-view.html", controller: "AddListingCtrl", authRequired: true });
  $routeProvider.otherwise({redirectTo: '/trades'});
}]).constant('FBURL', 'https://socialtrade.firebaseio.com').constant('loginRedirectPath', '/login')
;
/* FAKE login - Testing user's rights to access a url
myApp.run(['$rootScope', 'AuthService', '$location', function($rootScope, AuthService, $location){
    // Everytime the route in our app changes check auth status
    $rootScope.$on("$routeChangeStart", function(event, next, current) {
        // if you're logged out send to login page.
        if (next.requireLogin && !AuthService.getUserAuthenticated()) {
            $location.path('/login');
            event.preventDefault();
        }
    });
}]); */
myApp.run(['loginService', '$rootScope', 'FBURL', function(loginService, $rootScope, FBURL) {
   // establish authentication
   $rootScope.auth = loginService.init('/login');
   $rootScope.FBURL = FBURL;
}]);

/* Main App controller - used for "fake" authentication
 myApp.controller('MainCtrl', ['$scope', 'AuthService', '$location', function($scope, AuthService, $location) {

 	// check if user is authenticated on every page and return them
 	$scope.$on('$viewContentLoaded', function() {

		$scope.user = AuthService.getAuthenticatedUser();

	});
    $scope.logoutUser = function() {
        // run a logout function to your api
        AuthService.setUserAuthenticated(false);
        AuthService.setAuthenticatedUser(null);
        $location.path('/login');
    };

    $scope.isLoggedIn = function() {
        return AuthService.getUserAuthenticated();
    };
    $scope.isActive = function(url) {
    	return url == $location.$$url;
    };
}]);
*/
myApp.controller('MainCtrl', ['$scope', 'loginService', 'syncData', '$location', 'AuthService', 'firebaseRef', '$rootScope',
 function($scope, loginService, syncData, $location, AuthService, firebaseRef, $rootScope) {

      $scope.$on('$viewContentLoaded', function() {
        // $scope.user = AuthService.getAuthenticatedUser();
        if($scope.auth.user != null && $scope.auth.user.provider !== "google" && $scope.auth.user.provider !== "facebook") {
          var id = parseInt($scope.auth.user.id);
          $scope.user =  syncData(['users', id-1]);
         // firebaseRef('users/'+$scope.user.id).update({online: true});
        }
      });
       $rootScope.$on("glogin", function(event, user) {
            // do login things
            //$scope.user = user;
            $scope.$apply;
            //find user by email
            //TODO: izboljsava - avtomatska registracija, ce ga se ni!
            console.log(user.email);
            $scope.tu = syncData('users');
            $scope.tu.$on("loaded", function() {
              var keys = $scope.tu.$getIndex();
              var reg = false;
              var id = 0;
               angular.forEach(keys, function(key) {
                 if($scope.tu[key].email === user.email) {
                    reg = true;
                    id = key;
                 }

                 //onsole.log(key, $scope.tu[key].email);
              });
              if(!reg) {

                  //TODO: automatically register user
                 $scope.logout();
                 $location.path("/signup");
              } else {
                //Get user
                $scope.user = syncData(["users", id]);
              }

            });

        });
        $rootScope.$on("fblogin", function(event, user) {
            // do login things
            //$scope.user = user;
            $scope.$apply;
            //find user by email
            //TODO: izboljsava - avtomatska registracija, ce ga se ni!
            //console.log(user.thirdPartyUserData.email);
            $scope.tu = syncData('users');
            $scope.tu.$on("loaded", function() {
              var keys = $scope.tu.$getIndex();
              var reg = false;
              var id = 0;
               angular.forEach(keys, function(key) {
                 if($scope.tu[key].email === user.thirdPartyUserData.email) {
                    reg = true;
                    id = key;
                 }

                 //onsole.log(key, $scope.tu[key].email);
              });
              if(!reg) {

                  //TODO: automatically register user
                 $scope.logout();
                 $location.path("/signup");
              } else {
                //Get user
                $scope.user = syncData(["users", id]);
              }

            });

        });

      //online = false v logoutu! - http://stackoverflow.com/questions/15982215/firebase-count-online-users
      $scope.logout = function() {
       //  AuthService.setUserAuthenticated(false);
      //   AuthService.setAuthenticatedUser(null);
        /*  $("#lgin").css("display","");
          $("#reg").css("display","");
          $("#lgout").css("display","none");
          $("#lginfo").css("display","none"); */
          if($scope.user != null) {
          $scope.user.online = false;
          $scope.user.last_active = ISODateString(new Date());
          firebaseRef('users/'+$scope.user.id).update({online: false, last_active: $scope.user.last_active});
          }
         loginService.logout();
      };
  }]);
function ISODateString(d){
 function pad(n){return n<10 ? '0'+n : n}
 return d.getUTCFullYear()+'-'
      + pad(d.getUTCMonth()+1)+'-'
      + pad(d.getUTCDate())+'T'
      + pad(d.getUTCHours())+':'
      + pad(d.getUTCMinutes())+':'
      + pad(d.getUTCSeconds())+'Z'}<|endoftext|>


<commit_before>/*global _, Kinetic, MAPJS*/
if (Kinetic.Stage.prototype.isRectVisible) {
	throw ('isRectVisible already exists, should not mix in our methods');
}
MAPJS.Rectangle = function (x, y, width, height) {
	'use strict';
	this.scale = function (scale) {
		return new MAPJS.Rectangle(x * scale, y * scale, width * scale, height * scale);
	};
	this.translate = function (dx, dy) {
		return new MAPJS.Rectangle(x + dx, y + dy, width, height);
	};
	this.inset = function (margin) {
		return new MAPJS.Rectangle(x + margin, y + margin, width - (margin * 2), height - (margin * 2));
	};
	this.x = x;
	this.y = y;
	this.height = height;
	this.width = width;
};
Kinetic.Stage.prototype.isRectVisible = function (rect, offset) {
	'use strict';
	offset = offset || {x: 0, y: 0, margin: 0};
	var scale = this.getScale().x || 1;
	rect = rect.scale(scale).translate(offset.x, offset.y).inset(offset.margin);
	return !(
		rect.x + this.attrs.x > this.getWidth() ||
		rect.x + rect.width + this.attrs.x < 0  ||
		rect.y + this.attrs.y > this.getHeight() ||
		rect.y + rect.height + this.attrs.y < 0
	);
};

MAPJS.KineticMediator = function (mapModel, stage, imageRendering) {
	'use strict';
	window.stage = stage;
	var layer = new Kinetic.Layer(),
		nodeByIdeaId = {},
		connectorByFromIdeaIdToIdeaId = {},
		screenToStageCoordinates = function (x, y) {
			return {
				x: (x - stage.attrs.x) / (stage.getScale().x || 1),
				y: (y - stage.attrs.y) / (stage.getScale().y || 1)
			};
		},
		getInteractionPoint = function (evt) {
			if (evt.changedTouches && evt.changedTouches[0]) {
				return screenToStageCoordinates(evt.changedTouches[0].clientX, evt.changedTouches[0].clientY);
			}
			return screenToStageCoordinates(evt.layerX, evt.layerY);
		},
		connectorKey = function (fromIdeaId, toIdeaId) {
			return fromIdeaId + '_' + toIdeaId;
		},
		atLeastOneVisible = function (list, deltaX, deltaY) {
			var margin = Math.min(stage.getHeight(), stage.getWidth()) * 0.1;
			return _.find(list, function (node) {
				return node.isVisible({x: deltaX, y: deltaY, margin: margin});
			});
		},
		moveStage = function (deltaX, deltaY) {
			var visibleAfterMove, visibleBeforeMove;
			if (!stage) {
				return;
			}

			visibleBeforeMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, 0, 0);
			visibleAfterMove = atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, deltaX, deltaY);
			if (visibleAfterMove || (!visibleBeforeMove)) {
				if (deltaY !== 0) { stage.setY(stage.getY() + deltaY); }
				if (deltaX !== 0) { stage.setX(stage.getX() + deltaX); }
				stage.draw();
			}
		},
		resetStage = function () {
			new Kinetic.Tween({
				node: stage,
				x: 0.5 * stage.getWidth(),
				y: 0.5 * stage.getHeight(),
				scaleX: 1,
				scaleY: 1,
				easing: Kinetic.Easings.EaseInOut,
				duration: 0.05,
				onFinish: function () {
					stage.fire(':scaleChangeComplete');
				}
			}).play();
		},
		ensureSelectedNodeVisible = function (node) {
			var scale = stage.getScale().x || 1,
				offset = 100,
				move = { x: 0, y: 0 };
			if (!node.getIsSelected()) {
				return;
			}
			if (node.getAbsolutePosition().x + node.getWidth() * scale + offset > stage.getWidth()) {
				move.x = stage.getWidth() - (node.getAbsolutePosition().x + node.getWidth() * scale + offset);
			} else if (node.getAbsolutePosition().x < offset) {
				move.x  = offset - node.getAbsolutePosition().x;
			}
			if (node.getAbsolutePosition().y + node.getHeight() * scale + offset > stage.getHeight()) {
				move.y = stage.getHeight() - (node.getAbsolutePosition().y + node.getHeight() * scale + offset);
			} else if (node.getAbsolutePosition().y < offset) {
				move.y = offset - node.getAbsolutePosition().y;
			}
			new Kinetic.Tween({
				node: stage,
				x: stage.attrs.x + move.x,
				y: stage.attrs.y + move.y,
				duration: 0.4,
				easing: Kinetic.Easings.EaseInOut
			}).play();
		};
	stage.add(layer);
	layer.on('mouseover', function () {
		stage.getContainer().style.cursor = 'pointer';
	});
	layer.on('mouseout', function () {
		stage.getContainer().style.cursor = 'auto';
	});
	mapModel.addEventListener('nodeEditRequested', function (nodeId, shouldSelectAll, editingNew) {
		var node = nodeByIdeaId[nodeId];
		if (node) {
			node.editNode(shouldSelectAll, editingNew);
		}
	});
	mapModel.addEventListener('nodeCreated', function (n) {
		var node = new Kinetic.Idea({
			level: n.level,
			x: n.x,
			y: n.y,
			text: n.title,
			mmAttr: n.attr,
			opacity: 1,
			id: 'node_' + n.id,
			activated: n.activated
		});
		if (imageRendering) {
			node = Kinetic.IdeaProxy(node, stage, layer);
		}
		node.on('click tap', function (evt) { mapModel.clickNode(n.id, evt); });
		node.on('dblclick dbltap', function () {
			if (!mapModel.getEditingEnabled()) {
				mapModel.toggleCollapse('mouse');
				return;
			}
			mapModel.editNode('mouse', false, false);
		});
		node.on('dragstart', function () {
			node.moveToTop();
			node.setShadowOffset(8);
			node.attrs.opacity = 0.3;
		});
		node.on('dragmove', function (evt) {
			var stagePoint = getInteractionPoint(evt);
			mapModel.nodeDragMove(
				n.id,
				stagePoint.x,
				stagePoint.y
			);
		});
		node.on('dragend', function (evt) {
			var stagePoint = getInteractionPoint(evt);
			node.setShadowOffset(4);
			node.attrs.opacity = 1;
			mapModel.nodeDragEnd(
				n.id,
				stagePoint.x,
				stagePoint.y,
				evt.shiftKey
			);
			if (n.level > 1) {
				stage.setDraggable(true);
			}
		});
		node.on(':textChanged', function (event) {
			mapModel.updateTitle(n.id, event.text);
			mapModel.setInputEnabled(true);
		});
		node.on(':editing', function () {
			mapModel.setInputEnabled(false);
		});
		node.on(':request', function (event) {
			mapModel[event.type](event.source, n.id);
		});
		if (n.level > 1) {
			node.on('mouseover touchstart', stage.setDraggable.bind(stage, false));
			node.on('mouseout touchend', stage.setDraggable.bind(stage, true));
		}
		layer.add(node);
		stage.on(':scaleChangeComplete', function () {
			node.setupShadows();
		});
		nodeByIdeaId[n.id] = node;
	});
	mapModel.addEventListener('nodeSelectionChanged', function (ideaId, isSelected) {
		var node = nodeByIdeaId[ideaId];
		if (!node) {
			return;
		}
		node.setIsSelected(isSelected);
		if (!isSelected) {
			return;
		}
		ensureSelectedNodeVisible(node);
	});
	mapModel.addEventListener('nodeAttrChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setMMAttr(n.attr);
	});
	mapModel.addEventListener('nodeDroppableChanged', function (ideaId, isDroppable) {
		var node = nodeByIdeaId[ideaId];
		node.setIsDroppable(isDroppable);
	});
	mapModel.addEventListener('nodeRemoved', function (n) {
		var node = nodeByIdeaId[n.id];
		delete nodeByIdeaId[n.id];
		node.off('click dblclick tap dbltap dragstart dragmove dragend mouseover mouseout touchstart touchend :openAttachmentRequested :editing :textChanged ');
		// node.destroy();
		new Kinetic.Tween({
			node: node,
			opacity: 0.25,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.2,
			onFinish: node.destroy.bind(node)
		}).play();
	});
	mapModel.addEventListener('nodeMoved', function (n, reason) {
		var node = nodeByIdeaId[n.id];
		new Kinetic.Tween({
			node: node,
			x: n.x,
			y: n.y,
			easing: reason === 'failed' ? Kinetic.Easings.BounceEaseOut: Kinetic.Easings.EaseInOut,
			duration: 0.4,
			onFinish: ensureSelectedNodeVisible.bind(undefined, node)
		}).play();
	});
	mapModel.addEventListener('nodeTitleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setText(n.title);
		layer.draw();
	});
	mapModel.addEventListener('connectorCreated', function (n) {
		var connector = new Kinetic.Connector({
			shapeFrom: nodeByIdeaId[n.from],
			shapeTo: nodeByIdeaId[n.to],
			stroke: '#888',
			strokeWidth: 1,
			opacity: 0
		});
		connector.opacity = 0;
		connectorByFromIdeaIdToIdeaId[connectorKey(n.from, n.to)] = connector;
		layer.add(connector);
		connector.moveToBottom();
		new Kinetic.Tween({
			node: connector,
			opacity: 1,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.5
		}).play();
	});
	mapModel.addEventListener('connectorRemoved', function (n) {
		var key = connectorKey(n.from, n.to),
			connector = connectorByFromIdeaIdToIdeaId[key];
		delete connectorByFromIdeaIdToIdeaId[key];
		new Kinetic.Tween({
			node: connector,
			opacity: 0,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.4,
			onFinish: connector.destroy.bind(connector)
		}).play();
	});
	mapModel.addEventListener('linkCreated', function (l) {
		var link = new Kinetic.Link({
			id: 'link_' + l.ideaIdFrom + '_' + l.ideaIdTo,
			shapeFrom: nodeByIdeaId[l.ideaIdFrom],
			shapeTo: nodeByIdeaId[l.ideaIdTo],
			dashArray: [8, 8],
			stroke: '#800',
			strokeWidth: 1.5
		});
		link.on('click tap', function (event) {
			mapModel.selectLink(l, { x: event.layerX, y: event.layerY });
		});
		layer.add(link);
		link.moveToBottom();
		link.setMMAttr(l.attr);
	});
	mapModel.addEventListener('linkRemoved', function (l) {
		var link = layer.get('#link_' + l.ideaIdFrom + '_' + l.ideaIdTo)[0];
		link.destroy();
		layer.draw();
	});
	mapModel.addEventListener('linkAttrChanged', function (l) {
		var link = layer.get('#link_' + l.ideaIdFrom + '_' + l.ideaIdTo)[0];
		link.setMMAttr(l.attr);
	});
	mapModel.addEventListener('mapScaleChanged', function (scaleMultiplier, zoomPoint) {
		var currentScale = stage.getScale().x || 1,
			targetScale = Math.max(Math.min(currentScale * scaleMultiplier, 5), 0.2);
		if (currentScale === targetScale) {
			return;
		}
		zoomPoint = zoomPoint || {x:  0.5 * stage.getWidth(), y: 0.5 * stage.getHeight()};
		new Kinetic.Tween({
			node: stage,
			x: zoomPoint.x + (stage.attrs.x - zoomPoint.x) * targetScale / currentScale,
			y: zoomPoint.y + (stage.attrs.y - zoomPoint.y) * targetScale / currentScale,
			scaleX: targetScale,
			scaleY: targetScale,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.01,
			onFinish: function () {
				stage.fire(':scaleChangeComplete');
			}
		}).play();
	});
	mapModel.addEventListener('mapViewResetRequested', function () {
		resetStage();
	});
	mapModel.addEventListener('mapMoveRequested', function (deltaX, deltaY) {
		moveStage(deltaX, deltaY);
	});
	mapModel.addEventListener('activatedNodesChanged', function (activatedNodes, deactivatedNodes) {
		var setActivated = function (active, id) {
			var node = nodeByIdeaId[id];
			if (!node) {
				return;
			}
			node.setIsActivated(active);
		};
		_.each(activatedNodes, setActivated.bind(undefined, true));
		_.each(deactivatedNodes, setActivated.bind(undefined, false));
	});
	(function () {
		var x, y;
		stage.on('dragmove', function () {
			var deltaX = x - stage.attrs.x,
				deltaY = y - stage.attrs.y,
				visibleAfterMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, 0, 0),
				shouldMoveBack = !visibleAfterMove && !(atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, deltaX, deltaY));
			if (shouldMoveBack) {
				moveStage(deltaX, deltaY);
			} else {
				x = stage.attrs.x;
				y = stage.attrs.y;
			}
		});
	}());
};
MAPJS.KineticMediator.dimensionProvider = _.memoize(function (title) {
	'use strict';
	var text = new Kinetic.Idea({
		text: title
	});
	return {
		width: text.getWidth(),
		height: text.getHeight()
	};
});
MAPJS.KineticMediator.layoutCalculator = function (idea) {
	'use strict';
	return MAPJS.calculateLayout(idea, MAPJS.KineticMediator.dimensionProvider);
};
<commit_msg>different cursors when mapmodel is in addlink mode<commit_after>/*global _, Kinetic, MAPJS*/
if (Kinetic.Stage.prototype.isRectVisible) {
	throw ('isRectVisible already exists, should not mix in our methods');
}
MAPJS.Rectangle = function (x, y, width, height) {
	'use strict';
	this.scale = function (scale) {
		return new MAPJS.Rectangle(x * scale, y * scale, width * scale, height * scale);
	};
	this.translate = function (dx, dy) {
		return new MAPJS.Rectangle(x + dx, y + dy, width, height);
	};
	this.inset = function (margin) {
		return new MAPJS.Rectangle(x + margin, y + margin, width - (margin * 2), height - (margin * 2));
	};
	this.x = x;
	this.y = y;
	this.height = height;
	this.width = width;
};
Kinetic.Stage.prototype.isRectVisible = function (rect, offset) {
	'use strict';
	offset = offset || {x: 0, y: 0, margin: 0};
	var scale = this.getScale().x || 1;
	rect = rect.scale(scale).translate(offset.x, offset.y).inset(offset.margin);
	return !(
		rect.x + this.attrs.x > this.getWidth() ||
		rect.x + rect.width + this.attrs.x < 0  ||
		rect.y + this.attrs.y > this.getHeight() ||
		rect.y + rect.height + this.attrs.y < 0
	);
};

MAPJS.KineticMediator = function (mapModel, stage, imageRendering) {
	'use strict';
	window.stage = stage;
	var layer = new Kinetic.Layer(),
		nodeByIdeaId = {},
		connectorByFromIdeaIdToIdeaId = {},
		screenToStageCoordinates = function (x, y) {
			return {
				x: (x - stage.attrs.x) / (stage.getScale().x || 1),
				y: (y - stage.attrs.y) / (stage.getScale().y || 1)
			};
		},
		getInteractionPoint = function (evt) {
			if (evt.changedTouches && evt.changedTouches[0]) {
				return screenToStageCoordinates(evt.changedTouches[0].clientX, evt.changedTouches[0].clientY);
			}
			return screenToStageCoordinates(evt.layerX, evt.layerY);
		},
		connectorKey = function (fromIdeaId, toIdeaId) {
			return fromIdeaId + '_' + toIdeaId;
		},
		atLeastOneVisible = function (list, deltaX, deltaY) {
			var margin = Math.min(stage.getHeight(), stage.getWidth()) * 0.1;
			return _.find(list, function (node) {
				return node.isVisible({x: deltaX, y: deltaY, margin: margin});
			});
		},
		moveStage = function (deltaX, deltaY) {
			var visibleAfterMove, visibleBeforeMove;
			if (!stage) {
				return;
			}

			visibleBeforeMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, 0, 0);
			visibleAfterMove = atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, deltaX, deltaY);
			if (visibleAfterMove || (!visibleBeforeMove)) {
				if (deltaY !== 0) { stage.setY(stage.getY() + deltaY); }
				if (deltaX !== 0) { stage.setX(stage.getX() + deltaX); }
				stage.draw();
			}
		},
		resetStage = function () {
			new Kinetic.Tween({
				node: stage,
				x: 0.5 * stage.getWidth(),
				y: 0.5 * stage.getHeight(),
				scaleX: 1,
				scaleY: 1,
				easing: Kinetic.Easings.EaseInOut,
				duration: 0.05,
				onFinish: function () {
					stage.fire(':scaleChangeComplete');
				}
			}).play();
		},
		ensureSelectedNodeVisible = function (node) {
			var scale = stage.getScale().x || 1,
				offset = 100,
				move = { x: 0, y: 0 };
			if (!node.getIsSelected()) {
				return;
			}
			if (node.getAbsolutePosition().x + node.getWidth() * scale + offset > stage.getWidth()) {
				move.x = stage.getWidth() - (node.getAbsolutePosition().x + node.getWidth() * scale + offset);
			} else if (node.getAbsolutePosition().x < offset) {
				move.x  = offset - node.getAbsolutePosition().x;
			}
			if (node.getAbsolutePosition().y + node.getHeight() * scale + offset > stage.getHeight()) {
				move.y = stage.getHeight() - (node.getAbsolutePosition().y + node.getHeight() * scale + offset);
			} else if (node.getAbsolutePosition().y < offset) {
				move.y = offset - node.getAbsolutePosition().y;
			}
			new Kinetic.Tween({
				node: stage,
				x: stage.attrs.x + move.x,
				y: stage.attrs.y + move.y,
				duration: 0.4,
				easing: Kinetic.Easings.EaseInOut
			}).play();
		};
	stage.add(layer);
	layer.on('mouseover', function () {
		stage.getContainer().style.cursor = 'pointer';
	});
	layer.on('mouseout', function () {
		stage.getContainer().style.cursor = 'auto';
	});
	mapModel.addEventListener('addLinkModeToggled', function (isOn) {
		stage.getContainer().style.cursor = isOn ? 'crosshair' : 'auto';
		layer.off('mouseover mouseout');
		layer.on('mouseover', function () {
			stage.getContainer().style.cursor = isOn ? 'alias' : 'pointer';
		});
		layer.on('mouseout', function () {
			stage.getContainer().style.cursor = isOn ? 'crosshair' : 'auto';
		});
	});
	mapModel.addEventListener('nodeEditRequested', function (nodeId, shouldSelectAll, editingNew) {
		var node = nodeByIdeaId[nodeId];
		if (node) {
			node.editNode(shouldSelectAll, editingNew);
		}
	});
	mapModel.addEventListener('nodeCreated', function (n) {
		var node = new Kinetic.Idea({
			level: n.level,
			x: n.x,
			y: n.y,
			text: n.title,
			mmAttr: n.attr,
			opacity: 1,
			id: 'node_' + n.id,
			activated: n.activated
		});
		if (imageRendering) {
			node = Kinetic.IdeaProxy(node, stage, layer);
		}
		node.on('click tap', function (evt) { mapModel.clickNode(n.id, evt); });
		node.on('dblclick dbltap', function () {
			if (!mapModel.getEditingEnabled()) {
				mapModel.toggleCollapse('mouse');
				return;
			}
			mapModel.editNode('mouse', false, false);
		});
		node.on('dragstart', function () {
			node.moveToTop();
			node.setShadowOffset(8);
			node.attrs.opacity = 0.3;
		});
		node.on('dragmove', function (evt) {
			var stagePoint = getInteractionPoint(evt);
			mapModel.nodeDragMove(
				n.id,
				stagePoint.x,
				stagePoint.y
			);
		});
		node.on('dragend', function (evt) {
			var stagePoint = getInteractionPoint(evt);
			node.setShadowOffset(4);
			node.attrs.opacity = 1;
			mapModel.nodeDragEnd(
				n.id,
				stagePoint.x,
				stagePoint.y,
				evt.shiftKey
			);
			if (n.level > 1) {
				stage.setDraggable(true);
			}
		});
		node.on(':textChanged', function (event) {
			mapModel.updateTitle(n.id, event.text);
			mapModel.setInputEnabled(true);
		});
		node.on(':editing', function () {
			mapModel.setInputEnabled(false);
		});
		node.on(':request', function (event) {
			mapModel[event.type](event.source, n.id);
		});
		if (n.level > 1) {
			node.on('mouseover touchstart', stage.setDraggable.bind(stage, false));
			node.on('mouseout touchend', stage.setDraggable.bind(stage, true));
		}
		layer.add(node);
		stage.on(':scaleChangeComplete', function () {
			node.setupShadows();
		});
		nodeByIdeaId[n.id] = node;
	});
	mapModel.addEventListener('nodeSelectionChanged', function (ideaId, isSelected) {
		var node = nodeByIdeaId[ideaId];
		if (!node) {
			return;
		}
		node.setIsSelected(isSelected);
		if (!isSelected) {
			return;
		}
		ensureSelectedNodeVisible(node);
	});
	mapModel.addEventListener('nodeAttrChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setMMAttr(n.attr);
	});
	mapModel.addEventListener('nodeDroppableChanged', function (ideaId, isDroppable) {
		var node = nodeByIdeaId[ideaId];
		node.setIsDroppable(isDroppable);
	});
	mapModel.addEventListener('nodeRemoved', function (n) {
		var node = nodeByIdeaId[n.id];
		delete nodeByIdeaId[n.id];
		node.off('click dblclick tap dbltap dragstart dragmove dragend mouseover mouseout touchstart touchend :openAttachmentRequested :editing :textChanged ');
		// node.destroy();
		new Kinetic.Tween({
			node: node,
			opacity: 0.25,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.2,
			onFinish: node.destroy.bind(node)
		}).play();
	});
	mapModel.addEventListener('nodeMoved', function (n, reason) {
		var node = nodeByIdeaId[n.id];
		new Kinetic.Tween({
			node: node,
			x: n.x,
			y: n.y,
			easing: reason === 'failed' ? Kinetic.Easings.BounceEaseOut: Kinetic.Easings.EaseInOut,
			duration: 0.4,
			onFinish: ensureSelectedNodeVisible.bind(undefined, node)
		}).play();
	});
	mapModel.addEventListener('nodeTitleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setText(n.title);
		layer.draw();
	});
	mapModel.addEventListener('connectorCreated', function (n) {
		var connector = new Kinetic.Connector({
			shapeFrom: nodeByIdeaId[n.from],
			shapeTo: nodeByIdeaId[n.to],
			stroke: '#888',
			strokeWidth: 1,
			opacity: 0
		});
		connector.opacity = 0;
		connectorByFromIdeaIdToIdeaId[connectorKey(n.from, n.to)] = connector;
		layer.add(connector);
		connector.moveToBottom();
		new Kinetic.Tween({
			node: connector,
			opacity: 1,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.5
		}).play();
	});
	mapModel.addEventListener('connectorRemoved', function (n) {
		var key = connectorKey(n.from, n.to),
			connector = connectorByFromIdeaIdToIdeaId[key];
		delete connectorByFromIdeaIdToIdeaId[key];
		new Kinetic.Tween({
			node: connector,
			opacity: 0,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.4,
			onFinish: connector.destroy.bind(connector)
		}).play();
	});
	mapModel.addEventListener('linkCreated', function (l) {
		var link = new Kinetic.Link({
			id: 'link_' + l.ideaIdFrom + '_' + l.ideaIdTo,
			shapeFrom: nodeByIdeaId[l.ideaIdFrom],
			shapeTo: nodeByIdeaId[l.ideaIdTo],
			dashArray: [8, 8],
			stroke: '#800',
			strokeWidth: 1.5
		});
		link.on('click tap', function (event) {
			mapModel.selectLink(l, { x: event.layerX, y: event.layerY });
		});
		layer.add(link);
		link.moveToBottom();
		link.setMMAttr(l.attr);
	});
	mapModel.addEventListener('linkRemoved', function (l) {
		var link = layer.get('#link_' + l.ideaIdFrom + '_' + l.ideaIdTo)[0];
		link.destroy();
		layer.draw();
	});
	mapModel.addEventListener('linkAttrChanged', function (l) {
		var link = layer.get('#link_' + l.ideaIdFrom + '_' + l.ideaIdTo)[0];
		link.setMMAttr(l.attr);
	});
	mapModel.addEventListener('mapScaleChanged', function (scaleMultiplier, zoomPoint) {
		var currentScale = stage.getScale().x || 1,
			targetScale = Math.max(Math.min(currentScale * scaleMultiplier, 5), 0.2);
		if (currentScale === targetScale) {
			return;
		}
		zoomPoint = zoomPoint || {x:  0.5 * stage.getWidth(), y: 0.5 * stage.getHeight()};
		new Kinetic.Tween({
			node: stage,
			x: zoomPoint.x + (stage.attrs.x - zoomPoint.x) * targetScale / currentScale,
			y: zoomPoint.y + (stage.attrs.y - zoomPoint.y) * targetScale / currentScale,
			scaleX: targetScale,
			scaleY: targetScale,
			easing: Kinetic.Easings.EaseInOut,
			duration: 0.01,
			onFinish: function () {
				stage.fire(':scaleChangeComplete');
			}
		}).play();
	});
	mapModel.addEventListener('mapViewResetRequested', function () {
		resetStage();
	});
	mapModel.addEventListener('mapMoveRequested', function (deltaX, deltaY) {
		moveStage(deltaX, deltaY);
	});
	mapModel.addEventListener('activatedNodesChanged', function (activatedNodes, deactivatedNodes) {
		var setActivated = function (active, id) {
			var node = nodeByIdeaId[id];
			if (!node) {
				return;
			}
			node.setIsActivated(active);
		};
		_.each(activatedNodes, setActivated.bind(undefined, true));
		_.each(deactivatedNodes, setActivated.bind(undefined, false));
	});
	(function () {
		var x, y;
		stage.on('dragmove', function () {
			var deltaX = x - stage.attrs.x,
				deltaY = y - stage.attrs.y,
				visibleAfterMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, 0, 0),
				shouldMoveBack = !visibleAfterMove && !(atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaIdToIdeaId, deltaX, deltaY));
			if (shouldMoveBack) {
				moveStage(deltaX, deltaY);
			} else {
				x = stage.attrs.x;
				y = stage.attrs.y;
			}
		});
	}());
};
MAPJS.KineticMediator.dimensionProvider = _.memoize(function (title) {
	'use strict';
	var text = new Kinetic.Idea({
		text: title
	});
	return {
		width: text.getWidth(),
		height: text.getHeight()
	};
});
MAPJS.KineticMediator.layoutCalculator = function (idea) {
	'use strict';
	return MAPJS.calculateLayout(idea, MAPJS.KineticMediator.dimensionProvider);
};
<|endoftext|>