<commit_before>import log from '../lib/logger-service';
import * as strings from '../coaching-chatbot/strings.json';

module.exports = class InMemoryProvider {
  constructor() {
    this.db = {};
  }

  read(sessionId) {
    log.silly('DB contents: {0}', JSON.stringify(this.db));
    if (this.db[sessionId] === undefined) {
      this.db[sessionId] = {};
    }

    log.silly('Retrieved context for {0}: {1}',
        sessionId, JSON.stringify(this.db[sessionId]));
    return Promise.resolve(this.db[sessionId]);
  }

  readAll() {
    log.silly('DB contents: {0}', JSON.stringify(this.db));
    return this.db;
  }

  readAllWithReminders() {
    log.silly('Getting all sessions with reminders');
    let sessions = [];

    let d = new Date();
    // UTC + 2 -> Suomen aika
    let currentDate =
      new Date(d.getTime() + (1000 * ((d.getTimezoneOffset() / 60) + 2)));
    let currentHour = ('0' + currentDate.getHours()).substr(-2, 2);
    console.log("WEEKDAY: " + currentDate.getDay());
    console.log("HOURS: " + currentDate.getHours());

    for (let sessionId in this.db) {
      if (!{}.hasOwnProperty.call(this.db, sessionId)) continue;
      log.silly('Evaluating session with id: ', sessionId);
      let context = this.db[sessionId];

      const day = context.weekDay;
      if(day === undefined) continue;
      let meetingDay = strings['@WEEKDAYS'].indexOf(day.toUpperCase());
      if (meetingDay == currentDate.getDay()) {
        if (('0' + context.time).substr(-5, 2) == currentHour) {
          log.silly('Found context with id: ', sessionId);
          sessions.push( { 'id': sessionId, 'context': context } );
        }
      }
    }

    return Promise.resolve(sessions);
  }

  readAllWithFeedbacks() {
    log.silly('Getting all sessions with feedbacks');
    let sessions = [];

    let d = new Date();
    // UTC + 2 -> Suomen aika
    let currentDate =
      new Date(d.getTime() + (1000 * ((d.getTimezoneOffset() / 60) + 2)));
    let currentHour = ('0' + ((currentDate.getHours() - 1) % 24)).substr(-2, 2);

    for (let sessionId in this.db) {
      if (!{}.hasOwnProperty.call(this.db, sessionId)) continue;
      log.silly('Evaluating session with id: ', sessionId);
      let context = this.db[sessionId];

      const day = context.weekDay;
      if(day === undefined) continue;
      let meetingDay = strings['@WEEKDAYS'].indexOf(day.toUpperCase());
      if (meetingDay == ((currentDate.getDay() + 6) % 7)) {
        if (('0' + context.time).substr(-5, 2) == currentHour) {
          log.silly('Found context with id: ', sessionId);
          sessions.push( { 'id': sessionId, 'context': context } );
        }
      }
    }
    return Promise.resolve(sessions);
  }

  write(sessionId, context) {
    this.db[sessionId] = context;

    log.silly('Writing context for {0}: {1}',
        sessionId, JSON.stringify(this.db[sessionId]));
    return Promise.resolve(this.db[sessionId]);
  }

  getAvailablePairs(id) {
    return new Promise((resolve, reject) => {
      log.silly('Id: {0}', id);

      let pairs = [];

      for (let sessionId in this.db) {
        if (!{}.hasOwnProperty.call(this.db, sessionId)) continue;

        log.silly('Evaluating possible pair {0}', sessionId);
        if (sessionId == id) continue;
        let session = this.db[sessionId];
        let context = this.db[id];

        if (session.searching === true &&
            (!session.pairRequests || !session.pairRequests.includes(id)) &&
            (!session.rejectedPeers || !session.rejectedPeers.includes(id)) &&
            (session.communicationMethods && context.communicationMethods &&
              Object.keys(session.communicationMethods).some((method) =>
              Object.keys(context.communicationMethods).includes(method)))) {
          log.silly('Found a valid pair!');
          pairs.push({ id: sessionId });
        }
      }

      resolve(pairs);
    });
  }

  dump() {
    return this.db;
  }

  load(data) {
    this.db = data;
  }
};
<commit_msg>testing 2<commit_after>import log from '../lib/logger-service';
import * as strings from '../coaching-chatbot/strings.json';

module.exports = class InMemoryProvider {
  constructor() {
    this.db = {};
  }

  read(sessionId) {
    log.silly('DB contents: {0}', JSON.stringify(this.db));
    if (this.db[sessionId] === undefined) {
      this.db[sessionId] = {};
    }

    log.silly('Retrieved context for {0}: {1}',
        sessionId, JSON.stringify(this.db[sessionId]));
    return Promise.resolve(this.db[sessionId]);
  }

  readAll() {
    log.silly('DB contents: {0}', JSON.stringify(this.db));
    return this.db;
  }

  readAllWithReminders() {
    log.silly('Getting all sessions with reminders');
    let sessions = [];

    let d = new Date();
    let utc = d.getTime() + (d.getTimezoneOffset() * 60 * 1000);
    // UTC + 2 -> Suomen aika
    let currentDate = new Date(utc + (2 * 60 * 60 * 1000));
    let currentHour = ('0' + currentDate.getHours()).substr(-2, 2);
    console.log('WEEKDAY: ' + currentDate.getDay());
    console.log('HOURS: ' + currentDate.getHours());

    for (let sessionId in this.db) {
      if (!{}.hasOwnProperty.call(this.db, sessionId)) continue;
      log.silly('Evaluating session with id: ', sessionId);
      let context = this.db[sessionId];

      const day = context.weekDay;
      if(day === undefined) continue;
      let meetingDay = strings['@WEEKDAYS'].indexOf(day.toUpperCase());
      if (meetingDay == currentDate.getDay()) {
        if (('0' + context.time).substr(-5, 2) == currentHour) {
          log.silly('Found context with id: ', sessionId);
          sessions.push( { 'id': sessionId, 'context': context } );
        }
      }
    }

    return Promise.resolve(sessions);
  }

  readAllWithFeedbacks() {
    log.silly('Getting all sessions with feedbacks');
    let sessions = [];

    let d = new Date();
    // UTC + 2 -> Suomen aika
    let currentDate =
      new Date(d.getTime() + (1000 * ((d.getTimezoneOffset() / 60) + 2)));
    let currentHour = ('0' + ((currentDate.getHours() - 1) % 24)).substr(-2, 2);

    for (let sessionId in this.db) {
      if (!{}.hasOwnProperty.call(this.db, sessionId)) continue;
      log.silly('Evaluating session with id: ', sessionId);
      let context = this.db[sessionId];

      const day = context.weekDay;
      if(day === undefined) continue;
      let meetingDay = strings['@WEEKDAYS'].indexOf(day.toUpperCase());
      if (meetingDay == ((currentDate.getDay() + 6) % 7)) {
        if (('0' + context.time).substr(-5, 2) == currentHour) {
          log.silly('Found context with id: ', sessionId);
          sessions.push( { 'id': sessionId, 'context': context } );
        }
      }
    }
    return Promise.resolve(sessions);
  }

  write(sessionId, context) {
    this.db[sessionId] = context;

    log.silly('Writing context for {0}: {1}',
        sessionId, JSON.stringify(this.db[sessionId]));
    return Promise.resolve(this.db[sessionId]);
  }

  getAvailablePairs(id) {
    return new Promise((resolve, reject) => {
      log.silly('Id: {0}', id);

      let pairs = [];

      for (let sessionId in this.db) {
        if (!{}.hasOwnProperty.call(this.db, sessionId)) continue;

        log.silly('Evaluating possible pair {0}', sessionId);
        if (sessionId == id) continue;
        let session = this.db[sessionId];
        let context = this.db[id];

        if (session.searching === true &&
            (!session.pairRequests || !session.pairRequests.includes(id)) &&
            (!session.rejectedPeers || !session.rejectedPeers.includes(id)) &&
            (session.communicationMethods && context.communicationMethods &&
              Object.keys(session.communicationMethods).some((method) =>
              Object.keys(context.communicationMethods).includes(method)))) {
          log.silly('Found a valid pair!');
          pairs.push({ id: sessionId });
        }
      }

      resolve(pairs);
    });
  }

  dump() {
    return this.db;
  }

  load(data) {
    this.db = data;
  }
};
<|endoftext|>


<commit_before>
define([
    'flight/lib/component',
    'tpl!./overlay',
    'util/formatters',
    'service/workspace',
    'data'
], function(defineComponent, template, formatters, WorkspaceService, appData) {
    'use strict';

    var LAST_SAVED_UPDATE_FREQUENCY_SECONDS = 30;
    var MENUBAR_WIDTH = 30;
    var UPDATE_WORKSPACE_DIFF_SECONDS = 3;

    return defineComponent(WorkspaceOverlay);

    function WorkspaceOverlay() {

        var workspaceService = new WorkspaceService();

        this.defaultAttrs({
            userSelector: '.user',
            nameSelector: '.name',
            subtitleSelector: '.subtitle'
        });

        this.after('initialize', function() {
            var self = this;

            requestAnimationFrame(function() {
                MENUBAR_WIDTH = $('.menubar-pane').width();
            })

            this.userDeferred = $.Deferred();
            this.workspaceDeferred = $.Deferred();
            this.updateDiffBadge = _.throttle(this.updateDiffBadge.bind(this), UPDATE_WORKSPACE_DIFF_SECONDS * 1000)

            $.when(this.userDeferred, this.workspaceDeferred).done(function() {
                self.$node.show();

                requestAnimationFrame(function() {
                    self.$node.addClass('visible');
                });
            })

            this.$node.hide().html(template({}));

            this.on(document, 'workspaceSaving', this.onWorkspaceSaving);
            this.on(document, 'workspaceSaved', this.onWorkspaceSaved);
            this.on(document, 'workspaceLoaded', this.onWorkspaceLoaded);
            this.on(document, 'switchWorkspace', this.onSwitchWorkspace);
            this.on(document, 'graphPaddingUpdated', this.onGraphPaddingUpdated);
            this.on(document, 'currentUserChanged', this.onCurrentUserChanged)
            this.on(document, 'relationshipsLoaded', this.onRelationshipsLoaded)
            this.on(document, 'ajaxComplete', this.onAjaxComplete);
            this.on(document, 'showDiffPanel', this.showDiffPanel);
            this.on(document, 'escape', this.closeDiffPanel);

            this.trigger(document, 'registerKeyboardShortcuts', {
                scope: ['Graph', 'Map'],
                shortcuts: {
                    'alt-d':  { fire:'showDiffPanel', desc:'Show unpublished changes' }
                }
            });
        });

        this.showDiffPanel = function() {
            var badge = this.$node.find('.badge');
            if (badge.is(':visible')) {
                badge.popover('show');
            }
        };

        this.closeDiffPanel = function() {
            var badge = this.$node.find('.badge');
            if (badge.is(':visible')) {
                badge.popover('hide');
            }
        };

        this.onAjaxComplete = function(event, xhr, settings) {
            // Automatically call diff after every POST
            if (/post/i.test(settings.type)) {
                this.updateDiffBadge();
            }
        };

        this.onCurrentUserChanged = function(event, data) {
            this.userDeferred.resolve();
            this.updateUserTooltip(data);
        }

        this.onGraphPaddingUpdated = function(event, data) {
            this.$node.css('left', data.padding.l + MENUBAR_WIDTH);

            var width = $(window).width(),
                height = $(window).height(),
                popover = this.$node.find('.popover'),
                paddingH = 100,
                paddingV = 75,
                popoverCss = {
                    maxWidth: (width - MENUBAR_WIDTH - (data.padding.l + data.padding.r) - paddingH),
                    maxHeight: (height - (data.padding.t + data.padding.b) - paddingV)
                };

            this.popoverCss = popoverCss;
            if (popover.length) {
                this.updatePopoverSize(popover);
            }
        };

        this.updatePopoverSize = function(tip) {
            var css = {};
            if (tip.width() > this.popoverCss.maxWidth) {
                css.width = this.popoverCss.maxWidth + 'px';
            }
            if (tip.height() > this.popoverCss.maxHeight) {
                css.height = this.popoverCss.maxHeight + 'px';
            }

            tip.resizable('option', 'maxWidth', this.popoverCss.maxWidth);
            tip.resizable('option', 'maxHeight', this.popoverCss.maxHeight);
            if (_.keys(css).length) {
                tip.css(css);
            }
        }

        this.setContent = function(title, isEditable, subtitle) {
            this.select('nameSelector').text(title);
            this.select('subtitleSelector').html(isEditable === false ? 'read only' : subtitle);
        };

        this.onSwitchWorkspace = function() {
            this.$node.find('.badge').popover('destroy').remove();
        };

        this.onWorkspaceLoaded = function(event, data) {
            this.workspaceDeferred.resolve();
            this.setContent(data.title, data.isEditable, 'no changes');
            clearTimeout(this.updateTimer);
            this.updateWorkspaceTooltip(data);
            this.updateDiffBadge();
        };

        this.onRelationshipsLoaded = function(event, data) {
            this.updateWorkspaceTooltip(data);
        };

        this.onWorkspaceSaving = function(event, data) {
            this.select('subtitleSelector').text('saving...');
            clearTimeout(this.updateTimer);
            this.updateWorkspaceTooltip(data);
        };

        this.onWorkspaceSaved = function(event, data) {
            clearTimeout(this.updateTimer);
            this.lastSaved = formatters.date.utc(Date.now());

            if (data.title) {
                this.select('nameSelector').text(data.title);
            }

            this.updateWorkspaceTooltip(data);

            var prefix = 'last saved ',
                subtitle = this.select('subtitleSelector').text(prefix + 'moments ago'),
                setTimer = function() {
                    this.updateTimer = setTimeout(function () {

                        var time = formatters.date.relativeToNow(this.lastSaved);
                        subtitle.text(prefix + time);

                        setTimer();
                    }.bind(this), LAST_SAVED_UPDATE_FREQUENCY_SECONDS * 1000);
                }.bind(this);

            setTimer();
        };

        this.onDiffBadgeMouse = function(event) {
            this.trigger(
                event.type === 'mouseenter' ?  'focusVertices' : 'defocusVertices',
                { vertexIds: this.currentDiffIds || [] }
            );
        };

        this.updateDiffBadge = function() {
            var self = this,
                node = this.select('nameSelector'),
                badge = this.$node.find('.badge');

            if (!badge.length) {
                badge = $('')
                    .insertAfter(node)
                    .on('mouseenter mouseleave', this.onDiffBadgeMouse.bind(this))
            }

            workspaceService.diff(appData.workspaceId)
                .fail(function() {
                    badge.removePrefixedClasses('badge-').addClass('badge-important')
                        .attr('title', 'An error occured')
                        .text('!');
                })
                .done(function(diff) {
                    var vertexDiffsById = _.indexBy(diff.diffs, function(diff) {
                            return diff.vertexId;
                        }),
                        countOfTitleChanges = 0,
                        filteredDiffs = _.filter(diff.diffs, function(diff) {
                            if (diff.type !== 'PropertyDiffItem') return true;
                            if (/^[_]/.test(diff.name)) return false;
                            if (diff.name === 'title' && vertexDiffsById[diff.elementId]) {
                                countOfTitleChanges++;
                            }
                            return true;
                        }),
                        count = filteredDiffs.length - countOfTitleChanges,
                        formattedCount = formatters.number.pretty(count);

                    self.currentDiffIds =_.uniq(filteredDiffs.map(function(diff) {
                        return diff.vertexId || diff.elementId || diff.edgeId;
                    }));

                    require(['workspaces/diff/diff'], function(Diff) {
                        var popover = badge.data('popover'),
                            tip = popover && popover.tip();

                        if (tip && tip.is(':visible')) {
                            self.trigger(popover.tip().find('.popover-content'), 'diffsChanged', { diffs: filteredDiffs });
                            popover.show();
                        } else {
                            badge
                                .popover('destroy')
                                .popover({placement:'top', content:'Loading...', title: 'Unpublished Changes'});

                            popover = badge.data('popover');
                            tip = popover.tip();

                            var left = 10;
                            tip.css({
                                    width: '400px',
                                    height: '250px'
                                })
                                .resizable({
                                    handles: "n, e, ne",
                                    maxWidth: self.popoverCss.maxWidth,
                                    maxHeight: self.popoverCss.maxHeight
                                })
                                .find('.arrow').css({
                                    left: parseInt(badge.position().left - (left / 2) + 1, 10) + 'px',
                                    marginLeft: 0
                                })

                            // We fill in our own content
                            popover.setContent = function() {}
                            badge.on('shown', function() {
                                var css = {
                                    top: (parseInt(tip.css('top')) - 10) + 'px'
                                };
                                tip.css({top:top});

                                self.updatePopoverSize(tip);
                            })

                            Diff.teardownAll();
                            Diff.attachTo(tip.find('.popover-content'), {
                                diffs: filteredDiffs
                            });
                        }
                    });

                    var previousCount = badge.text();
                    badge.removePrefixedClasses('badge-').addClass('badge-info')
                        .attr('title', formatters.string.plural(formattedCount, 'unpublished change'))
                        .text(count > 0 ? formattedCount : '');
                    if (previousCount && formattedCount && formattedCount != previousCount) {
                        badge.removeClass('flash');
                        requestAnimationFrame(function() {
                            badge.addClass('flash');
                        })
                    }
                })
        };

        this.updateUserTooltip = function(data) {
            if (data && data.user) {
                this.select('userSelector').text(data.user.userName)
                    .tooltip('destroy')
                    .tooltip({
                        placement: 'right',
                        html: true,
                        title: 'Authorizations: ' + (data.user.authorizations.join(', ') || 'none') + '',
                        trigger: 'hover',
                        delay: { show:500, hide:0 }
                    })
            }
        }

        this.updateWorkspaceTooltip = function(data) {
            if (data && data.data && data.data.vertices) {
                this.verticesCount = data.data.vertices.length;
            }
            if (this.verticesCount === 0) {
                this.edgesCount = 0;
            } else if (data.relationships) {
                this.edgesCount = data.relationships.length;
            } else {
                this.edgesCount = $('.cytoscape-container').cytoscape('get').edges().length;
            }

            var name = this.select('nameSelector'),
                tooltip = name.data('tooltip'),
                tip = tooltip && tooltip.tip(),
                text = 'Vertices: ' + formatters.number.pretty(this.verticesCount || 0) +
                    ', Edges: ' + formatters.number.pretty(this.edgesCount || 0)

            if (tip && tip.is(':visible')) {
                tip.find('.tooltip-inner span').text(text);
            } else {
                name
                    .tooltip('destroy')
                    .tooltip({
                        placement: 'right',
                        html: true,
                        title: '' + text + '',
                        trigger: 'hover',
                        delay: { show:500, hide:0 }
                    });
            }

        }
    }
});
<commit_msg>Close popover after publish/undo and no changes left<commit_after>
define([
    'flight/lib/component',
    'tpl!./overlay',
    'util/formatters',
    'service/workspace',
    'data'
], function(defineComponent, template, formatters, WorkspaceService, appData) {
    'use strict';

    var LAST_SAVED_UPDATE_FREQUENCY_SECONDS = 30;
    var MENUBAR_WIDTH = 30;
    var UPDATE_WORKSPACE_DIFF_SECONDS = 3;

    return defineComponent(WorkspaceOverlay);

    function WorkspaceOverlay() {

        var workspaceService = new WorkspaceService();

        this.defaultAttrs({
            userSelector: '.user',
            nameSelector: '.name',
            subtitleSelector: '.subtitle'
        });

        this.after('initialize', function() {
            var self = this;

            requestAnimationFrame(function() {
                MENUBAR_WIDTH = $('.menubar-pane').width();
            })

            this.userDeferred = $.Deferred();
            this.workspaceDeferred = $.Deferred();
            this.updateDiffBadge = _.throttle(this.updateDiffBadge.bind(this), UPDATE_WORKSPACE_DIFF_SECONDS * 1000)

            $.when(this.userDeferred, this.workspaceDeferred).done(function() {
                self.$node.show();

                requestAnimationFrame(function() {
                    self.$node.addClass('visible');
                });
            })

            this.$node.hide().html(template({}));

            this.on(document, 'workspaceSaving', this.onWorkspaceSaving);
            this.on(document, 'workspaceSaved', this.onWorkspaceSaved);
            this.on(document, 'workspaceLoaded', this.onWorkspaceLoaded);
            this.on(document, 'switchWorkspace', this.onSwitchWorkspace);
            this.on(document, 'graphPaddingUpdated', this.onGraphPaddingUpdated);
            this.on(document, 'currentUserChanged', this.onCurrentUserChanged)
            this.on(document, 'relationshipsLoaded', this.onRelationshipsLoaded)
            this.on(document, 'ajaxComplete', this.onAjaxComplete);
            this.on(document, 'showDiffPanel', this.showDiffPanel);
            this.on(document, 'escape', this.closeDiffPanel);

            this.trigger(document, 'registerKeyboardShortcuts', {
                scope: ['Graph', 'Map'],
                shortcuts: {
                    'alt-d':  { fire:'showDiffPanel', desc:'Show unpublished changes' }
                }
            });
        });

        this.showDiffPanel = function() {
            var badge = this.$node.find('.badge');
            if (badge.is(':visible')) {
                badge.popover('show');
            }
        };

        this.closeDiffPanel = function() {
            var badge = this.$node.find('.badge');
            if (badge.is(':visible')) {
                badge.popover('hide');
            }
        };

        this.onAjaxComplete = function(event, xhr, settings) {
            // Automatically call diff after every POST
            if (/post/i.test(settings.type)) {
                this.updateDiffBadge();
            }
        };

        this.onCurrentUserChanged = function(event, data) {
            this.userDeferred.resolve();
            this.updateUserTooltip(data);
        }

        this.onGraphPaddingUpdated = function(event, data) {
            this.$node.css('left', data.padding.l + MENUBAR_WIDTH);

            var width = $(window).width(),
                height = $(window).height(),
                popover = this.$node.find('.popover'),
                paddingH = 100,
                paddingV = 75,
                popoverCss = {
                    maxWidth: (width - MENUBAR_WIDTH - (data.padding.l + data.padding.r) - paddingH),
                    maxHeight: (height - (data.padding.t + data.padding.b) - paddingV)
                };

            this.popoverCss = popoverCss;
            if (popover.length) {
                this.updatePopoverSize(popover);
            }
        };

        this.updatePopoverSize = function(tip) {
            var css = {};
            if (tip.width() > this.popoverCss.maxWidth) {
                css.width = this.popoverCss.maxWidth + 'px';
            }
            if (tip.height() > this.popoverCss.maxHeight) {
                css.height = this.popoverCss.maxHeight + 'px';
            }

            tip.resizable('option', 'maxWidth', this.popoverCss.maxWidth);
            tip.resizable('option', 'maxHeight', this.popoverCss.maxHeight);
            if (_.keys(css).length) {
                tip.css(css);
            }
        }

        this.setContent = function(title, isEditable, subtitle) {
            this.select('nameSelector').text(title);
            this.select('subtitleSelector').html(isEditable === false ? 'read only' : subtitle);
        };

        this.onSwitchWorkspace = function() {
            this.$node.find('.badge').popover('destroy').remove();
        };

        this.onWorkspaceLoaded = function(event, data) {
            this.workspaceDeferred.resolve();
            this.setContent(data.title, data.isEditable, 'no changes');
            clearTimeout(this.updateTimer);
            this.updateWorkspaceTooltip(data);
            this.updateDiffBadge();
        };

        this.onRelationshipsLoaded = function(event, data) {
            this.updateWorkspaceTooltip(data);
        };

        this.onWorkspaceSaving = function(event, data) {
            this.select('subtitleSelector').text('saving...');
            clearTimeout(this.updateTimer);
            this.updateWorkspaceTooltip(data);
        };

        this.onWorkspaceSaved = function(event, data) {
            clearTimeout(this.updateTimer);
            this.lastSaved = formatters.date.utc(Date.now());

            if (data.title) {
                this.select('nameSelector').text(data.title);
            }

            this.updateWorkspaceTooltip(data);

            var prefix = 'last saved ',
                subtitle = this.select('subtitleSelector').text(prefix + 'moments ago'),
                setTimer = function() {
                    this.updateTimer = setTimeout(function () {

                        var time = formatters.date.relativeToNow(this.lastSaved);
                        subtitle.text(prefix + time);

                        setTimer();
                    }.bind(this), LAST_SAVED_UPDATE_FREQUENCY_SECONDS * 1000);
                }.bind(this);

            setTimer();
        };

        this.onDiffBadgeMouse = function(event) {
            this.trigger(
                event.type === 'mouseenter' ?  'focusVertices' : 'defocusVertices',
                { vertexIds: this.currentDiffIds || [] }
            );
        };

        this.updateDiffBadge = function() {
            var self = this,
                node = this.select('nameSelector'),
                badge = this.$node.find('.badge');

            if (!badge.length) {
                badge = $('')
                    .insertAfter(node)
                    .on('mouseenter mouseleave', this.onDiffBadgeMouse.bind(this))
            }

            workspaceService.diff(appData.workspaceId)
                .fail(function() {
                    badge.removePrefixedClasses('badge-').addClass('badge-important')
                        .attr('title', 'An error occured')
                        .text('!');
                })
                .done(function(diff) {
                    var vertexDiffsById = _.indexBy(diff.diffs, function(diff) {
                            return diff.vertexId;
                        }),
                        countOfTitleChanges = 0,
                        filteredDiffs = _.filter(diff.diffs, function(diff) {
                            if (diff.type !== 'PropertyDiffItem') return true;
                            if (/^[_]/.test(diff.name)) return false;
                            if (diff.name === 'title' && vertexDiffsById[diff.elementId]) {
                                countOfTitleChanges++;
                            }
                            return true;
                        }),
                        count = filteredDiffs.length - countOfTitleChanges,
                        formattedCount = formatters.number.pretty(count);

                    self.currentDiffIds =_.uniq(filteredDiffs.map(function(diff) {
                        return diff.vertexId || diff.elementId || diff.edgeId;
                    }));

                    require(['workspaces/diff/diff'], function(Diff) {
                        var popover = badge.data('popover'),
                            tip = popover && popover.tip();

                        if (tip && tip.is(':visible')) {
                            self.trigger(popover.tip().find('.popover-content'), 'diffsChanged', { diffs: filteredDiffs });
                            popover.show();
                        } else {
                            badge
                                .popover('destroy')
                                .popover({placement:'top', content:'Loading...', title: 'Unpublished Changes'});

                            popover = badge.data('popover');
                            tip = popover.tip();

                            var left = 10;
                            tip.css({
                                    width: '400px',
                                    height: '250px'
                                })
                                .resizable({
                                    handles: "n, e, ne",
                                    maxWidth: self.popoverCss.maxWidth,
                                    maxHeight: self.popoverCss.maxHeight
                                })
                                .find('.arrow').css({
                                    left: parseInt(badge.position().left - (left / 2) + 1, 10) + 'px',
                                    marginLeft: 0
                                })

                            // We fill in our own content
                            popover.setContent = function() {}
                            badge.on('shown', function() {
                                var css = {
                                    top: (parseInt(tip.css('top')) - 10) + 'px'
                                };
                                tip.css({top:top});

                                self.updatePopoverSize(tip);
                            })

                            Diff.teardownAll();
                            Diff.attachTo(tip.find('.popover-content'), {
                                diffs: filteredDiffs
                            });
                        }
                    });

                    var previousCount = badge.text();
                    badge.removePrefixedClasses('badge-').addClass('badge-info')
                        .attr('title', formatters.string.plural(formattedCount, 'unpublished change'))
                        .text(count > 0 ? formattedCount : '');
                    if (formattedCount && formattedCount != previousCount) {
                        badge.removeClass('flash');
                        requestAnimationFrame(function() {
                            badge.addClass('flash');
                        })
                    }
                    if (count === 0) {
                        badge.popover('destroy');
                    }
                })
        };

        this.updateUserTooltip = function(data) {
            if (data && data.user) {
                this.select('userSelector').text(data.user.userName)
                    .tooltip('destroy')
                    .tooltip({
                        placement: 'right',
                        html: true,
                        title: 'Authorizations: ' + (data.user.authorizations.join(', ') || 'none') + '',
                        trigger: 'hover',
                        delay: { show:500, hide:0 }
                    })
            }
        }

        this.updateWorkspaceTooltip = function(data) {
            if (data && data.data && data.data.vertices) {
                this.verticesCount = data.data.vertices.length;
            }
            if (this.verticesCount === 0) {
                this.edgesCount = 0;
            } else if (data.relationships) {
                this.edgesCount = data.relationships.length;
            } else {
                this.edgesCount = $('.cytoscape-container').cytoscape('get').edges().length;
            }

            var name = this.select('nameSelector'),
                tooltip = name.data('tooltip'),
                tip = tooltip && tooltip.tip(),
                text = 'Vertices: ' + formatters.number.pretty(this.verticesCount || 0) +
                    ', Edges: ' + formatters.number.pretty(this.edgesCount || 0)

            if (tip && tip.is(':visible')) {
                tip.find('.tooltip-inner span').text(text);
            } else {
                name
                    .tooltip('destroy')
                    .tooltip({
                        placement: 'right',
                        html: true,
                        title: '' + text + '',
                        trigger: 'hover',
                        delay: { show:500, hide:0 }
                    });
            }

        }
    }
});
<|endoftext|>


<commit_before>/**
 * 레이어 관련 기능
 * @param magoInstance
 * @param baseLayers
 * @param policy
 * @returns
 */
function mapInit(magoInstance, baseLayers, policy) {
	if(!(this instanceof mapInit)) {
        throw new Error(JS_MESSAGE["layer.init"]);
    }

	var WMS_LAYER = 'wmsLayer';
	var DISTRICT_LAYER = 'district';
	var viewer = magoInstance.getViewer();
	var imageryLayers = viewer.imageryLayers;
	var dataSources = viewer.dataSources;
	var geoserverDataUrl = policy.geoserverDataUrl;
	var geoserverDataWorkspace = policy.geoserverDataWorkspace;
	// 레이어 리스트를 맵 형태로 저장
	var layerMap = [];
	// 레이어 리스트
	var sortedLayer = [];
	for(var i=0; i < baseLayers.length; i++) {
		var layerList = baseLayers[i].layerList;
		var layerLength = layerList.length;
		for(var j=0; j < layerLength; j++) {
			sortedLayer.push(layerList[j]);
		}
	}

	// 레이어 리스트를 zindex 기준으로 오름 차순 정렬
	sortedLayer.sort(function(a, b) {
	    return a.zindex- b.zindex
	});

	// basemap 이 n개 이므로 basemap length 확인해서 레이어 추가/삭제 시 target index로 사용
	var baseMapLength = imageryLayers._layers.filter(function(f){
		return f.isBaseLayer();
	}).length;

	/**
	 * wms layer init
	 */
	var initWMSLayer = function(layerList) {
		var preLayer = getImageryLayerById(WMS_LAYER);
		if(preLayer) imageryLayers.remove(preLayer);
		if(layerList.length ===0) return;

		var queryString = "enable_yn='Y'";
	    var queryStrings = layerList.map(function(){ return queryString; }).join(';');	// map: ie9부터 지원
		var provider = new Cesium.WebMapServiceImageryProvider({
	        url : geoserverDataUrl + "/wms",
	        layers : layerList.map(function(e){return geoserverDataWorkspace + ':'+e}).join(','),
	        minimumLevel:2,
	        maximumLevel : 20,
	        parameters : {
	            service : 'WMS'
	            ,version : '1.1.1'
	            ,request : 'GetMap'
	            ,transparent : 'true'
	            ,format : 'image/png'
	            ,time : 'P2Y/PRESENT'
//	            ,maxZoom : 25
//	            ,maxNativeZoom : 23
	            ,CQL_FILTER: queryStrings
	        },
	        enablePickFeatures : false
	    });

		var layer = viewer.imageryLayers.addImageryProvider(provider);
		layer.id = WMS_LAYER;
	};

	/**
	 * wms 레이어 추가
	 */
	var addWMSLayer = function(layerKey) {
		if(getWMSLayerExists(layerKey)) return;
		var layerList = null;
		if(getWMSLayers()) {
			layerList = getWMSLayers().split(",");
			var targetIndex = 0;
			// zindex에 따라 정렬
			for(var i=0; i < layerList.length; i++) {
				var currnetLayerIndex = layerMap[layerList[i]].zindex;
				if(currnetLayerIndex <= layerMap[layerKey].zindex) {
					targetIndex = i+1;
				}
			}
			layerList.splice(targetIndex, 0, layerKey);
		} else {
			layerList = [layerKey];
		}

		initWMSLayer(layerList);
	};

	/**
	 * wfs 레이어 추가
	 */
	var addWFSLayer = function(layerKey) {
		if(getDataSourceById(layerKey)) return;

		var geoJson = geoserverDataUrl+ "/" + geoserverDataWorkspace + "/" + "/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=" +
//				geoserverDataWorkspace + ":" + layerKey + "&maxFeatures=200&outputFormat=application/json";
				geoserverDataWorkspace + ":" + layerKey + "&outputFormat=application/json";
		var promise = Cesium.GeoJsonDataSource.load(geoJson, {
			//TODO terrain 사용시 외곽선 disable 되는거 처리 해야함. wfs도 zindex를 적용해야 하는데 add 메서드에 index주는게 없음.
			stroke: Cesium.Color.fromCssColorString(layerMap[layerKey].layerLineColor),
	        fill: Cesium.Color.fromCssColorString(layerMap[layerKey].layerFillColor).withAlpha(layerMap[layerKey].layerAlphaStyle),
	        strokeWidth: layerMap[layerKey].layerLineStyle,
	        clampToGround: true
		});
		promise.then(function(wfsLayer) {
			wfsLayer.id = layerKey;
	        dataSources.add(wfsLayer);
	    }).otherwise(function(error){
	        //Display any errrors encountered while loading.
	        alert(error);
	    });
	};

	/**
	 * tile 레이어 추가
	 */
	var addTileLayer = function(layerKey) {
		if(getImageryLayerById(layerKey)) return;

		var provider = new Cesium.WebMapServiceImageryProvider({
	        url : geoserverDataUrl + "/gwc/service/wms",
	        layers : [geoserverDataWorkspace + ':'+layerKey],
	        minimumLevel:2,
	        maximumLevel : 20,
	        parameters : {
	            service : 'WMS'
	            ,version : '1.1.1'
	            ,request : 'GetMap'
	            ,transparent : 'true'
	            ,format : 'image/png'
	            ,time : 'P2Y/PRESENT',
//	            ,maxZoom : 25
//	            ,maxNativeZoom : 23,
	            tiled : true
	        }
	    });

		var targetIndex = baseMapLength;
		for(var i=0; i < imageryLayers.length; i++) {
			var layer = imageryLayers.get(i);
			var currnetLayerId = layer.id;
			// zindex에 따라 정렬 . wmsLayer, district(행정구역이동 provider)는 provider 하나씩 생성하므로 인덱스 정렬 대상에서 제외.
			if(currnetLayerId && currnetLayerId !== WMS_LAYER && currnetLayerId !== DISTRICT_LAYER) {
				if(layerMap[currnetLayerId].zindex <= layerMap[layerKey].zindex) {
					targetIndex = i+1;
				}
			}
		}

		var addedLayer = new Cesium.ImageryLayer(provider, {minimumTerrainLevel:5});
		addedLayer.id = layerKey;
		viewer.imageryLayers.add(addedLayer, targetIndex);

		//var addedLayer = viewer.imageryLayers.addImageryProvider(provider, targetIndex);
	};

	/**
	 * wms 레이어 제거
	 */
	var removeWMSLayer = function(layerKey) {
		var layerList = getWMSLayers().split(",");
		for(var i=0; i < layerList.length;i++) {
			if(layerKey === layerList[i]) {
				layerList.splice(i,1);
			}
		}

		initWMSLayer(layerList);
	};

	/**
	 * wfs 레이어 제거
	 */
	var removeWFSLayer = function(layerKey) {
		var layer = getDataSourceById(layerKey);
		dataSources.remove(layer);
	};

	/**
	 * tile 레이어 제거
	 */
	var removeTileLayer = function(layerKey) {
		var layer = getImageryLayerById(layerKey);
		imageryLayers.remove(layer);
	};

	/*
	 * wms layer string 리턴
	 */
	var getWMSLayers = function() {
		var layer = getImageryLayerById(WMS_LAYER);
		var layerList = "";
		if(layer) {
			layerList = layer._imageryProvider.layers;
			return layerList.split(geoserverDataWorkspace+":").join("");
		} else {
			return layerList;
		}
	};

	/**
	 * wms layer string이 있는지 확인
	 */
	var getWMSLayerExists = function(layerKey) {
		var layerList  = getWMSLayers().split(",");
		var flag = false;
		for(var i=0; i < layerList.length; i++) {
			if(layerList[i] === layerKey) {
				flag = true;
			}
		}

		return flag;
	};

	/**
	 * layerKey에 해당하는 imageryLayer 객체를 리턴
	 */
	var getImageryLayerById = function(layerKey) {
		var layer = null;
		var length = imageryLayers.length;
		for(var i=0; i < length; i++) {
			var id = imageryLayers.get(i).id;
			if(!id) continue;
			if(imageryLayers.get(i).id === layerKey){
	            layer = imageryLayers.get(i);
	            break;
	        }
		}

		return layer;
	};

	/**
	 * layerKey에 해당하는 dataSources 객체를 리턴
	 */
	var getDataSourceById = function(layerKey) {
		var layer = null;
		var length = dataSources.length;
		for(var i=0; i < length; i++) {
			var id = dataSources.get(i).id;
			if(!id) continue;
			if(dataSources.get(i).id === layerKey){
	            layer = dataSources.get(i);
	            break;
	        }
		}

		return layer;
	};

	return {
		/**
		 * 지도 객체에 baseLaye list를 추가
		 * @param displayFlag {boolean} true일경우에는 모든 레이어 추가, 아닐 경우에는 defaultDiaply true인 레이어만 추가
		 * @returns
		 */
		initLayer : function(displayFlag) {
			var wmsLayerList = [];
			for(var i=0; i < sortedLayer.length; i++) {
				var ogcWebServices = sortedLayer[i].ogcWebServices;
				var cacheAvailable = sortedLayer[i].cacheAvailable;
				var layerKey = sortedLayer[i].layerKey;
				layerMap[layerKey] = sortedLayer[i];
				// 기본 표시 true일 경우에만 레이어 추가
				if(!displayFlag && !sortedLayer[i].defaultDisplay) continue;
				if(ogcWebServices ==='wms' && cacheAvailable) {
					addTileLayer(layerKey);
				} else if (ogcWebServices ==='wms' && !cacheAvailable) {
					wmsLayerList.push(layerKey);
				} else if(ogcWebServices ==='wfs') {
					addWFSLayer(layerKey);
				} else {
					alert(ogcWebServices + JS_MESSAGE["layer.not.supported"]);
				}
			}

			if(wmsLayerList.length > 0) {
				initWMSLayer(wmsLayerList);
			}
		},

		/**
		 * 레이어 추가
		 */
		addLayer : function(layerKey) {
			var ogcWebServices = layerMap[layerKey].ogcWebServices;
			var cacheAvailable = layerMap[layerKey].cacheAvailable;
			if(ogcWebServices === 'wms' && cacheAvailable) {
				addTileLayer(layerKey);
			} else {
				if(ogcWebServices === 'wms') {
					addWMSLayer(layerKey);
				} else if(ogcWebServices ==='wfs') {
					addWFSLayer(layerKey);
				} else {
					alert(ogcWebServices + JS_MESSAGE["layer.not.supported"]);
				}
			}
		},

		/**
		 * 그룹 레이어 추가
		 */
		addGroupLayer : function(layerGroupId) {
			for(var i=0; i < baseLayers.length; i++) {
				var ancestor = baseLayers[i].ancestor;
				var layerList = baseLayers[i].layerList;
				var layerLength = layerList.length;
				if(layerGroupId === ancestor && layerLength > 0) {
					for(var j=0; j < layerLength; j++) {
						this.addLayer(layerList[j].layerKey);
					}
					break;
				}
			}
		},

		/**
		 * 레이어 삭제
		 */
		removeLayer : function(layerKey) {
			var ogcWebServices = layerMap[layerKey].ogcWebServices;
			var cacheAvailable = layerMap[layerKey].cacheAvailable;
			if(ogcWebServices === 'wms' && cacheAvailable) {
				removeTileLayer(layerKey);
			} else {
				if(ogcWebServices === 'wms') {
					removeWMSLayer(layerKey);
				} else if(ogcWebServices ==='wfs') {
					removeWFSLayer(layerKey);
				} else {
					alert(ogcWebServices + JS_MESSAGE["layer.not.supported"]);
				}
			}
		},

		/**
		 * 그룹 레이어 삭제
		 */
		removeGroupLayer : function(layerGroupId) {
			for(var i=0; i < baseLayers.length; i++) {
				var ancestor = baseLayers[i].ancestor;
				var layerList = baseLayers[i].layerList;
				var layerLength = layerList.length;
				if(layerGroupId === ancestor && layerLength > 0) {
					for(var j=0; j < layerLength; j++) {
						this.removeLayer(layerList[j].layerKey);
					}
					break;
				}
			}
		},

		/**
		 * 전체 레이어 삭제
		 */
		removeAllLayers : function() {
			if(imageryLayers.length > 0) {
				// 기본 provider를 제외하고 모두 삭제
				while(imageryLayers.length > baseMapLength) {
					imageryLayers.remove(imageryLayers.get(baseMapLength));
				}
			}
			// wfs 삭제
			dataSources.removeAll();
		},

		getWMSLayers : function() {
			return getWMSLayers();
		},

		getImageryLayerById : function(layerKey) {
			return getImageryLayerById(layerKey);
		},

		getDataSourceById : function(layerKey) {
			return getDataSourceById(layerKey);
		}
	}
}
<commit_msg>fix : 배경지도 위로 레이어가 보이도록 순서 조정<commit_after>/**
 * 레이어 관련 기능
 * @param magoInstance
 * @param baseLayers
 * @param policy
 * @returns
 */
function mapInit(magoInstance, baseLayers, policy) {
	if(!(this instanceof mapInit)) {
        throw new Error(JS_MESSAGE["layer.init"]);
    }

	var WMS_LAYER = 'wmsLayer';
	var DISTRICT_LAYER = 'district';
	var viewer = magoInstance.getViewer();
	var imageryLayers = viewer.imageryLayers;
	var dataSources = viewer.dataSources;
	var geoserverDataUrl = policy.geoserverDataUrl;
	var geoserverDataWorkspace = policy.geoserverDataWorkspace;
	// 레이어 리스트를 맵 형태로 저장
	var layerMap = [];
	// 레이어 리스트
	var sortedLayer = [];
	for(var i=0; i < baseLayers.length; i++) {
		var layerList = baseLayers[i].layerList;
		var layerLength = layerList.length;
		for(var j=0; j < layerLength; j++) {
			sortedLayer.push(layerList[j]);
		}
	}

	// 레이어 리스트를 zindex 기준으로 오름 차순 정렬
	sortedLayer.sort(function(a, b) {
	    return a.zindex- b.zindex
	});

	// basemap 이 n개 이므로 basemap length 확인해서 레이어 추가/삭제 시 target index로 사용
	var baseMapLength = imageryLayers._layers.filter(function(f){
		return f.baseMapName;
	}).length;

	/**
	 * wms layer init
	 */
	var initWMSLayer = function(layerList) {
		var preLayer = getImageryLayerById(WMS_LAYER);
		if(preLayer) imageryLayers.remove(preLayer);
		if(layerList.length ===0) return;

		var queryString = "enable_yn='Y'";
	    var queryStrings = layerList.map(function(){ return queryString; }).join(';');	// map: ie9부터 지원
		var provider = new Cesium.WebMapServiceImageryProvider({
	        url : geoserverDataUrl + "/wms",
	        layers : layerList.map(function(e){return geoserverDataWorkspace + ':'+e}).join(','),
	        minimumLevel:2,
	        maximumLevel : 20,
	        parameters : {
	            service : 'WMS'
	            ,version : '1.1.1'
	            ,request : 'GetMap'
	            ,transparent : 'true'
	            ,format : 'image/png'
	            ,time : 'P2Y/PRESENT'
//	            ,maxZoom : 25
//	            ,maxNativeZoom : 23
	            ,CQL_FILTER: queryStrings
	        },
	        enablePickFeatures : false
	    });

		var layer = viewer.imageryLayers.addImageryProvider(provider);
		layer.id = WMS_LAYER;
	};

	/**
	 * wms 레이어 추가
	 */
	var addWMSLayer = function(layerKey) {
		if(getWMSLayerExists(layerKey)) return;
		var layerList = null;
		if(getWMSLayers()) {
			layerList = getWMSLayers().split(",");
			var targetIndex = 0;
			// zindex에 따라 정렬
			for(var i=0; i < layerList.length; i++) {
				var currnetLayerIndex = layerMap[layerList[i]].zindex;
				if(currnetLayerIndex <= layerMap[layerKey].zindex) {
					targetIndex = i+1;
				}
			}
			layerList.splice(targetIndex, 0, layerKey);
		} else {
			layerList = [layerKey];
		}

		initWMSLayer(layerList);
	};

	/**
	 * wfs 레이어 추가
	 */
	var addWFSLayer = function(layerKey) {
		if(getDataSourceById(layerKey)) return;

		var geoJson = geoserverDataUrl+ "/" + geoserverDataWorkspace + "/" + "/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=" +
//				geoserverDataWorkspace + ":" + layerKey + "&maxFeatures=200&outputFormat=application/json";
				geoserverDataWorkspace + ":" + layerKey + "&outputFormat=application/json";
		var promise = Cesium.GeoJsonDataSource.load(geoJson, {
			//TODO terrain 사용시 외곽선 disable 되는거 처리 해야함. wfs도 zindex를 적용해야 하는데 add 메서드에 index주는게 없음.
			stroke: Cesium.Color.fromCssColorString(layerMap[layerKey].layerLineColor),
	        fill: Cesium.Color.fromCssColorString(layerMap[layerKey].layerFillColor).withAlpha(layerMap[layerKey].layerAlphaStyle),
	        strokeWidth: layerMap[layerKey].layerLineStyle,
	        clampToGround: true
		});
		promise.then(function(wfsLayer) {
			wfsLayer.id = layerKey;
	        dataSources.add(wfsLayer);
	    }).otherwise(function(error){
	        //Display any errrors encountered while loading.
	        alert(error);
	    });
	};

	/**
	 * tile 레이어 추가
	 */
	var addTileLayer = function(layerKey) {
		if(getImageryLayerById(layerKey)) return;

		var provider = new Cesium.WebMapServiceImageryProvider({
	        url : geoserverDataUrl + "/gwc/service/wms",
	        layers : [geoserverDataWorkspace + ':'+layerKey],
	        minimumLevel:2,
	        maximumLevel : 20,
	        parameters : {
	            service : 'WMS'
	            ,version : '1.1.1'
	            ,request : 'GetMap'
	            ,transparent : 'true'
	            ,format : 'image/png'
	            ,time : 'P2Y/PRESENT',
//	            ,maxZoom : 25
//	            ,maxNativeZoom : 23,
	            tiled : true
	        }
	    });

		var targetIndex = baseMapLength;
		for(var i=0; i < imageryLayers.length; i++) {
			var layer = imageryLayers.get(i);
			var currnetLayerId = layer.id;
			// zindex에 따라 정렬 . wmsLayer, district(행정구역이동 provider)는 provider 하나씩 생성하므로 인덱스 정렬 대상에서 제외.
			if(currnetLayerId && currnetLayerId !== WMS_LAYER && currnetLayerId !== DISTRICT_LAYER) {
				if(layerMap[currnetLayerId].zindex <= layerMap[layerKey].zindex) {
					targetIndex = i+1;
				}
			}
		}

		var addedLayer = new Cesium.ImageryLayer(provider, {minimumTerrainLevel:5});
		addedLayer.id = layerKey;
		viewer.imageryLayers.add(addedLayer, targetIndex);

		//var addedLayer = viewer.imageryLayers.addImageryProvider(provider, targetIndex);
	};

	/**
	 * wms 레이어 제거
	 */
	var removeWMSLayer = function(layerKey) {
		var layerList = getWMSLayers().split(",");
		for(var i=0; i < layerList.length;i++) {
			if(layerKey === layerList[i]) {
				layerList.splice(i,1);
			}
		}

		initWMSLayer(layerList);
	};

	/**
	 * wfs 레이어 제거
	 */
	var removeWFSLayer = function(layerKey) {
		var layer = getDataSourceById(layerKey);
		dataSources.remove(layer);
	};

	/**
	 * tile 레이어 제거
	 */
	var removeTileLayer = function(layerKey) {
		var layer = getImageryLayerById(layerKey);
		imageryLayers.remove(layer);
	};

	/*
	 * wms layer string 리턴
	 */
	var getWMSLayers = function() {
		var layer = getImageryLayerById(WMS_LAYER);
		var layerList = "";
		if(layer) {
			layerList = layer._imageryProvider.layers;
			return layerList.split(geoserverDataWorkspace+":").join("");
		} else {
			return layerList;
		}
	};

	/**
	 * wms layer string이 있는지 확인
	 */
	var getWMSLayerExists = function(layerKey) {
		var layerList  = getWMSLayers().split(",");
		var flag = false;
		for(var i=0; i < layerList.length; i++) {
			if(layerList[i] === layerKey) {
				flag = true;
			}
		}

		return flag;
	};

	/**
	 * layerKey에 해당하는 imageryLayer 객체를 리턴
	 */
	var getImageryLayerById = function(layerKey) {
		var layer = null;
		var length = imageryLayers.length;
		for(var i=0; i < length; i++) {
			var id = imageryLayers.get(i).id;
			if(!id) continue;
			if(imageryLayers.get(i).id === layerKey){
	            layer = imageryLayers.get(i);
	            break;
	        }
		}

		return layer;
	};

	/**
	 * layerKey에 해당하는 dataSources 객체를 리턴
	 */
	var getDataSourceById = function(layerKey) {
		var layer = null;
		var length = dataSources.length;
		for(var i=0; i < length; i++) {
			var id = dataSources.get(i).id;
			if(!id) continue;
			if(dataSources.get(i).id === layerKey){
	            layer = dataSources.get(i);
	            break;
	        }
		}

		return layer;
	};

	return {
		/**
		 * 지도 객체에 baseLaye list를 추가
		 * @param displayFlag {boolean} true일경우에는 모든 레이어 추가, 아닐 경우에는 defaultDiaply true인 레이어만 추가
		 * @returns
		 */
		initLayer : function(displayFlag) {
			var wmsLayerList = [];
			for(var i=0; i < sortedLayer.length; i++) {
				var ogcWebServices = sortedLayer[i].ogcWebServices;
				var cacheAvailable = sortedLayer[i].cacheAvailable;
				var layerKey = sortedLayer[i].layerKey;
				layerMap[layerKey] = sortedLayer[i];
				// 기본 표시 true일 경우에만 레이어 추가
				if(!displayFlag && !sortedLayer[i].defaultDisplay) continue;
				if(ogcWebServices ==='wms' && cacheAvailable) {
					addTileLayer(layerKey);
				} else if (ogcWebServices ==='wms' && !cacheAvailable) {
					wmsLayerList.push(layerKey);
				} else if(ogcWebServices ==='wfs') {
					addWFSLayer(layerKey);
				} else {
					alert(ogcWebServices + JS_MESSAGE["layer.not.supported"]);
				}
			}

			if(wmsLayerList.length > 0) {
				initWMSLayer(wmsLayerList);
			}
		},

		/**
		 * 레이어 추가
		 */
		addLayer : function(layerKey) {
			var ogcWebServices = layerMap[layerKey].ogcWebServices;
			var cacheAvailable = layerMap[layerKey].cacheAvailable;
			if(ogcWebServices === 'wms' && cacheAvailable) {
				addTileLayer(layerKey);
			} else {
				if(ogcWebServices === 'wms') {
					addWMSLayer(layerKey);
				} else if(ogcWebServices ==='wfs') {
					addWFSLayer(layerKey);
				} else {
					alert(ogcWebServices + JS_MESSAGE["layer.not.supported"]);
				}
			}
		},

		/**
		 * 그룹 레이어 추가
		 */
		addGroupLayer : function(layerGroupId) {
			for(var i=0; i < baseLayers.length; i++) {
				var ancestor = baseLayers[i].ancestor;
				var layerList = baseLayers[i].layerList;
				var layerLength = layerList.length;
				if(layerGroupId === ancestor && layerLength > 0) {
					for(var j=0; j < layerLength; j++) {
						this.addLayer(layerList[j].layerKey);
					}
					break;
				}
			}
		},

		/**
		 * 레이어 삭제
		 */
		removeLayer : function(layerKey) {
			var ogcWebServices = layerMap[layerKey].ogcWebServices;
			var cacheAvailable = layerMap[layerKey].cacheAvailable;
			if(ogcWebServices === 'wms' && cacheAvailable) {
				removeTileLayer(layerKey);
			} else {
				if(ogcWebServices === 'wms') {
					removeWMSLayer(layerKey);
				} else if(ogcWebServices ==='wfs') {
					removeWFSLayer(layerKey);
				} else {
					alert(ogcWebServices + JS_MESSAGE["layer.not.supported"]);
				}
			}
		},

		/**
		 * 그룹 레이어 삭제
		 */
		removeGroupLayer : function(layerGroupId) {
			for(var i=0; i < baseLayers.length; i++) {
				var ancestor = baseLayers[i].ancestor;
				var layerList = baseLayers[i].layerList;
				var layerLength = layerList.length;
				if(layerGroupId === ancestor && layerLength > 0) {
					for(var j=0; j < layerLength; j++) {
						this.removeLayer(layerList[j].layerKey);
					}
					break;
				}
			}
		},

		/**
		 * 전체 레이어 삭제
		 */
		removeAllLayers : function() {
			if(imageryLayers.length > 0) {
				// 기본 provider를 제외하고 모두 삭제
				while(imageryLayers.length > baseMapLength) {
					imageryLayers.remove(imageryLayers.get(baseMapLength));
				}
			}
			// wfs 삭제
			dataSources.removeAll();
		},

		getWMSLayers : function() {
			return getWMSLayers();
		},

		getImageryLayerById : function(layerKey) {
			return getImageryLayerById(layerKey);
		},

		getDataSourceById : function(layerKey) {
			return getDataSourceById(layerKey);
		}
	}
}
<|endoftext|>


<commit_before>/**
 * The Image map layer module.
 *
 * @return WMSLayer class (extends Class).
 */
define([
  'underscore',
  'amplify',
  'uri',
  'abstract/layer/OverlayLayerClass',
  'map/views/layers/CustomInfowindow',

], function(_, amplify, UriTemplate, OverlayLayerClass, CustomInfowindow) {

  'use strict';

  function bound(value, opt_min, opt_max) {
      if (opt_min != null) value = Math.max(value, opt_min);
      if (opt_max != null) value = Math.min(value, opt_max);
      return value;
  }

  function degreesToRadians(deg) {
      return deg * (Math.PI / 180);
  }

  function radiansToDegrees(rad) {
      return rad / (Math.PI / 180);
  }

  function MercatorProjection() {
      var MERCATOR_RANGE = 256;
      this.pixelOrigin_ = new google.maps.Point(
          MERCATOR_RANGE / 2, MERCATOR_RANGE / 2);
      this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
      this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
  };

  MercatorProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {
      var me = this;

      var point = opt_point || new google.maps.Point(0, 0);

      var origin = me.pixelOrigin_;
      point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
      // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
      // 89.189.  This is about a third of a tile past the edge of the world tile.
      var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999, 0.9999);
      point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -me.pixelsPerLonRadian_;
      return point;
  };

  MercatorProjection.prototype.fromDivPixelToLatLng = function(pixel, zoom) {
      var me = this;

      var origin = me.pixelOrigin_;
      var scale = Math.pow(2, zoom);
      var lng = (pixel.x / scale - origin.x) / me.pixelsPerLonDegree_;
      var latRadians = (pixel.y / scale - origin.y) / -me.pixelsPerLonRadian_;
      var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
      return new google.maps.LatLng(lat, lng);
  };

  MercatorProjection.prototype.fromDivPixelToSphericalMercator = function(pixel, zoom) {
      var me = this;
      var coord = me.fromDivPixelToLatLng(pixel, zoom);

      var r= 6378137.0;
      var x = r* degreesToRadians(coord.lng());
      var latRad = degreesToRadians(coord.lat());
      var y = (r/2) * Math.log((1+Math.sin(latRad))/ (1-Math.sin(latRad)));

      return new google.maps.Point(x,y);
  };

  var WMSLayerClass = OverlayLayerClass.extend({

    init: function(layer, options, map) {
      this.map = map;
      this.url = this.options.url;
      this.tiles = layer.tileurl;
      this._super(layer, options, map);
      this._setImageMapType(layer);
    },

    _getLayer: function() {
      var deferred = new $.Deferred();
      deferred.resolve(this._imageMaptype);
      return deferred.promise();
    },

    _setImageMapType: function(layer) {
      this._imageMaptype = new google.maps.ImageMapType({
        getTileUrl: _.bind(this._getTileUrl,this),
        tileSize: this.tileSize,
        name: this.name,
        url: this.tiles
      });
      this.addClick();
    },

    _getTileUrl: function(coord, zoom) {
      var lULP = new google.maps.Point(coord.x*256,(coord.y+1)*256);
      var lLRP = new google.maps.Point((coord.x+1)*256,coord.y*256);
      var projectionMap = new MercatorProjection();

      var lULg = projectionMap.fromDivPixelToSphericalMercator(lULP, zoom);
      var lLRg  = projectionMap.fromDivPixelToSphericalMercator(lLRP, zoom);

      var lUL_Latitude = lULg.y;
      var lUL_Longitude = lULg.x;
      var lLR_Latitude = lLRg.y;
      var lLR_Longitude = lLRg.x;
      //GJ: there is a bug when crossing the -180 longitude border (tile does not render) - this check seems to fix it
      if (lLR_Longitude < lUL_Longitude) {
        lLR_Longitude = Math.abs(lLR_Longitude);
      }
      var url = this.url;
      url += "&BBOX=" + lUL_Longitude + "," + lUL_Latitude + "," + lLR_Longitude + "," + lLR_Latitude; // set bounding box
      return url;
    },

    addClick: function() {
      google.maps.event.addListener(this.map, "click", _.bind(function(event) {
        var projectionMap = new MercatorProjection();
        this.location = {
          zoom: this.map.getZoom(),
          latlng: event.latLng,
          point: projectionMap.fromLatLngToPoint(event.latLng),
          setBounds: function() {
            this.boundL = new google.maps.LatLng(this.latlng.lat()-0.1, this.latlng.lng()-0.1);
            this.boundR = new google.maps.LatLng(this.latlng.lat()+0.1, this.latlng.lng()+0.1);
          },
          setBBox: function() {
            this.bbox = this.boundL.lng() + "," + this.boundL.lat() + "," + this.boundR.lng() + "," + this.boundR.lat();
          },
        }
        this.location.setBounds();
        this.location.setBBox();
        this.location.infowindowUrl = this.getQuery(this.location.latlng.K,this.location.latlng.G);

        $.get(this.location.infowindowUrl).done(_.bind(function(data) {
          if(this.infowindow) {
            this.infowindow.remove();
          }
          var data = JSON.parse(data);
          var infoWindowOptions = {
            offset: [0, 100],
            infowindowData: {
              name: data.features[0].attributes['tis.nombre']|| data.features[0].attributes['nombre'],
              country: data.features[0].attributes['tis.pais']|| data.features[0].attributes['pais'],
              status: data.features[0].attributes['tis.leyenda']|| data.features[0].attributes['situacion'],
              date_create: data.features[0].attributes['tis.fecha_norma'],
              area_ha: data.features[0].attributes['tis.area_oficial_ha']|| data.features[0].attributes['area_oficial_ha'],
              category:data.features[0].attributes['tis.categoria'],
              source: data.features[0].attributes['tis.fuente'],
              company: data.features[0].attributes['cia'],
              substance: data.features[0].attributes['tipo_minerio'],

            }
          }
          this.infowindow = new CustomInfowindow(this.location.latlng, this.map, infoWindowOptions);
        }, this ));

      }, this ));

    },

  });
  return WMSLayerClass;
});
<commit_msg>Raisg click bulletproof<commit_after>/**
 * The Image map layer module.
 *
 * @return WMSLayer class (extends Class).
 */
define([
  'underscore',
  'amplify',
  'uri',
  'abstract/layer/OverlayLayerClass',
  'map/views/layers/CustomInfowindow',

], function(_, amplify, UriTemplate, OverlayLayerClass, CustomInfowindow) {

  'use strict';

  function bound(value, opt_min, opt_max) {
      if (opt_min != null) value = Math.max(value, opt_min);
      if (opt_max != null) value = Math.min(value, opt_max);
      return value;
  }

  function degreesToRadians(deg) {
      return deg * (Math.PI / 180);
  }

  function radiansToDegrees(rad) {
      return rad / (Math.PI / 180);
  }

  function MercatorProjection() {
      var MERCATOR_RANGE = 256;
      this.pixelOrigin_ = new google.maps.Point(
          MERCATOR_RANGE / 2, MERCATOR_RANGE / 2);
      this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
      this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
  };

  MercatorProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {
      var me = this;

      var point = opt_point || new google.maps.Point(0, 0);

      var origin = me.pixelOrigin_;
      point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
      // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
      // 89.189.  This is about a third of a tile past the edge of the world tile.
      var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999, 0.9999);
      point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -me.pixelsPerLonRadian_;
      return point;
  };

  MercatorProjection.prototype.fromDivPixelToLatLng = function(pixel, zoom) {
      var me = this;

      var origin = me.pixelOrigin_;
      var scale = Math.pow(2, zoom);
      var lng = (pixel.x / scale - origin.x) / me.pixelsPerLonDegree_;
      var latRadians = (pixel.y / scale - origin.y) / -me.pixelsPerLonRadian_;
      var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
      return new google.maps.LatLng(lat, lng);
  };

  MercatorProjection.prototype.fromDivPixelToSphericalMercator = function(pixel, zoom) {
      var me = this;
      var coord = me.fromDivPixelToLatLng(pixel, zoom);

      var r= 6378137.0;
      var x = r* degreesToRadians(coord.lng());
      var latRad = degreesToRadians(coord.lat());
      var y = (r/2) * Math.log((1+Math.sin(latRad))/ (1-Math.sin(latRad)));

      return new google.maps.Point(x,y);
  };

  var WMSLayerClass = OverlayLayerClass.extend({

    init: function(layer, options, map) {
      this.map = map;
      this.url = this.options.url;
      this.tiles = layer.tileurl;
      this._super(layer, options, map);
      this._setImageMapType(layer);
    },

    _getLayer: function() {
      var deferred = new $.Deferred();
      deferred.resolve(this._imageMaptype);
      return deferred.promise();
    },

    _setImageMapType: function(layer) {
      this._imageMaptype = new google.maps.ImageMapType({
        getTileUrl: _.bind(this._getTileUrl,this),
        tileSize: this.tileSize,
        name: this.name,
        url: this.tiles
      });
      this.addClick();
    },

    _getTileUrl: function(coord, zoom) {
      var lULP = new google.maps.Point(coord.x*256,(coord.y+1)*256);
      var lLRP = new google.maps.Point((coord.x+1)*256,coord.y*256);
      var projectionMap = new MercatorProjection();

      var lULg = projectionMap.fromDivPixelToSphericalMercator(lULP, zoom);
      var lLRg  = projectionMap.fromDivPixelToSphericalMercator(lLRP, zoom);

      var lUL_Latitude = lULg.y;
      var lUL_Longitude = lULg.x;
      var lLR_Latitude = lLRg.y;
      var lLR_Longitude = lLRg.x;
      //GJ: there is a bug when crossing the -180 longitude border (tile does not render) - this check seems to fix it
      if (lLR_Longitude < lUL_Longitude) {
        lLR_Longitude = Math.abs(lLR_Longitude);
      }
      var url = this.url;
      url += "&BBOX=" + lUL_Longitude + "," + lUL_Latitude + "," + lLR_Longitude + "," + lLR_Latitude; // set bounding box
      return url;
    },

    addClick: function() {
      google.maps.event.addListener(this.map, "click", _.bind(function(event) {
        var projectionMap = new MercatorProjection();
        this.location = {
          zoom: this.map.getZoom(),
          latlng: event.latLng,
          point: projectionMap.fromLatLngToPoint(event.latLng),
          setBounds: function() {
            this.boundL = new google.maps.LatLng(this.latlng.lat()-0.1, this.latlng.lng()-0.1);
            this.boundR = new google.maps.LatLng(this.latlng.lat()+0.1, this.latlng.lng()+0.1);
          },
          setBBox: function() {
            this.bbox = this.boundL.lng() + "," + this.boundL.lat() + "," + this.boundR.lng() + "," + this.boundR.lat();
          },
        }
        this.location.setBounds();
        this.location.setBBox();
        this.location.infowindowUrl = this.getQuery(this.location.latlng.K,this.location.latlng.G);

        $.get(this.location.infowindowUrl).done(_.bind(function(data) {
          if(this.infowindow) {
            this.infowindow.remove();
          }
          var data = JSON.parse(data);
          if (!!data.features[0]) {
            var infoWindowOptions = {
              offset: [0, 100],
              infowindowData: {
                name: data.features[0].attributes['tis.nombre']|| data.features[0].attributes['nombre'],
                country: data.features[0].attributes['tis.pais']|| data.features[0].attributes['pais'],
                status: data.features[0].attributes['tis.leyenda']|| data.features[0].attributes['situacion'],
                date_create: data.features[0].attributes['tis.fecha_norma'],
                area_ha: data.features[0].attributes['tis.area_oficial_ha']|| data.features[0].attributes['area_oficial_ha'],
                category:data.features[0].attributes['tis.categoria'],
                source: data.features[0].attributes['tis.fuente'],
                company: data.features[0].attributes['cia'],
                substance: data.features[0].attributes['tipo_minerio'],
              }
            }
            this.infowindow = new CustomInfowindow(this.location.latlng, this.map, infoWindowOptions);
          }
        }, this ));

      }, this ));

    },

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


<commit_before>angular.module("OpenHq").controller("StoryController", function($scope, $rootScope, $routeParams, $http, $filter, $location, Task, TasksRepository, StoriesRepository, Story, AttachmentsRepository, Attachment, CurrentUser, Comment, Upload, ConfirmDialog) {
  $scope.fileUploads = [];
  $scope.currentlyUploading = 0;

  CurrentUser.get(function(user) {
    $scope.currentUser = user;
  });

  StoriesRepository.find($routeParams.slug).then(function(story) {
    console.log(story.attachments, story.comments);
    $scope.newComment = new Comment({story_id: story.id, attachment_ids: "" });
    $scope.newTask = new Task({story_id: story.id, assigned_to: 0 });
    $scope.story = story;

    $scope.story.hasCompletedTasks = $filter('completedTasks')($scope.story.tasks).length > 0;
    $scope.story.showingCompletedTasks = false;
  });

  StoriesRepository.collaborators($routeParams.slug).then(function(collaborators) {
    $scope.collaborators = collaborators;
  });

  $rootScope.$on('story:taskCompleted', function(){
    $scope.story.hasCompletedTasks = $filter('completedTasks')($scope.story.tasks).length > 0;
  });

  $scope.taskCompletionPercentage = function() {
    if (! $scope.story) return 0; // Story not loaded yet
    if ($scope.story.tasks.length === 0) return 0; // Protect zero division error

    var percent = $filter('completedTasks')($scope.story.tasks).length / $scope.story.tasks.length * 100;
    return Math.round(percent);
  };

  $scope.createComment = function(newComment) {
    newComment.create().then(function(resp) {
      $scope.story.comments.push(resp);
      $scope.fileUploads = [];
      $scope.newComment = new Comment({story_id: $scope.story.id, attachment_ids: "" });
    });
  };

  $scope.toggleEditComment = function(comment) {
    if (comment.editing) return comment.editing = false;

    comment.editing = true;
  };

  $scope.updateComment = function(comment) {
    comment.update().then(function(resp) {
      comment.editing = false;
    });
  };

  $scope.deleteComment = function(comment) {
    ConfirmDialog.show('Delete comment', 'Are you sure you want to delete this comment?').then(function(){
      comment.delete().then(function() {
        var index = $scope.story.comments.indexOf(comment);
        if (index > -1) $scope.story.comments.splice(index, 1);
      });
    });
  };

  $scope.createTask = function(newTask) {
    newTask.create().then(function(resp) {
      resp.due_at = resp.due_at ? new Date(resp.due_at) : "";
      $scope.story.tasks.push(resp);
      $scope.newTask = new Task({story_id: $scope.story.id, assigned_to: 0});
    });
  };

  $scope.archiveStory = function() {
    ConfirmDialog.show('Archive Story', 'Are you sure you want to archive this story?').then(function(){
      $scope.story.delete().then(function(){
        // TODO: add a notification
        $location.url('/projects/'+$scope.story.project.slug);
      });
    });
  };

  $scope.deleteCompletedTasks = function() {
    ConfirmDialog.show('Delete Completed Tasks', 'Are you sure you want to delete all the completed tasks?').then(function(){
      TasksRepository.deleteCompleted($routeParams.slug).then(function(){
        // remove any completed tasks from the collection
        $scope.story.tasks = _.where($scope.story.tasks, {completed: false});
        $scope.story.hasCompletedTasks = false;
        $scope.story.showingCompletedTasks = false;
      });
    });
  };

  $scope.upload = function($files) {
    if (!$files || !$files.length) {
      console.error("No files found");
      return;
    }

    _.each($files, function(file) {
      if (!file.$error) {
        $scope.currentlyUploading++;

        AttachmentsRepository.presignedUrl(file).then(function(awsData) {
          console.log("Upload start", awsData.upload_url, file.name, file.type);

          $scope.fileUploads.push(file);

          Upload.http({
              url: awsData.upload_url,
              method: "PUT",
              data: file,
              headers: {
                'Content-Type': file.type
              }
          }).progress(function (evt) {
              var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
              file.uploadProgress = progressPercentage;
          }).success(function (data, status, headers, config) {
            console.log("Upload success", arguments);
            $scope.currentlyUploading--;

            file.uploadComplete = true;

            var attachment = new Attachment({
              story_id: $scope.story.id,
              file_name: file.name,
              file_size: file.size,
              content_type: file.type,
              file_path: awsData.file_path,
            });

            attachment.create().then(function(attachment) {
              console.log("Actually created", attachment);
              $scope.story.attachments.push(attachment);

              $scope.newComment.attachment_ids += attachment.id + ",";
            });
          }); // upload

        }); // presignedUrl
      }
    });
  };

  $rootScope.$on('task:deleted', function(_ev, task_id){
    $scope.story.tasks = _.reject($scope.story.tasks, function(task){
      return task.id == task_id;
    });
  });
});
<commit_msg>remove console log<commit_after>angular.module("OpenHq").controller("StoryController", function($scope, $rootScope, $routeParams, $http, $filter, $location, Task, TasksRepository, StoriesRepository, Story, AttachmentsRepository, Attachment, CurrentUser, Comment, Upload, ConfirmDialog) {
  $scope.fileUploads = [];
  $scope.currentlyUploading = 0;

  CurrentUser.get(function(user) {
    $scope.currentUser = user;
  });

  StoriesRepository.find($routeParams.slug).then(function(story) {
    $scope.newComment = new Comment({story_id: story.id, attachment_ids: "" });
    $scope.newTask = new Task({story_id: story.id, assigned_to: 0 });
    $scope.story = story;

    $scope.story.hasCompletedTasks = $filter('completedTasks')($scope.story.tasks).length > 0;
    $scope.story.showingCompletedTasks = false;
  });

  StoriesRepository.collaborators($routeParams.slug).then(function(collaborators) {
    $scope.collaborators = collaborators;
  });

  $rootScope.$on('story:taskCompleted', function(){
    $scope.story.hasCompletedTasks = $filter('completedTasks')($scope.story.tasks).length > 0;
  });

  $scope.taskCompletionPercentage = function() {
    if (! $scope.story) return 0; // Story not loaded yet
    if ($scope.story.tasks.length === 0) return 0; // Protect zero division error

    var percent = $filter('completedTasks')($scope.story.tasks).length / $scope.story.tasks.length * 100;
    return Math.round(percent);
  };

  $scope.createComment = function(newComment) {
    newComment.create().then(function(resp) {
      $scope.story.comments.push(resp);
      $scope.fileUploads = [];
      $scope.newComment = new Comment({story_id: $scope.story.id, attachment_ids: "" });
    });
  };

  $scope.toggleEditComment = function(comment) {
    if (comment.editing) return comment.editing = false;

    comment.editing = true;
  };

  $scope.updateComment = function(comment) {
    comment.update().then(function(resp) {
      comment.editing = false;
    });
  };

  $scope.deleteComment = function(comment) {
    ConfirmDialog.show('Delete comment', 'Are you sure you want to delete this comment?').then(function(){
      comment.delete().then(function() {
        var index = $scope.story.comments.indexOf(comment);
        if (index > -1) $scope.story.comments.splice(index, 1);
      });
    });
  };

  $scope.createTask = function(newTask) {
    newTask.create().then(function(resp) {
      resp.due_at = resp.due_at ? new Date(resp.due_at) : "";
      $scope.story.tasks.push(resp);
      $scope.newTask = new Task({story_id: $scope.story.id, assigned_to: 0});
    });
  };

  $scope.archiveStory = function() {
    ConfirmDialog.show('Archive Story', 'Are you sure you want to archive this story?').then(function(){
      $scope.story.delete().then(function(){
        // TODO: add a notification
        $location.url('/projects/'+$scope.story.project.slug);
      });
    });
  };

  $scope.deleteCompletedTasks = function() {
    ConfirmDialog.show('Delete Completed Tasks', 'Are you sure you want to delete all the completed tasks?').then(function(){
      TasksRepository.deleteCompleted($routeParams.slug).then(function(){
        // remove any completed tasks from the collection
        $scope.story.tasks = _.where($scope.story.tasks, {completed: false});
        $scope.story.hasCompletedTasks = false;
        $scope.story.showingCompletedTasks = false;
      });
    });
  };

  $scope.upload = function($files) {
    if (!$files || !$files.length) {
      console.error("No files found");
      return;
    }

    _.each($files, function(file) {
      if (!file.$error) {
        $scope.currentlyUploading++;

        AttachmentsRepository.presignedUrl(file).then(function(awsData) {
          console.log("Upload start", awsData.upload_url, file.name, file.type);

          $scope.fileUploads.push(file);

          Upload.http({
              url: awsData.upload_url,
              method: "PUT",
              data: file,
              headers: {
                'Content-Type': file.type
              }
          }).progress(function (evt) {
              var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
              file.uploadProgress = progressPercentage;
          }).success(function (data, status, headers, config) {
            console.log("Upload success", arguments);
            $scope.currentlyUploading--;

            file.uploadComplete = true;

            var attachment = new Attachment({
              story_id: $scope.story.id,
              file_name: file.name,
              file_size: file.size,
              content_type: file.type,
              file_path: awsData.file_path,
            });

            attachment.create().then(function(attachment) {
              console.log("Actually created", attachment);
              $scope.story.attachments.push(attachment);

              $scope.newComment.attachment_ids += attachment.id + ",";
            });
          }); // upload

        }); // presignedUrl
      }
    });
  };

  $rootScope.$on('task:deleted', function(_ev, task_id){
    $scope.story.tasks = _.reject($scope.story.tasks, function(task){
      return task.id == task_id;
    });
  });
});
<|endoftext|>