<commit_before>var notifications = {};
notifications.total = 0;

notifications.init = function() {
    if ($('[data-notif-total]').size() > 0) {
        notifications.initCounts();
        notifications.showUnread();
        notifications.delegateReadedEvent();
        notifications.listen();
    }
};

notifications.listen = function() {
    function handleData(response) {
        response = JSON.parse(response);
        console.log(response);
        if (response) {
            if (response.t == 'n') {
                notifications.handleNewNotification(response);
            } else if (response.t == 'f') {
                notifications.handleFriendship(response.id);
            } else if (response.t == 'c') {
                notifications.handleComment(response.w, response.id, response.p)
            }
        }
    }
    if ((typeof Meteor != 'undefined') && (typeof notificationChannel != 'undefined')) {
        Meteor.registerEventCallback("process", handleData);
        Meteor.joinChannel(notificationChannel);
        Meteor.connect();
        console.log('Escuchando notifications..');
    }
};

notifications.handleNewNotification = function(response) {
    id = response.id; entity = response.p;
    notifications.updateBubbleCount(entity, 1, false);
    ajax.getNotification(id, function(response) {
        if (response) {
            entityContent = $('[data-entity]').data('entity');
            if ('total' === entityContent) {
                $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
            } else {
                if (entityContent  === entity) {
                    if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                    $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                    $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
                } else {
                    notice(notifications.getBubbleNotificationTemplate(response));
                }
            }
        }
    });
};

notifications.showCounts = function(entity, value) {
    if (value > 0) {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) {
            $('[data-notif-' + entity + ']').children("span").eq(0).html(value);
        } else {
            $('[data-notif-' + entity + ']').prepend(getBadgeTemplate(value));
        }
    } else {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) $('[data-notif-' + entity + ']').children("span").eq(0).remove();
    }
    if ('total' === entity && $('[data-notif-count]').size()) $('[data-notif-count]').html(value);
    function getBadgeTemplate(number) {
        return '' + number + '';
    }
};

notifications.initCounts = function () {
    ajax.genericAction('user_ajaxgetnotifications_typecounts', {},
        function(response) {
            if (response) {
                for (i in response) {
                    result = response[i];
                    notifications.total += parseInt(result.cnt);
                    $('[data-notif-' + result.parent + ']').data('notif-' + result.parent).count = parseInt(result.cnt);
                    notifications.showCounts(result.parent, result.cnt);
                }
                notifications.showCounts("total", notifications.total);
            }
        }
    );
};

notifications.updateBubbleCount = function(entity, value, parentOfNotification) {
    // newCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count += value;
    actualCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count;
    newCant = parseInt(actualCant) + parseInt(value);
    $('[data-notif-' + entity + ']').data('notif-' + entity).count = newCant;
    notifications.total += value;
    notifications.showCounts(entity, newCant);
    notifications.showCounts("total", notifications.total);
    $('[data-notif-' + entity + '] span').effect("highlight", {color: "#a0c882"}, 2000);
    $('[data-notif-' + entity + ']').effect("bounce", { times: 4 }, 1200);
    if ('total' === entity) {
         newCant = $('[data-notif-' + parentOfNotification + ']').data('notif-' + parentOfNotification).count += value;
         notifications.showCounts(parentOfNotification, newCant);
    }
};

notifications.showUnread = function () {
    if ($('[data-entity]').size() > 0) {
        entity = $('[data-entity]').data('entity');
        ajax.genericAction('notification_getlatest', { 'parentName' : entity},
            function(response) {
                console.log('Notifications unread for ' + entity + ': ' + response);
                nCounts = response.length;
                if (nCounts > 4) nCounts = 4;
                for (j = 0; j < nCounts; j++) {
                    id = response[j];
                    ajax.getNotification(id, function(response) {
                    if (response) {
                        if ($('[data-entity]').size() > 0) {
                            //if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                            $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                        }
                    }});
                }
            }
        )
    }
};

notifications.readNotification = function(id) {
    ajax.deleteNotification(id, function(response) {console.log('ReadNotification: ' + id + ' => ' + response)});
};

notifications.delegateReadedEvent = function () {
    $('[data-notification]').on( 'mouseenter', '[data-sidebaralert]', function() {
        readed = $(this).data('sidebaralert');
        if (!readed) {
            $(this).data('sidebaralert', true);
            entity = $('[data-entity]').data('entity');
            notificationId = $(this).find('[data-notifid]').data('notifid');
            parentOfNotification = $(this).find('[data-notifid]').data('parent');
            notifications.readNotification(notificationId);
            notifications.updateBubbleCount(entity, -1, parentOfNotification);
        }
    });
};

notifications.getBubbleNotificationTemplate = function(htmlResponse) {
    return '
' + htmlResponse + '
';
};

notifications.getClassicNotificationTemplate = function (htmlResponse) {
    btnClose = '<button type="button" class="close" data-dismiss="alert">×</button>';
    return '
'+ btnClose + htmlResponse + '
';
};

notifications.sendToMeteor = function (type) {
    ajax.genericAction('notification_setfake', {'type': type},
        function(response){}
    );
};

notifications.test = function(id, parent) {
    var r = {}; r.id = id; r.p = parent;
    notifications.handleNewNotification(r);
};

notifications.handleFriendship = function(id) {
    var actualNumber = $("li.alerts_user a span").html();
    parseInt(actualNumber);
    if(actualNumber == ''){
        actualNumber = 0;
    }

    ajax.genericAction('user_ajaxgetfriendship', {
        'id': id
    }, function(r){
        console.log(r);
        if(r){
            if(!r.target.restricted){
                notice(r.author.name + " te empezó a seguir.");
            }else{
                var template = $("#templatePendingFriends ul li").clone();
                if(r.author.image){
                    template.find("img.avatar").attr('src', r.author.image);
                }
                template.find("span.info a.name").attr('href', r.author.url).html(r.author.name);
                template.find("a.deny").attr('id', r.author.id);
                template.find("div.button a.accept").attr('id', r.author.id);
                template.addClass('hidden');

                $("li.alerts_user ul li.more").before(template);
            }
            actualNumber++;

            $("li.alerts_user a span").html(actualNumber).removeClass('hidden');
            $(".alerts_user a:first span").effect("highlight",{},3000);
            $(".alerts_user a:first").effect("bounce",{
                times:1
            },300);
        }
    });
};

notifications.handleComment = function(wallname, id, parent) {
    $('[data-wall="'+wallname+'"]').addWallComment(id, parent);
};

$(document).ready(function() {
    notifications.init();
});<commit_msg>Total count bounce issue / notifications_handler.js<commit_after>var notifications = {};
notifications.total = 0;

notifications.init = function() {
    if ($('[data-notif-total]').size() > 0) {
        notifications.initCounts();
        notifications.showUnread();
        notifications.delegateReadedEvent();
        notifications.listen();
    }
};

notifications.listen = function() {
    function handleData(response) {
        response = JSON.parse(response);
        console.log(response);
        if (response) {
            if (response.t == 'n') {
                notifications.handleNewNotification(response);
            } else if (response.t == 'f') {
                notifications.handleFriendship(response.id);
            } else if (response.t == 'c') {
                notifications.handleComment(response.w, response.id, response.p)
            }
        }
    }
    if ((typeof Meteor != 'undefined') && (typeof notificationChannel != 'undefined')) {
        Meteor.registerEventCallback("process", handleData);
        Meteor.joinChannel(notificationChannel);
        Meteor.connect();
        console.log('Escuchando notifications..');
    }
};

notifications.handleNewNotification = function(response) {
    id = response.id; entity = response.p;
    notifications.updateBubbleCount(entity, 1, false);
    ajax.getNotification(id, function(response) {
        if (response) {
            entityContent = $('[data-entity]').data('entity');
            if ('total' === entityContent) {
                $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
            } else {
                if (entityContent  === entity) {
                    if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                    $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                    $('[data-sidebaralert]:first').effect("bounce", {times:2}, 300);
                } else {
                    notice(notifications.getBubbleNotificationTemplate(response));
                }
            }
        }
    });
};

notifications.showCounts = function(entity, value) {
    if (value > 0) {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) {
            $('[data-notif-' + entity + ']').children("span").eq(0).html(value);
        } else {
            $('[data-notif-' + entity + ']').prepend(getBadgeTemplate(value));
        }
    } else {
        if ($('[data-notif-' + entity + ']').children("span").length > 0) $('[data-notif-' + entity + ']').children("span").eq(0).remove();
    }
    if ('total' === entity && $('[data-notif-count]').size()) $('[data-notif-count]').html(value);
    function getBadgeTemplate(number) {
        return '' + number + '';
    }
};

notifications.initCounts = function () {
    ajax.genericAction('user_ajaxgetnotifications_typecounts', {},
        function(response) {
            if (response) {
                for (i in response) {
                    result = response[i];
                    notifications.total += parseInt(result.cnt);
                    $('[data-notif-' + result.parent + ']').data('notif-' + result.parent).count = parseInt(result.cnt);
                    notifications.showCounts(result.parent, result.cnt);
                }
                notifications.showCounts("total", notifications.total);
            }
        }
    );
};

notifications.updateBubbleCount = function(entity, value, parentOfNotification) {
    // newCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count += value;
    actualCant = $('[data-notif-' + entity + ']').data('notif-' + entity).count;
    newCant = parseInt(actualCant) + parseInt(value);
    $('[data-notif-' + entity + ']').data('notif-' + entity).count = newCant;
    notifications.total += value;
    notifications.showCounts(entity, newCant);
    notifications.showCounts("total", notifications.total);
    $('[data-notif-' + entity + '] span').effect("highlight", {color: "#a0c882"}, 2000);
    if ('total' != entity) $('[data-notif-' + entity + ']').effect("bounce", { times: 4 }, 1200);
    if ('total' === entity) {
         newCant = $('[data-notif-' + parentOfNotification + ']').data('notif-' + parentOfNotification).count += value;
         notifications.showCounts(parentOfNotification, newCant);
    }
};

notifications.showUnread = function () {
    if ($('[data-entity]').size() > 0) {
        entity = $('[data-entity]').data('entity');
        ajax.genericAction('notification_getlatest', { 'parentName' : entity},
            function(response) {
                console.log('Notifications unread for ' + entity + ': ' + response);
                nCounts = response.length;
                if (nCounts > 4) nCounts = 4;
                for (j = 0; j < nCounts; j++) {
                    id = response[j];
                    ajax.getNotification(id, function(response) {
                    if (response) {
                        if ($('[data-entity]').size() > 0) {
                            //if ($('[data-sidebaralert]').size() >= 4) $('[data-sidebaralert]:last').fadeOut("slow").remove();
                            $('[data-notification]').prepend(notifications.getClassicNotificationTemplate(response));
                        }
                    }});
                }
            }
        )
    }
};

notifications.readNotification = function(id) {
    ajax.deleteNotification(id, function(response) {console.log('ReadNotification: ' + id + ' => ' + response)});
};

notifications.delegateReadedEvent = function () {
    $('[data-notification]').on( 'mouseenter', '[data-sidebaralert]', function() {
        readed = $(this).data('sidebaralert');
        if (!readed) {
            $(this).data('sidebaralert', true);
            entity = $('[data-entity]').data('entity');
            notificationId = $(this).find('[data-notifid]').data('notifid');
            parentOfNotification = $(this).find('[data-notifid]').data('parent');
            notifications.readNotification(notificationId);
            notifications.updateBubbleCount(entity, -1, parentOfNotification);
        }
    });
};

notifications.getBubbleNotificationTemplate = function(htmlResponse) {
    return '
' + htmlResponse + '
';
};

notifications.getClassicNotificationTemplate = function (htmlResponse) {
    btnClose = '<button type="button" class="close" data-dismiss="alert">×</button>';
    return '
'+ btnClose + htmlResponse + '
';
};

notifications.sendToMeteor = function (type) {
    ajax.genericAction('notification_setfake', {'type': type},
        function(response){}
    );
};

notifications.test = function(id, parent) {
    var r = {}; r.id = id; r.p = parent;
    notifications.handleNewNotification(r);
};

notifications.handleFriendship = function(id) {
    var actualNumber = $("li.alerts_user a span").html();
    parseInt(actualNumber);
    if(actualNumber == ''){
        actualNumber = 0;
    }

    ajax.genericAction('user_ajaxgetfriendship', {
        'id': id
    }, function(r){
        console.log(r);
        if(r){
            if(!r.target.restricted){
                notice(r.author.name + " te empezó a seguir.");
            }else{
                var template = $("#templatePendingFriends ul li").clone();
                if(r.author.image){
                    template.find("img.avatar").attr('src', r.author.image);
                }
                template.find("span.info a.name").attr('href', r.author.url).html(r.author.name);
                template.find("a.deny").attr('id', r.author.id);
                template.find("div.button a.accept").attr('id', r.author.id);
                template.addClass('hidden');

                $("li.alerts_user ul li.more").before(template);
            }
            actualNumber++;

            $("li.alerts_user a span").html(actualNumber).removeClass('hidden');
            $(".alerts_user a:first span").effect("highlight",{},3000);
            $(".alerts_user a:first").effect("bounce",{
                times:1
            },300);
        }
    });
};

notifications.handleComment = function(wallname, id, parent) {
    $('[data-wall="'+wallname+'"]').addWallComment(id, parent);
};

$(document).ready(function() {
    notifications.init();
});<|endoftext|>


<commit_before>angular.module('zeus.services', [])
.factory('Details', function($http) {
  var getReviews = function (type, id) {
    return $http({
      method: 'GET',
      url: '/review/' + type + '/' + id
    })
    .then(function (res) {
      return res;
    });
  };
  var getDetails = function (type, id, callback) {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/' + type + '/' + id + '?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    }).then(function (res) {
      return res.data;
    });
  };

  return {
    getDetails: getDetails,
    getReviews: getReviews
  };

})

.factory('Landing', function($http) {
  var getPopular = function() {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/movie/popular?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    })
    .then(function(res) {
      return res;
    });
  };

  var getLatest = function() {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/movie/latest?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    })
    .then(function(res) {
      return res;
    });
  };

  var getUpcoming = function() {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/movie/upcoming?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    })
    .then(function(res) {
      return res;
    });
  };

  return {
    getPopular: getPopular,
    getLatest: getLatest,
    getUpcoming: getUpcoming
  };

})
.factory('Results', function($http) {
  var multiSearch = function(query) {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/search/multi?api_key=144a52aa180019a468d95822c036cbce&language=en-US&query=' + query
    })
    .then(function(res) {
      return res;
    });
  };

  return {
    multiSearch: multiSearch
  };

});<commit_msg>Fix URL for latest, saves correct data form response<commit_after>angular.module('zeus.services', [])
.factory('Details', function($http) {
  var getReviews = function (type, id) {
    return $http({
      method: 'GET',
      url: '/review/' + type + '/' + id
    })
    .then(function (res) {
      return res;
    });
  };
  var getDetails = function (type, id, callback) {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/' + type + '/' + id + '?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    }).then(function (res) {
      return res.data;
    });
  };

  return {
    getDetails: getDetails,
    getReviews: getReviews
  };

})

.factory('Landing', function($http) {
  var getPopular = function() {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/movie/popular?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    })
    .then(function(res) {
      return res.data;
    });
  };

  var getLatest = function() {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/movie/now_playing?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    })
    .then(function(res) {
      return res.data;
    });
  };

  var getUpcoming = function() {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/movie/upcoming?api_key=144a52aa180019a468d95822c036cbce&language=en-US'
    })
    .then(function(res) {
      return res.data;
    });
  };

  return {
    getPopular: getPopular,
    getLatest: getLatest,
    getUpcoming: getUpcoming
  };

})
.factory('Results', function($http) {
  var multiSearch = function(query) {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/search/multi?api_key=144a52aa180019a468d95822c036cbce&language=en-US&query=' + query
    })
    .then(function(res) {
      return res;
    });
  };

  return {
    multiSearch: multiSearch
  };

});<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'

import RedactedInput from './RedactedInput'

const SlackConfig = React.createClass({
  propTypes: {
    config: PropTypes.shape({
      options: PropTypes.shape({
        url: PropTypes.bool.isRequired,
        channel: PropTypes.string.isRequired,
      }).isRequired,
    }).isRequired,
    onSave: PropTypes.func.isRequired,
    onTest: PropTypes.func.isRequired,
  },

  getInitialState() {
    return {
      testEnabled: !!this.props.config.options.url,
    }
  },

  componentWillReceiveProps(nextProps) {
    this.setState({
      testEnabled: !!nextProps.config.options.url,
    })
  },

  handleSaveAlert(e) {
    e.preventDefault()

    const properties = {
      url: this.url.value,
      channel: this.channel.value,
    }

    this.props.onSave(properties)
  },

  handleTest(e) {
    e.preventDefault()
    this.props.onTest({
      url: this.url.value,
      channel: this.channel.value,
    })
  },

  render() {
    const {url, channel} = this.props.config.options

    return (
      <form onSubmit={this.handleSaveAlert}>

            Slack Webhook URL (

              see more on Slack webhooks

            )

          <RedactedInput
            defaultValue={url}
            id="url"
            refFunc={r => (this.url = r)}
          />

          Slack Channel (optional)
          <input
            className="form-control"
            id="slack-channel"
            type="text"
            placeholder="#alerts"
            ref={r => (this.channel = r)}
            defaultValue={channel || ''}
          />

            Send Test Message

          <button className="btn btn-primary" type="submit">Save</button>

      </form>
    )
  },
})

export default SlackConfig
<commit_msg>remove test button from slack config<commit_after>import React, {PropTypes} from 'react'

import RedactedInput from './RedactedInput'

const SlackConfig = React.createClass({
  propTypes: {
    config: PropTypes.shape({
      options: PropTypes.shape({
        url: PropTypes.bool.isRequired,
        channel: PropTypes.string.isRequired,
      }).isRequired,
    }).isRequired,
    onSave: PropTypes.func.isRequired,
    onTest: PropTypes.func.isRequired,
  },

  getInitialState() {
    return {
      testEnabled: !!this.props.config.options.url,
    }
  },

  componentWillReceiveProps(nextProps) {
    this.setState({
      testEnabled: !!nextProps.config.options.url,
    })
  },

  handleSaveAlert(e) {
    e.preventDefault()

    const properties = {
      url: this.url.value,
      channel: this.channel.value,
    }

    this.props.onSave(properties)
  },

  handleTest(e) {
    e.preventDefault()
    this.props.onTest({
      url: this.url.value,
      channel: this.channel.value,
    })
  },

  render() {
    const {url, channel} = this.props.config.options

    return (
      <form onSubmit={this.handleSaveAlert}>

            Slack Webhook URL (

              see more on Slack webhooks

            )

          <RedactedInput
            defaultValue={url}
            id="url"
            refFunc={r => this.url = r}
          />

          Slack Channel (optional)
          <input
            className="form-control"
            id="slack-channel"
            type="text"
            placeholder="#alerts"
            ref={r => this.channel = r}
            defaultValue={channel || ''}
          />

          <button className="btn btn-block btn-primary" type="submit">
            Save
          </button>

      </form>
    )
  },
})

export default SlackConfig
<|endoftext|>


<commit_before>(function (module) {
    module.controller('ProjectHomeController', ProjectHomeController);
    ProjectHomeController.$inject = ["project", "mcmodal", "templates", "$state", "Restangular"];

    function ProjectHomeController(project, mcmodal, templates, $state, Restangular) {
        var ctrl = this;

        ctrl.project = project;
        ctrl.chooseTemplate = chooseTemplate;
        ctrl.chooseExistingProcess = chooseExistingProcess;
        ctrl.templates = templates;
        ctrl.hasFavorites = _.partial(_.any, ctrl.templates, _.matchesProperty('favorite', true));

        /////////////////////////

        function chooseTemplate() {
            mcmodal.chooseTemplate(ctrl.project, templates).then(function (processTemplateName) {
                $state.go('projects.project.processes.create', {process: processTemplateName, process_id: ''});
            });
        }

        function chooseExistingProcess() {
            Restangular.one('v2').one("projects", project.id).one("processes").getList().then(function(processes) {
                mcmodal.chooseExistingProcess(processes).then(function (existingProcess) {
                    var processName = existingProcess.process_name ? existingProcess.process_name : 'TEM';
                    $state.go('projects.project.processes.create', {process: processName, process_id: existingProcess.id});
                });
            });
        }
    }
}(angular.module('materialscommons')));
<commit_msg>Remove the hard coded process name now that the process name has been set.<commit_after>(function (module) {
    module.controller('ProjectHomeController', ProjectHomeController);
    ProjectHomeController.$inject = ["project", "mcmodal", "templates", "$state", "Restangular"];

    function ProjectHomeController(project, mcmodal, templates, $state, Restangular) {
        var ctrl = this;

        ctrl.project = project;
        ctrl.chooseTemplate = chooseTemplate;
        ctrl.chooseExistingProcess = chooseExistingProcess;
        ctrl.templates = templates;
        ctrl.hasFavorites = _.partial(_.any, ctrl.templates, _.matchesProperty('favorite', true));

        /////////////////////////

        function chooseTemplate() {
            mcmodal.chooseTemplate(ctrl.project, templates).then(function (processTemplateName) {
                $state.go('projects.project.processes.create', {process: processTemplateName, process_id: ''});
            });
        }

        function chooseExistingProcess() {
            Restangular.one('v2').one("projects", project.id).one("processes").getList().then(function(processes) {
                mcmodal.chooseExistingProcess(processes).then(function (existingProcess) {
                    $state.go('projects.project.processes.create',
                        {process: existingProcess.process_name, process_id: existingProcess.id});
                });
            });
        }
    }
}(angular.module('materialscommons')));
<|endoftext|>


<commit_before>var googleAuthScopes;
var googleOAuth2Result;

function onClientLoad() {
  $.ajax({
    url: apiBaseUrl + '/oauth2-scopes',
    type: 'GET',
    dataType: 'json'
  })
  .fail(onAjaxError)
  .done(onGetOAuth2Scopes);
}

function onGetOAuth2Scopes(data, textStatus, jqXHR) {
  googleAuthScopes = data;

  gapi.client.setApiKey(googleClientSecret);
  authorize();

  $('#appTokenButton').click(function () {
    invokeOAuthAuthorization('offline');
  });
}

function authorize() {
  setTimeout(function() {
    gapi.auth.authorize({
      client_id: googleClientId,
      scope: googleAuthScopes,
      immediate: true
    }, onAuthResult);
  }, 1);
}

function onAuthResult(authResult) {
  var authorizeButton = $('#authorize-button');

  if (authResult && !authResult.error) {
    googleOAuth2Result = authResult;
    authorizeButton.hide();

    checkSchedule()
      .fail(onFirstCheckScheduleFail);

    $('#refreshButton').click(function () {
      $('#no-bus-schedule').hide();
      $('#departures').hide();
      $('#departures-list').empty();

      checkSchedule()
        .fail(onFirstCheckScheduleFail);
    });

  } else {
    $('#authorize').show();
    $('#authorize-button').click(function() {
      invokeOAuthAuthorization('online');

      return false;
    });
  }
}

function onAjaxError(jqXHR, textStatus, errorThrown) {
  if (jqXHR.status == 401) {
    // token expired - authorize again
    authorize();
  } else {
    alert("ERROR: " + jqXHR.status + ": " + textStatus + ": " + errorThrown);
  }
}

function setAuthorizationHeader(jqXHR) {
  jqXHR.setRequestHeader('Authorization', googleOAuth2Result.token_type + ' ' + googleOAuth2Result.access_token);
}

function checkSchedule() {
  return $.ajax({
    url: apiBaseUrl + '/schedule',
    type: 'GET',
    dataType: 'json',
    beforeSend: setAuthorizationHeader,
  }).done(onCheckScheduleDone);
}

function onFirstCheckScheduleFail(jqXHR, textStatus, errorThrown) {
  if (jqXHR.status === 404) {
    // user hasn't created their schedule yet
    createEmptySchedule()
      .done(function () {
        // attempt to get schedule again
        checkSchedule()
          .fail(onAjaxError);
      });
  } else {
    onAjaxError(jqXHR, textStatus, errorThrown);
  }
}

function onCheckScheduleDone(data, textStatus, jqXHR) {
  $('#authenticated').show();
  $('#editScheduleButton').click(function () {
    window.open(data.editUrl, '_blank');
  });

  if ($.isEmptyObject(data.routes)) {
    // nothing defined in the schedule - prompt user to edit their schedule
    $('#no-bus-schedule').show();
  } else {
    // a schedule exists - get departures
    getDepartures();
  }
}

function createEmptySchedule() {
  return $.ajax({
    url: apiBaseUrl + '/schedule',
    type: 'POST',
    beforeSend: setAuthorizationHeader,
  }).fail(onAjaxError);
}

function getDepartures() {
  return $.ajax({
    url: apiBaseUrl + '/departures',
    type: 'GET',
    dataType: 'json',
    beforeSend: setAuthorizationHeader,
  })
  .fail(onAjaxError)
  .done(onGetDeparturesDone);
}

function onGetDeparturesDone(data, textStatus, jqXHR) {
  $.each(data, function (index, departure) {
    var route = departure.route.number;
    if (departure.route.terminal) {
      route += ('-' + departure.route.terminal);
    }

    var time = moment(departure.time);

    var wait = time.diff(moment(), 'minutes');

    var message = time.format('LT') + " (" + wait + " minutes): " + route + " @ " + departure.stop.name;
    var item = $('
' + message + '
');

    $('#departures-list').append(item);
  });

  $('#departures').show();
}

function invokeOAuthAuthorization(accessType) {
  var redirectUri = window.location.protocol + '//' + window.location.host + '/' + googleOAuth2CallbackUrl;

  var oauthUrl = 'https://accounts.google.com/o/oauth2/auth' +
    '?' +
    '&client_id=' + encodeURI(googleClientId) +
    '&scope=' + encodeURI(googleAuthScopes) +
    '&immediate=false' +
    '&response_type=code' +
    '&redirect_uri=' + encodeURI(redirectUri) +
    '&access_type=' + accessType +
    '&state=' + accessType +
    '&approval_prompt=force';

  window.location = oauthUrl;
}
<commit_msg>Tweak API parse w/ new endpoint data<commit_after>var googleAuthScopes;
var googleOAuth2Result;

function onClientLoad() {
  $.ajax({
    url: apiBaseUrl + '/oauth2-scopes',
    type: 'GET',
    dataType: 'json'
  })
  .fail(onAjaxError)
  .done(onGetOAuth2Scopes);
}

function onGetOAuth2Scopes(data, textStatus, jqXHR) {
  googleAuthScopes = data;

  gapi.client.setApiKey(googleClientSecret);
  authorize();

  $('#appTokenButton').click(function () {
    invokeOAuthAuthorization('offline');
  });
}

function authorize() {
  setTimeout(function() {
    gapi.auth.authorize({
      client_id: googleClientId,
      scope: googleAuthScopes,
      immediate: true
    }, onAuthResult);
  }, 1);
}

function onAuthResult(authResult) {
  var authorizeButton = $('#authorize-button');

  if (authResult && !authResult.error) {
    googleOAuth2Result = authResult;
    authorizeButton.hide();

    checkSchedule()
      .fail(onFirstCheckScheduleFail);

    $('#refreshButton').click(function () {
      $('#no-bus-schedule').hide();
      $('#departures').hide();
      $('#departures-list').empty();

      checkSchedule()
        .fail(onFirstCheckScheduleFail);
    });

  } else {
    $('#authorize').show();
    $('#authorize-button').click(function() {
      invokeOAuthAuthorization('online');

      return false;
    });
  }
}

function onAjaxError(jqXHR, textStatus, errorThrown) {
  if (jqXHR.status == 401) {
    // token expired - authorize again
    authorize();
  } else {
    alert("ERROR: " + jqXHR.status + ": " + textStatus + ": " + errorThrown);
  }
}

function setAuthorizationHeader(jqXHR) {
  jqXHR.setRequestHeader('Authorization', googleOAuth2Result.token_type + ' ' + googleOAuth2Result.access_token);
}

function checkSchedule() {
  return $.ajax({
    url: apiBaseUrl + '/schedule',
    type: 'GET',
    dataType: 'json',
    beforeSend: setAuthorizationHeader,
  }).done(onCheckScheduleDone);
}

function onFirstCheckScheduleFail(jqXHR, textStatus, errorThrown) {
  if (jqXHR.status === 404) {
    // user hasn't created their schedule yet
    createEmptySchedule()
      .done(function () {
        // attempt to get schedule again
        checkSchedule()
          .fail(onAjaxError);
      });
  } else {
    onAjaxError(jqXHR, textStatus, errorThrown);
  }
}

function onCheckScheduleDone(data, textStatus, jqXHR) {
  $('#authenticated').show();
  $('#editScheduleButton').click(function () {
    window.open(data.editUrl, '_blank');
  });

  if ($.isEmptyObject(data.routes)) {
    // nothing defined in the schedule - prompt user to edit their schedule
    $('#no-bus-schedule').show();
  } else {
    // a schedule exists - get departures
    getDepartures();
  }
}

function createEmptySchedule() {
  return $.ajax({
    url: apiBaseUrl + '/schedule',
    type: 'POST',
    beforeSend: setAuthorizationHeader,
  }).fail(onAjaxError);
}

function getDepartures() {
  return $.ajax({
    url: apiBaseUrl + '/departures',
    type: 'GET',
    dataType: 'json',
    beforeSend: setAuthorizationHeader,
  })
  .fail(onAjaxError)
  .done(onGetDeparturesDone);
}

function onGetDeparturesDone(data, textStatus, jqXHR) {
  $.each(data, function (index, departure) {
    var route = departure.route.id;
    if (departure.route.terminal) {
      route += ('-' + departure.route.terminal);
    }

    var time = moment(departure.time);

    var wait = time.diff(moment(), 'minutes');

    var message = time.format('LT') + " (" + wait + " minutes): " + route + " @ " + departure.stop.description;
    var item = $('
' + message + '
');

    $('#departures-list').append(item);
  });

  $('#departures').show();
}

function invokeOAuthAuthorization(accessType) {
  var redirectUri = window.location.protocol + '//' + window.location.host + '/' + googleOAuth2CallbackUrl;

  var oauthUrl = 'https://accounts.google.com/o/oauth2/auth' +
    '?' +
    '&client_id=' + encodeURI(googleClientId) +
    '&scope=' + encodeURI(googleAuthScopes) +
    '&immediate=false' +
    '&response_type=code' +
    '&redirect_uri=' + encodeURI(redirectUri) +
    '&access_type=' + accessType +
    '&state=' + accessType +
    '&approval_prompt=force';

  window.location = oauthUrl;
}
<|endoftext|>


<commit_before>// U+0590  to U+05FF  - Hebrew
// U+0600  to U+06FF  - Arabic
// U+0700  to U+074F  - Syriac
// U+0750  to U+077F  - Arabic Supplement
// U+0780  to U+07BF  - Thaana
// U+07C0  to U+07FF  - N'Ko
// U+0800  to U+083F  - Samaritan
// U+08A0  to U+08FF  - Arabic Extended-A
// U+FB1D  to U+FB4F  - Hebrew presentation forms
// U+FB50  to U+FDFF  - Arabic presentation forms A
// U+FE70  to U+FEFF  - Arabic presentation forms B

const rtlChars = /[\u0590-\u083F]|[\u08A0-\u08FF]|[\uFB1D-\uFDFF]|[\uFE70-\uFEFF]/mg;

export function isRtl(text) {
  if (text.length === 0) {
    return false;
  }

  text = text.replace(/(?:^|[^\/\w])@([a-z0-9_]+(@[a-z0-9\.\-]+)?)/ig, '');
  text = text.replace(/(?:^|[^\/\w])#([\S]+)/ig, '');
  text = text.replace(/\s+/g, '');

  const matches = text.match(rtlChars);

  if (!matches) {
    return false;
  }

  return matches.length / text.length > 0.3;
};
<commit_msg>Exclude URLs from text analysis (#11759)<commit_after>// U+0590  to U+05FF  - Hebrew
// U+0600  to U+06FF  - Arabic
// U+0700  to U+074F  - Syriac
// U+0750  to U+077F  - Arabic Supplement
// U+0780  to U+07BF  - Thaana
// U+07C0  to U+07FF  - N'Ko
// U+0800  to U+083F  - Samaritan
// U+08A0  to U+08FF  - Arabic Extended-A
// U+FB1D  to U+FB4F  - Hebrew presentation forms
// U+FB50  to U+FDFF  - Arabic presentation forms A
// U+FE70  to U+FEFF  - Arabic presentation forms B

const rtlChars = /[\u0590-\u083F]|[\u08A0-\u08FF]|[\uFB1D-\uFDFF]|[\uFE70-\uFEFF]/mg;

export function isRtl(text) {
  if (text.length === 0) {
    return false;
  }

  text = text.replace(/(?:^|[^\/\w])@([a-z0-9_]+(@[a-z0-9\.\-]+)?)/ig, '');
  text = text.replace(/(?:^|[^\/\w])#([\S]+)/ig, '');
  text = text.replace(/\s+/g, '');
  text = text.replace(/(\w\S+\.\w{2,}\S*)/g, '');

  const matches = text.match(rtlChars);

  if (!matches) {
    return false;
  }

  return matches.length / text.length > 0.3;
};
<|endoftext|>


<commit_before>// Geometries
var point = new ol.geom.Point(
    ol.proj.transform([3,50], 'EPSG:4326', 'EPSG:3857')
    );

// Features
var pointFeature = new ol.Feature(point);

// Source and vector layer
var vectorSource = new ol.source.Vector();

var style = new ol.style.Style({
    image: new ol.style.Circle({
        fill: new ol.style.Fill({
            color: 'rgba(255, 100, 50, 0.3)'
        }),
        stroke: new ol.style.Stroke({
            width: 1,
            color: 'rgba(255, 100, 50, 0.8)'
        }),
        radius: 7
    }),
});

var vectorLayer = new ol.layer.Vector({
    source: vectorSource,
    style: style
});

// Maps
var map = new ol.Map({
target: 'map',  // The DOM element that will contains the map
renderer: 'canvas', // Force the renderer to be used
layers: [
// Add a new Tile layer getting tiles from OpenStreetMap source
new ol.layer.Tile({
    source: new ol.source.OSM()
}),
vectorLayer
],
// Create a view centered on the specified location and zoom level
view: new ol.View({
    center: ol.proj.transform([2.1833, 41.3833], 'EPSG:4326', 'EPSG:3857'),
    zoom: 2
})
});

function emptyVector() {
  var features = vectorSource.getFeatures();

  for(var i = 0; i < features.length; i++) {
    vectorSource.removeFeature(features[i]);
  }
}

var script = null;

function checkTweets(query) {
    $.getJSON( "emoji.json", function(tweets) {
        console.log(tweets);
        for(var i = 0; i < tweets.data.length; i++) {
            if (tweets.data[i].indexOf(query) !== -1) {
                return 1;
            }
        }
    });
    return 0;
}

function updateMap() {
  if(vectorSource.getFeatures().length > 0) { // Empty the vector, if full
    emptyVector();
  }

var query = document.getElementById('searchField').value;

var flag = checkTweets(query);

if(flag !== 1) {
    return;
}

// Fetch loklak API data, and fill the vector
loklakFetcher.getTweets(query, function(tweets) {
    for(var i = 0; i < tweets.statuses.length; i++) {
        if(tweets.statuses[i].location_point !== undefined){
            // Creation of the point with the tweet's coordinates
            //  Coords system swap is required: OpenLayers uses by default
            //  EPSG:3857, while loklak's output is EPSG:4326
            var point = new ol.geom.Point(ol.proj.transform(tweets.statuses[i].location_point, 'EPSG:4326', 'EPSG:3857'));
            vectorSource.addFeature(new ol.Feature({  // Add the point to the data vector
                geometry: point
            }));
        }
    }
});
}

// Event listeners for updating the map
document.getElementById('searchButton').addEventListener('click', updateMap);

document.getElementById('searchField').addEventListener('keyup', function(e) {
  if(e.keyCode === 13) {
    updateMap();
  }
});
<commit_msg>new additions<commit_after>// Geometries
var point = new ol.geom.Point(
    ol.proj.transform([3,50], 'EPSG:4326', 'EPSG:3857')
    );

// Features
var pointFeature = new ol.Feature(point);

// Source and vector layer
var vectorSource = new ol.source.Vector();

var style = new ol.style.Style({
    image: new ol.style.Circle({
        fill: new ol.style.Fill({
            color: 'rgba(255, 100, 50, 0.3)'
        }),
        stroke: new ol.style.Stroke({
            width: 1,
            color: 'rgba(255, 100, 50, 0.8)'
        }),
        radius: 7
    }),
});

var vectorLayer = new ol.layer.Vector({
    source: vectorSource,
    style: style
});

// Maps
var map = new ol.Map({
target: 'map',  // The DOM element that will contains the map
renderer: 'canvas', // Force the renderer to be used
layers: [
// Add a new Tile layer getting tiles from OpenStreetMap source
new ol.layer.Tile({
    source: new ol.source.OSM()
}),
vectorLayer
],
// Create a view centered on the specified location and zoom level
view: new ol.View({
    center: ol.proj.transform([2.1833, 41.3833], 'EPSG:4326', 'EPSG:3857'),
    zoom: 2
})
});

function emptyVector() {
  var features = vectorSource.getFeatures();

  for(var i = 0; i < features.length; i++) {
    vectorSource.removeFeature(features[i]);
  }
}

var script = null;

function checkTweets(query) {
    $.getJSON( "emoji.json", function(tweets) {
        console.log(tweets);
        for(var i = 0; i < tweets.data.length; i++) {
            if (tweets.data[i].indexOf(query) !== -1) {
                console.log(tweets.data[i].indexOf(query));
                return 1;
            }
        }
    });
    return 0;
}

function updateMap() {
  if(vectorSource.getFeatures().length > 0) { // Empty the vector, if full
    emptyVector();
  }

var query = document.getElementById('searchField').value;

var flag = checkTweets(query);

console.log(flag);
if(flag !== 1) {
    return;
}

// Fetch loklak API data, and fill the vector
loklakFetcher.getTweets(query, function(tweets) {
    for(var i = 0; i < tweets.statuses.length; i++) {
        if(tweets.statuses[i].location_point !== undefined){
            // Creation of the point with the tweet's coordinates
            //  Coords system swap is required: OpenLayers uses by default
            //  EPSG:3857, while loklak's output is EPSG:4326
            var point = new ol.geom.Point(ol.proj.transform(tweets.statuses[i].location_point, 'EPSG:4326', 'EPSG:3857'));
            vectorSource.addFeature(new ol.Feature({  // Add the point to the data vector
                geometry: point
            }));
        }
    }
});
}

// Event listeners for updating the map
document.getElementById('searchButton').addEventListener('click', updateMap);

document.getElementById('searchField').addEventListener('keyup', function(e) {
  if(e.keyCode === 13) {
    updateMap();
  }
});
<|endoftext|>


<commit_before>define(['backbone'], function(Backbone) {

    return {
        opts: function(options) {
            return (options && options.empty ? '<option value=""> - </option>' : '') +
                this.map(function(m) { return '<option value="'+m.get(this.valueAttribute)+'">'+m.get(this.keyAttribute)+'</option>' }, this)
        },

        kv: function(options) {
            var kv = {}
            if (options && options.empty) kv[''] = ' - '

            this.each(function(m) {
                kv[m.get(this.valueAttribute)] = m.get(this.keyAttribute)
            }, this)

            return kv
        },
    }

})<commit_msg>kvcol can add a class to an option<commit_after>define(['backbone'], function(Backbone) {

    return {
        opts: function(options) {
            return (options && options.empty ? '<option value=""> - </option>' : '') +
                this.map(function(m) {
                    var cl= ''
                    if (options && options.addClass && options.classProperty) {
                        if (m.get(options.classProperty) == options.classPropertyValue) cl = options.addClass
                    }
                    return '<option class="'+cl+'" value="'+m.get(this.valueAttribute)+'">'+m.get(this.keyAttribute)+'</option>'
                }, this)
        },

        kv: function(options) {
            var kv = {}
            if (options && options.empty) kv[''] = ' - '

            this.each(function(m) {
                kv[m.get(this.valueAttribute)] = m.get(this.keyAttribute)
            }, this)

            return kv
        },
    }

})<|endoftext|>


<commit_before>/* @flow */

import { CompositeDisposable, Disposable } from 'sb-event-kit'
import { it, beforeEach, wait } from 'jasmine-fix'
import Commands from '../lib/commands'
import { getKeyboardEvent } from './helpers'

describe('Commands', function() {
  let commands
  let editorView

  beforeEach(async function() {
    commands = new Commands()
    commands.activate()
    await atom.workspace.open(__filename)
    editorView = atom.views.getView(atom.workspace.getActiveTextEditor())
  })
  afterEach(function() {
    atom.workspace.destroyActivePane()
    commands.dispose()
  })

  describe('Highlights', function() {
    it('does nothing if not activated and we try to deactivate', function() {
      commands.processHighlightsHide()
    })
    it('does not activate unless provider tells it to', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onHighlightsShow(function() {
        timesShow++
        return Promise.resolve(false)
      })
      commands.onHighlightsHide(function() {
        timesHide++
      })
      await commands.processHighlightsShow()
      commands.processHighlightsHide()

      expect(timesShow).toBe(1)
      expect(timesHide).toBe(0)
    })
    it('activates when the provider tells it to', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onHighlightsShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onHighlightsHide(function() {
        timesHide++
      })
      await commands.processHighlightsShow()
      commands.processHighlightsHide()

      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('throws if already highlighted', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onHighlightsShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onHighlightsHide(function() {
        timesHide++
      })
      await commands.processHighlightsShow()
      try {
        await commands.processHighlightsShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      try {
        await commands.processHighlightsShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      commands.processHighlightsHide()
      commands.processHighlightsHide()
      commands.processHighlightsHide()

      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('disposes list if available', async function() {
      let disposed = false
      const active = { type: 'list', subscriptions: new CompositeDisposable() }
      active.subscriptions.add(new Disposable(function() {
        disposed = true
      }))
      commands.active = active
      expect(disposed).toBe(false)
      await commands.processHighlightsShow()
      expect(disposed).toBe(true)
    })
    it('adds and removes classes appropriately', async function() {
      commands.onHighlightsShow(function() {
        return Promise.resolve(true)
      })
      expect(editorView.classList.contains('intentions-highlights')).toBe(false)
      await commands.processHighlightsShow()
      expect(editorView.classList.contains('intentions-highlights')).toBe(true)
      commands.processHighlightsHide()
      expect(editorView.classList.contains('intentions-highlights')).toBe(false)
    })
    describe('command listener', function() {
      it('just activates if theres no keyboard event attached', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.commands.dispatch(editorView, 'intentions:highlight')
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('just activates if keyboard event is not keydown', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('does not deactivate if keyup is not same keycode', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keydown'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup', 1))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('does deactivate if keyup is the same keycode', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keydown'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
    })
  })
  describe('Lists', function() {
    it('does nothing if deactivated and we try to activate it', function() {
      commands.processListHide()
    })
    it('does not pass on move events if not activated', function() {
      const callback = jasmine.createSpy('commands:list-move')
      commands.onListMove(callback)
      commands.processListMove('up')
      commands.processListMove('down')
      commands.processListMove('down')
      expect(callback).not.toHaveBeenCalled()
    })
    it('passes on move events if activated', function() {
      const callback = jasmine.createSpy('commands:list-move')
      commands.onListMove(callback)
      commands.processListMove('down')
      commands.processListMove('down')
      commands.processListMove('down')
      commands.active = { type: 'list', subscriptions: new CompositeDisposable() }
      commands.processListMove('down')
      commands.processListMove('down')
      commands.processListMove('down')
      expect(callback).toHaveBeenCalled()
      expect(callback.calls.length).toBe(3)
    })
    it('ignores confirm if not activated', function() {
      const callback = jasmine.createSpy('commands:list-confirm')
      commands.onListConfirm(callback)
      commands.processListConfirm()
      commands.processListConfirm()
      commands.processListConfirm()
      commands.processListConfirm()
      expect(callback).not.toHaveBeenCalled()
    })
    it('passes on confirm if activated', function() {
      const callback = jasmine.createSpy('commands:list-confirm')
      commands.onListConfirm(callback)
      commands.processListConfirm()
      commands.processListConfirm()
      commands.active = { type: 'list', subscriptions: new CompositeDisposable() }
      commands.processListConfirm()
      commands.processListConfirm()
      expect(callback).toHaveBeenCalled()
      expect(callback.calls.length).toBe(2)
    })
    it('does not activate if listeners dont say that', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(false)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(0)
    })
    it('activates when listeners allow', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('ignores if list is already active', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      try {
        await commands.processListShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      try {
        await commands.processListShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      try {
        await commands.processListShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      commands.processListHide()
      commands.processListHide()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('disposes if highlights are active', async function() {
      let disposed = false
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
      commands.active = { type: 'highlight', subscriptions: new CompositeDisposable() }
      commands.active.subscriptions.add(new Disposable(function() {
        disposed = true
      }))
      expect(disposed).toBe(false)
      await commands.processListShow()
      commands.processListHide()
      expect(disposed).toBe(true)
      expect(timesShow).toBe(2)
      expect(timesHide).toBe(2)
    })
    it('adds and removes classes appropriately', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      expect(editorView.classList.contains('intentions-list')).toBe(false)
      await commands.processListShow()
      expect(editorView.classList.contains('intentions-list')).toBe(true)
      commands.processListHide()
      expect(editorView.classList.contains('intentions-list')).toBe(false)
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('disposes list on mouseup', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
      await commands.processListShow()
      document.body.dispatchEvent(new MouseEvent('mouseup'))
      await wait(10)
      expect(timesShow).toBe(2)
      expect(timesHide).toBe(2)
    })
    describe('command listener', function() {
      it('just enables when no keyboard event', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onListHide(function() {
          timesHide++
        })
        atom.commands.dispatch(editorView, 'intentions:show')
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processListHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('just enables when keyboard event is not keydown', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onListHide(function() {
          timesHide++
        })
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processListHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('disposes itself on any commands other than known', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onListHide(function() {
          timesHide++
        })
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keydown'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)

        atom.keymaps.emitter.emit('did-match-binding', { binding: { command: 'core:move-up' } })
        await wait(10)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)

        atom.keymaps.emitter.emit('did-match-binding', { binding: { command: 'core:move-down' } })
        await wait(10)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)

        atom.keymaps.emitter.emit('did-match-binding', { binding: { command: 'core:move-confirm' } })
        await wait(10)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)

        commands.processListHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
    })
  })
})
<commit_msg>:white_check_mark: Add specs for new behavior Fixes #26<commit_after>/* @flow */

import { CompositeDisposable, Disposable } from 'sb-event-kit'
import { it, beforeEach, wait } from 'jasmine-fix'
import Commands from '../lib/commands'
import { getKeyboardEvent } from './helpers'

describe('Commands', function() {
  let commands
  let editorView

  beforeEach(async function() {
    commands = new Commands()
    commands.activate()
    await atom.workspace.open(__filename)
    editorView = atom.views.getView(atom.workspace.getActiveTextEditor())
  })
  afterEach(function() {
    atom.workspace.destroyActivePane()
    commands.dispose()
  })

  describe('Highlights', function() {
    it('does nothing if not activated and we try to deactivate', function() {
      commands.processHighlightsHide()
    })
    it('does not activate unless provider tells it to', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onHighlightsShow(function() {
        timesShow++
        return Promise.resolve(false)
      })
      commands.onHighlightsHide(function() {
        timesHide++
      })
      await commands.processHighlightsShow()
      commands.processHighlightsHide()

      expect(timesShow).toBe(1)
      expect(timesHide).toBe(0)
    })
    it('activates when the provider tells it to', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onHighlightsShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onHighlightsHide(function() {
        timesHide++
      })
      await commands.processHighlightsShow()
      commands.processHighlightsHide()

      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('throws if already highlighted', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onHighlightsShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onHighlightsHide(function() {
        timesHide++
      })
      await commands.processHighlightsShow()
      try {
        await commands.processHighlightsShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      try {
        await commands.processHighlightsShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      commands.processHighlightsHide()
      commands.processHighlightsHide()
      commands.processHighlightsHide()

      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('disposes list if available', async function() {
      let disposed = false
      const active = { type: 'list', subscriptions: new CompositeDisposable() }
      active.subscriptions.add(new Disposable(function() {
        disposed = true
      }))
      commands.active = active
      expect(disposed).toBe(false)
      await commands.processHighlightsShow()
      expect(disposed).toBe(true)
    })
    it('adds and removes classes appropriately', async function() {
      commands.onHighlightsShow(function() {
        return Promise.resolve(true)
      })
      expect(editorView.classList.contains('intentions-highlights')).toBe(false)
      await commands.processHighlightsShow()
      expect(editorView.classList.contains('intentions-highlights')).toBe(true)
      commands.processHighlightsHide()
      expect(editorView.classList.contains('intentions-highlights')).toBe(false)
    })
    describe('command listener', function() {
      it('just activates if theres no keyboard event attached', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.commands.dispatch(editorView, 'intentions:highlight')
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('ignores more than one activation requests', async function() {
        let timesShow = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        expect(timesShow).toBe(1)
      })
      it('just activates if keyboard event is not keydown', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('does not deactivate if keyup is not same keycode', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keydown'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup', 1))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('does deactivate if keyup is the same keycode', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onHighlightsShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onHighlightsHide(function() {
          timesHide++
        })
        expect(timesShow).toBe(0)
        expect(timesHide).toBe(0)
        atom.keymaps.dispatchCommandEvent('intentions:highlight', editorView, getKeyboardEvent('keydown'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
        commands.processHighlightsHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
    })
  })
  describe('Lists', function() {
    it('does nothing if deactivated and we try to activate it', function() {
      commands.processListHide()
    })
    it('does not pass on move events if not activated', function() {
      const callback = jasmine.createSpy('commands:list-move')
      commands.onListMove(callback)
      commands.processListMove('up')
      commands.processListMove('down')
      commands.processListMove('down')
      expect(callback).not.toHaveBeenCalled()
    })
    it('passes on move events if activated', function() {
      const callback = jasmine.createSpy('commands:list-move')
      commands.onListMove(callback)
      commands.processListMove('down')
      commands.processListMove('down')
      commands.processListMove('down')
      commands.active = { type: 'list', subscriptions: new CompositeDisposable() }
      commands.processListMove('down')
      commands.processListMove('down')
      commands.processListMove('down')
      expect(callback).toHaveBeenCalled()
      expect(callback.calls.length).toBe(3)
    })
    it('ignores confirm if not activated', function() {
      const callback = jasmine.createSpy('commands:list-confirm')
      commands.onListConfirm(callback)
      commands.processListConfirm()
      commands.processListConfirm()
      commands.processListConfirm()
      commands.processListConfirm()
      expect(callback).not.toHaveBeenCalled()
    })
    it('passes on confirm if activated', function() {
      const callback = jasmine.createSpy('commands:list-confirm')
      commands.onListConfirm(callback)
      commands.processListConfirm()
      commands.processListConfirm()
      commands.active = { type: 'list', subscriptions: new CompositeDisposable() }
      commands.processListConfirm()
      commands.processListConfirm()
      expect(callback).toHaveBeenCalled()
      expect(callback.calls.length).toBe(2)
    })
    it('does not activate if listeners dont say that', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(false)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(0)
    })
    it('activates when listeners allow', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('ignores if list is already active', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      try {
        await commands.processListShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      try {
        await commands.processListShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      try {
        await commands.processListShow()
        expect(false).toBe(true)
      } catch (error) {
        expect(error.message).toBe('Already active')
      }
      commands.processListHide()
      commands.processListHide()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('disposes if highlights are active', async function() {
      let disposed = false
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
      commands.active = { type: 'highlight', subscriptions: new CompositeDisposable() }
      commands.active.subscriptions.add(new Disposable(function() {
        disposed = true
      }))
      expect(disposed).toBe(false)
      await commands.processListShow()
      commands.processListHide()
      expect(disposed).toBe(true)
      expect(timesShow).toBe(2)
      expect(timesHide).toBe(2)
    })
    it('adds and removes classes appropriately', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      expect(editorView.classList.contains('intentions-list')).toBe(false)
      await commands.processListShow()
      expect(editorView.classList.contains('intentions-list')).toBe(true)
      commands.processListHide()
      expect(editorView.classList.contains('intentions-list')).toBe(false)
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
    })
    it('disposes list on mouseup', async function() {
      let timesShow = 0
      let timesHide = 0
      commands.onListShow(function() {
        timesShow++
        return Promise.resolve(true)
      })
      commands.onListHide(function() {
        timesHide++
      })
      await commands.processListShow()
      commands.processListHide()
      expect(timesShow).toBe(1)
      expect(timesHide).toBe(1)
      await commands.processListShow()
      document.body.dispatchEvent(new MouseEvent('mouseup'))
      await wait(10)
      expect(timesShow).toBe(2)
      expect(timesHide).toBe(2)
    })
    describe('command listener', function() {
      it('just enables when no keyboard event', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onListHide(function() {
          timesHide++
        })
        atom.commands.dispatch(editorView, 'intentions:show')
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processListHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('just enables when keyboard event is not keydown', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onListHide(function() {
          timesHide++
        })
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        commands.processListHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
      it('ignores more than one activation requests', async function() {
        let timesShow = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keypress'))
        await wait(10)
        expect(timesShow).toBe(1)
      })
      it('disposes itself on any commands other than known', async function() {
        let timesShow = 0
        let timesHide = 0
        commands.onListShow(function() {
          timesShow++
          return Promise.resolve(true)
        })
        commands.onListHide(function() {
          timesHide++
        })
        atom.keymaps.dispatchCommandEvent('intentions:show', editorView, getKeyboardEvent('keydown'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)

        atom.keymaps.emitter.emit('did-match-binding', { binding: { command: 'core:move-up' } })
        await wait(10)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)

        atom.keymaps.emitter.emit('did-match-binding', { binding: { command: 'core:move-down' } })
        await wait(10)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(0)

        atom.keymaps.emitter.emit('did-match-binding', { binding: { command: 'core:move-confirm' } })
        await wait(10)
        document.body.dispatchEvent(getKeyboardEvent('keyup'))
        await wait(10)
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)

        commands.processListHide()
        expect(timesShow).toBe(1)
        expect(timesHide).toBe(1)
      })
    })
  })
})
<|endoftext|>