<commit_before>const { LayerController } = require('../components/layerController');

var globalMap = {};
var imageUrl = '';
global.L = { DomEvent: {disableClickPropagation: jest.fn(), disableScrollPropagation: jest.fn()},
            imageOverlay: (raster, coordinates, settings) => ({setUrl: (url, coords, options) => {globalMap[url] = coords; imageUrl = url;},
                                                               addTo: (map) => {globalMap[raster] = coordinates},
                                                               remove: (map) => {delete globalMap[raster]},
                                                               bringToFront: () => {},
                                                               bringToBack: () => {},
                                                               _image: {}}),
            icon: (options) => {}};

const controller = require('../components/Controller.js');
jest.mock('../components/Controller.js', () => ({
    controllers: ({
        currentDomain: ({
            getValue: () => 1,
            subscribe: () => {}
        }),
        syncImageLoad: ({
            subscribe: (fun) => {},
            increment: () => {}
        }),
        currentTimestamp: ({
            getValue: () => '2020',
            subscribe: (fun) => {}
        }),
    }),

}));

const util = require('../util.js');
jest.mock('../util.js', () => ({
    simVars: ({
        currentSimulation: 'test',
        rasters: ({
            1: {
                '2020': {'raster': {raster: 'raster test', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'test colorbar raster'},
                    'overlay': {raster: 'overlay test', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'test colorbar overlay' }},
                '2021': {'raster': {raster: 'raster test current timestamp', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                    'overlay': {raster: 'overlay test', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            },
            2: {
                '2020': {'raster': {raster: 'raster test 2', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                    'overlay': {raster: 'overlay test 2', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            }
        }),
        rasterBase: 'testBase/',
        sortedTimestamps: ['2020'],
        overlayOrder: [],
        displayedColorbar: null,
        organization: 'SJSU',
        overlayList: ['overlay'],
        baseLayerDict: {},
    }),
    map: {
        addTo: jest.fn(),
        fitBounds: jest.fn(),
        on: jest.fn()
    },
    dragElement: jest.fn(),
    debounce: jest.fn()
}));

HTMLCanvasElement.prototype.getContext = () => {
    return {drawImage: jest.fn()}
};

describe('Tests for adding layers to menu and selecting layers', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should populate its raster and overlay layers correctly', () => {
        const rasterDict = layerController.rasterDict;
        const overlayDict = layerController.overlayDict;
        expect(Object.entries(rasterDict).length).toEqual(1);
        expect('raster' in rasterDict).toEqual(true);
        expect(Object.entries(overlayDict).length).toEqual(1);
        expect('overlay' in overlayDict).toEqual(true);
    });

    test('Layers should be correctly added to the map when selected', () => {
        layerController.handleOverlayadd('raster');
        expect('testBase/raster test' in globalMap).toEqual(true);
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
    });

    test('Layers should be correctly removed from the map when selected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect('testBase/raster test' in globalMap).toEqual(false);
    });

    test('Layer Controller should preserve previous selected layers when domain is switched on the same simulation', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
        expect('testBase/raster test 2' in globalMap).toEqual(true);
        expect('testBase/raster test' in globalMap).toEqual(false);
    });

    test('Layer Controller should clear selected layers when domain is switched to new simulation', () => {
        layerController.handleOverlayadd('raster');
        util.simVars.currentSimulation = 'new simulation';
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.length).toEqual(0);
        expect(globalMap).toEqual({});
    });

    test('Layer Controller should show the current_timestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect('testBase/raster test current timestamp' in globalMap).toEqual(true);
    });

    test('updateSlider should set img according to currentTimestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect(imageUrl).toEqual('testBase/raster test current timestamp');
    });
});

describe('Tests for adding layers with colorbars', () => {
    var layerController;

    beforeEach(async () => {
        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () => '2020';

        util.simVars.overlayOrder = [];
        util.simVars.displayedColorbar = '';

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should add any colorbars', () => {
        layerController.handleOverlayadd('raster');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbars when layer deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect(util.simVars.displayedColorbar).toEqual(null);
    });

    test('Layer Controller should put most recent selected colorbar on top', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        expect(util.simVars.displayedColorbar).toEqual('overlay');
    });

    test('Layer Controller should put last selected colorbar on top when another is deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        layerController.handleOverlayRemove('overlay');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbar when switching to a domain without one', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.displayedColorbar).toEqual(null);
    });
});

describe('Tests for preloading', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.rasters = ({
            1: {
                '2020': {'layer': {raster: 'rasterTest1/2020', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar1/2020'}},
                '2021': {'layer': {raster: 'rasterTest1/2021', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar1/2021'}}
            },
            2: {
                '2020': {'layer': {raster: 'rasterTest2/2020', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2020'}},
                '2020.5': {'layer': {raster: 'rasterTest2/2020.5', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2020.5'}},
                '2021': {'layer': {raster: 'rasterTest2/2021', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2021'}},
                '2021.5': {'layer': {raster: 'rasterTest2/2021.5', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2021.5'}}
            }
        })
        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn()
    });

    test('test test', () => {
        expect(true).toEqual(true);
    });
});<commit_msg>Refactors layerController test for readability<commit_after>const { LayerController } = require('../components/layerController');

var globalMap = {};
var imageUrl = '';
global.L = { DomEvent: {disableClickPropagation: jest.fn(), disableScrollPropagation: jest.fn()},
            imageOverlay: (raster, coordinates, settings) => ({setUrl: (url, coords, options) => {globalMap[url] = coords; imageUrl = url;},
                                                               addTo: (map) => {globalMap[raster] = coordinates},
                                                               remove: (map) => {delete globalMap[raster]},
                                                               bringToFront: () => {},
                                                               bringToBack: () => {},
                                                               _image: {}}),
            icon: (options) => {}};

const controller = require('../components/Controller.js');
jest.mock('../components/Controller.js', () => ({
    controllers: ({
        currentDomain: ({
            getValue: () => 1,
            subscribe: () => {}
        }),
        syncImageLoad: ({
            subscribe: (fun) => {},
            increment: () => {}
        }),
        currentTimestamp: ({
            getValue: () => '2020',
            subscribe: (fun) => {}
        }),
    }),

}));

const testCoords = ({0: [0,0], 1: [0, 1], 2: [1, 0], 3: [1, 1]});

const util = require('../util.js');
jest.mock('../util.js', () => ({
    simVars: ({
        currentSimulation: 'test',
        rasters: ({
            1: {
                '2020': {'raster': {raster: 'rasterTest', coords: testCoords, 'colorbar': 'testColorbar/raster'},
                    'overlay': {raster: 'overlayTest', coords: testCoords, 'colorbar': 'testColorbar/overlay' }},
                '2021': {'raster': {raster: 'rasterTest/currentTimestamp', coords: testCoords},
                    'overlay': {raster: 'overlayTest', coords: testCoords }}
            },
            2: {
                '2020': {'raster': {raster: 'rasterTest2', coords: testCoords },
                    'overlay': {raster: 'overlayTest2', coords: testCoords }}
            }
        }),
        rasterBase: 'testBase/',
        sortedTimestamps: ['2020'],
        overlayOrder: [],
        displayedColorbar: null,
        organization: 'SJSU',
        overlayList: ['overlay'],
        baseLayerDict: {},
    }),
    map: {
        addTo: jest.fn(),
        fitBounds: jest.fn(),
        on: jest.fn()
    },
    dragElement: jest.fn(),
    debounce: jest.fn()
}));

HTMLCanvasElement.prototype.getContext = () => {
    return {drawImage: jest.fn()}
};

describe('Tests for adding layers to menu and selecting layers', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should populate its raster and overlay layers correctly', () => {
        const rasterDict = layerController.rasterDict;
        const overlayDict = layerController.overlayDict;
        expect(Object.entries(rasterDict).length).toEqual(1);
        expect('raster' in rasterDict).toEqual(true);
        expect(Object.entries(overlayDict).length).toEqual(1);
        expect('overlay' in overlayDict).toEqual(true);
    });

    test('Layers should be correctly added to the map when selected', () => {
        layerController.handleOverlayadd('raster');
        expect('testBase/rasterTest' in globalMap).toEqual(true);
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
    });

    test('Layers should be correctly removed from the map when selected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect('testBase/rasterTest' in globalMap).toEqual(false);
    });

    test('Layer Controller should preserve previous selected layers when domain is switched on the same simulation', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
        expect('testBase/rasterTest2' in globalMap).toEqual(true);
        expect('testBase/rasterTest' in globalMap).toEqual(false);
    });

    test('Layer Controller should clear selected layers when domain is switched to new simulation', () => {
        layerController.handleOverlayadd('raster');
        util.simVars.currentSimulation = 'new simulation';
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.length).toEqual(0);
        expect(globalMap).toEqual({});
    });

    test('Layer Controller should show the current_timestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect('testBase/rasterTest/currentTimestamp' in globalMap).toEqual(true);
    });

    test('updateSlider should set img according to currentTimestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect(imageUrl).toEqual('testBase/rasterTest/currentTimestamp');
    });
});

describe('Tests for adding layers with colorbars', () => {
    var layerController;

    beforeEach(async () => {
        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () => '2020';

        util.simVars.overlayOrder = [];
        util.simVars.displayedColorbar = '';

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should add any colorbars', () => {
        layerController.handleOverlayadd('raster');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbars when layer deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect(util.simVars.displayedColorbar).toEqual(null);
    });

    test('Layer Controller should put most recent selected colorbar on top', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        expect(util.simVars.displayedColorbar).toEqual('overlay');
    });

    test('Layer Controller should put last selected colorbar on top when another is deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        layerController.handleOverlayRemove('overlay');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbar when switching to a domain without one', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.displayedColorbar).toEqual(null);
    });
});

describe('Tests for preloading', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.rasters = ({
            1: {
                '2020': {'layer': {raster: 'rasterTest1/2020', coords: testCoords, 'colorbar': 'colorbar1/2020'}},
                '2021': {'layer': {raster: 'rasterTest1/2021', coords: testCoords, 'colorbar': 'colorbar1/2021'}}
            },
            2: {
                '2020': {'layer': {raster: 'rasterTest2/2020', coords: testCoords, 'colorbar': 'colorbar2/2020'}},
                '2020.5': {'layer': {raster: 'rasterTest2/2020.5', coords: testCoords, 'colorbar': 'colorbar2/2020.5'}},
                '2021': {'layer': {raster: 'rasterTest2/2021', coords: testCoords, 'colorbar': 'colorbar2/2021'}},
                '2021.5': {'layer': {raster: 'rasterTest2/2021.5', coords: testCoords, 'colorbar': 'colorbar2/2021.5'}}
            }
        })
        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn()
    });

    test('test test', () => {
        expect(true).toEqual(true);
    });
});<|endoftext|>


<commit_before>PER_PAGE = 50;

var authorTemplate = Handlebars.compile($('#timeline-author-template').html());
function formatAuthor(author) {
    var login = author.login;
    var avatarURL = author.avatar_url;
    var githubURL = 'http://github.com/' + login;

    return authorTemplate({
        login: login,
        avatarURL: avatarURL,
        githubURL: githubURL
    });
}

function formatLink(href, text, title) {
    if (title) {
        return '' + text + '';
    }
    return '' + text + '';
}

function formatIssue(issue) {
    return formatLink(issue.html_url, '#' + issue.number, issue.title);
}

var TIMELINE_MAPPING = {
    'CommitCommentEvent': {
        action: function(e) {
            return "commented on";
        },
        object: function(e) {
            var url = e.payload.comment.html_url;
            url = url.substring(0, url.lastIndexOf('#'));

            var sha = url.substring(url.lastIndexOf('/') + 1);
            return formatLink(url, sha.substring(0, 7));
        },
        link: function(e) {
            return e.payload.comment.html_url;
        }
    },
    'CreateEvent': {
        action: function(e) {
            var s = "created";
            if (e.payload.ref_type == 'branch') {
                return s + " branch";
            } else if (e.payload.ref_type == 'tag') {
                return s + " tag";
            }
            return s;
        },
        object: function(e) {
            return e.payload.ref;
        },
    },
    'DeleteEvent': {
        action: function(e) {
            var s = "deleted";
            if (e.payload.ref_type == 'branch') {
                return s + " branch";
            } else if (e.payload.ref_type == 'tag') {
                return s + " tag";
            }
            return s;
        },
        object: function(e) {
            return e.payload.ref;
        },
    },
    'ForkEvent': {
        action: function(e) {
            return "forked to";
        },
        object: function(e) {
            var name = e.payload.forkee.full_name;
            var url = e.payload.forkee.html_url;
            return formatLink(url, name);
        }
    },
    'GollumEvent': {
        action: function(e) {
            var page = e.payload.pages[0];
            return page.action;
        },
        object: function(e) {
            var page = e.payload.pages[0];
            return "wiki page " + formatLink(page.html_url, page.page_name);
        }
    },
    'IssueCommentEvent': {
        action: function(e) {
            return "commented on";
        },
        object: function(e) {
            return formatIssue(e.payload.issue);
        },
        link: function(e) {
            return e.payload.comment.html_url;
        }
    },
    'IssuesEvent': {
        action: function(e) {
            return e.payload.action;
        },
        object: function(e) {
            return formatIssue(e.payload.issue);
        }
    },
    'MemberEvent': {
        action: function(e) {
            return "added";
        },
        object: function(e) {
            var user = e.payload.member;
            return formatLink(user.html_url, user.login) + " as a collaborator";
        }
    },
    'PublicEvent': {
        action: function(e) {
            return "open sourced";
        },
        object: function(e) {
            return "the repository";
        }
    },
    'PullRequestEvent': {
        action: function(e) {
            return e.payload.action;
        },
        object: function(e) {
            var pullReq = e.payload.pull_request;
            return "pull request " + formatIssue(pullReq);
        }
    },
    'PullRequestReviewCommentEvent': {
        action: function(e) {
            return "reviewed";
        },
        object: function(e) {
            var url = e.payload.comment.pull_request_url;
            var number = url.substring(url.lastIndexOf('/') + 1);
            var htmlURL = e.payload.comment.html_url;
            var pullReqURL = htmlURL.substring(0, htmlURL.lastIndexOf('#'));
            return "pull request " + makeLink(pullReqURL, '#' + number);
        },
        link: function(e) {
            return e.payload.comment.html_url;
        }
    },
    'PushEvent': {
        action: function(e) {
            return "pushed";
        },
        object: function(e) {
            var count = e.payload.size;
            return count + " commits";
        },
        link: function(e) {
            var head = e.payload.head;
            var repo = e.repo.name;
            var url = 'http://github.com/' + repo + '/commit/' + head;
            return url;
        }
    },
    'WatchEvent': {
        action: function(e) {
            return "starred";
        },
        object: function(e) {
            return "the repository";
        }
    },
    'EndOfTimeline': {
        action: function (e) {
            return "No more events available";
        },
        object: function (e) {
            return;
        }
    }
};

function populateTimeline(count, starting_from) {
    var $timeline = $('#timeline');
    var template = Handlebars.compile($('#timeline-item-template').html());
    var $loading = $('#timeline-loading');

    $.get(API_BASE + '/recent_events',
          {count: count, starting_from: starting_from})
          .success(function(data) {
              var fragment = document.createDocumentFragment();
              data.data.forEach(function(e) {
                  mapping = TIMELINE_MAPPING[e.type];
                  if (!mapping) {
                      return;
                  }
                  context = {
                      author: formatAuthor(e.actor),
                      action: mapping.action(e),
                      object: mapping.object(e),
                      timestamp: moment(e.created_at).fromNow()
                  };
                  if (mapping.link) {
                      context.link = mapping.link(e);
                  }
                  var $item = $(template(context));
                  fragment.appendChild($item[0]);
              });
              $(fragment).insertBefore($loading);

              if (!data.data.length) {
                  mapping = TIMELINE_MAPPING['EndOfTimeline'];
                  context = {
                      author: "Sorry!",
                      action: mapping.action(),
                      object: mapping.object(),
                      timestamp: ""
                  }
                  var $item = $(template(context));
                  $loading.remove();
                  $timeline.append($item);
                  $('#tab-1').off('scroll');
              }
          });

    if (!starting_from) {
        $('#tab-1').on('scroll', function () {
            if($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
                populateTimeline(PER_PAGE, $timeline.children('.timeline-item').length);
            }
        });
    }
}

populateTimeline(PER_PAGE, 0);
<commit_msg>sane defaults for populateTimeline<commit_after>PER_PAGE = 50;

var authorTemplate = Handlebars.compile($('#timeline-author-template').html());
function formatAuthor(author) {
    var login = author.login;
    var avatarURL = author.avatar_url;
    var githubURL = 'http://github.com/' + login;

    return authorTemplate({
        login: login,
        avatarURL: avatarURL,
        githubURL: githubURL
    });
}

function formatLink(href, text, title) {
    if (title) {
        return '' + text + '';
    }
    return '' + text + '';
}

function formatIssue(issue) {
    return formatLink(issue.html_url, '#' + issue.number, issue.title);
}

var TIMELINE_MAPPING = {
    'CommitCommentEvent': {
        action: function(e) {
            return "commented on";
        },
        object: function(e) {
            var url = e.payload.comment.html_url;
            url = url.substring(0, url.lastIndexOf('#'));

            var sha = url.substring(url.lastIndexOf('/') + 1);
            return formatLink(url, sha.substring(0, 7));
        },
        link: function(e) {
            return e.payload.comment.html_url;
        }
    },
    'CreateEvent': {
        action: function(e) {
            var s = "created";
            if (e.payload.ref_type == 'branch') {
                return s + " branch";
            } else if (e.payload.ref_type == 'tag') {
                return s + " tag";
            }
            return s;
        },
        object: function(e) {
            return e.payload.ref;
        },
    },
    'DeleteEvent': {
        action: function(e) {
            var s = "deleted";
            if (e.payload.ref_type == 'branch') {
                return s + " branch";
            } else if (e.payload.ref_type == 'tag') {
                return s + " tag";
            }
            return s;
        },
        object: function(e) {
            return e.payload.ref;
        },
    },
    'ForkEvent': {
        action: function(e) {
            return "forked to";
        },
        object: function(e) {
            var name = e.payload.forkee.full_name;
            var url = e.payload.forkee.html_url;
            return formatLink(url, name);
        }
    },
    'GollumEvent': {
        action: function(e) {
            var page = e.payload.pages[0];
            return page.action;
        },
        object: function(e) {
            var page = e.payload.pages[0];
            return "wiki page " + formatLink(page.html_url, page.page_name);
        }
    },
    'IssueCommentEvent': {
        action: function(e) {
            return "commented on";
        },
        object: function(e) {
            return formatIssue(e.payload.issue);
        },
        link: function(e) {
            return e.payload.comment.html_url;
        }
    },
    'IssuesEvent': {
        action: function(e) {
            return e.payload.action;
        },
        object: function(e) {
            return formatIssue(e.payload.issue);
        }
    },
    'MemberEvent': {
        action: function(e) {
            return "added";
        },
        object: function(e) {
            var user = e.payload.member;
            return formatLink(user.html_url, user.login) + " as a collaborator";
        }
    },
    'PublicEvent': {
        action: function(e) {
            return "open sourced";
        },
        object: function(e) {
            return "the repository";
        }
    },
    'PullRequestEvent': {
        action: function(e) {
            return e.payload.action;
        },
        object: function(e) {
            var pullReq = e.payload.pull_request;
            return "pull request " + formatIssue(pullReq);
        }
    },
    'PullRequestReviewCommentEvent': {
        action: function(e) {
            return "reviewed";
        },
        object: function(e) {
            var url = e.payload.comment.pull_request_url;
            var number = url.substring(url.lastIndexOf('/') + 1);
            var htmlURL = e.payload.comment.html_url;
            var pullReqURL = htmlURL.substring(0, htmlURL.lastIndexOf('#'));
            return "pull request " + makeLink(pullReqURL, '#' + number);
        },
        link: function(e) {
            return e.payload.comment.html_url;
        }
    },
    'PushEvent': {
        action: function(e) {
            return "pushed";
        },
        object: function(e) {
            var count = e.payload.size;
            return count + " commits";
        },
        link: function(e) {
            var head = e.payload.head;
            var repo = e.repo.name;
            var url = 'http://github.com/' + repo + '/commit/' + head;
            return url;
        }
    },
    'WatchEvent': {
        action: function(e) {
            return "starred";
        },
        object: function(e) {
            return "the repository";
        }
    },
    'EndOfTimeline': {
        action: function (e) {
            return "No more events available";
        },
        object: function (e) {
            return;
        }
    }
};

function populateTimeline(count, starting_from) {
    var $timeline = $('#timeline');
    var template = Handlebars.compile($('#timeline-item-template').html());
    var $loading = $('#timeline-loading');

    // if we don't have a specified index, don't do anythin
    if (API_BASE.indexOf('undefined/undefined') >= 0) {
        return;
    }

    if (!count) {
        count = PER_PAGE;
    }
    if (!starting_from) {
        starting_from = 0;
    }

    $.get(API_BASE + '/recent_events',
          {count: count, starting_from: starting_from})
          .success(function(data) {
              var fragment = document.createDocumentFragment();
              data.data.forEach(function(e) {
                  mapping = TIMELINE_MAPPING[e.type];
                  if (!mapping) {
                      return;
                  }
                  context = {
                      author: formatAuthor(e.actor),
                      action: mapping.action(e),
                      object: mapping.object(e),
                      timestamp: moment(e.created_at).fromNow()
                  };
                  if (mapping.link) {
                      context.link = mapping.link(e);
                  }
                  var $item = $(template(context));
                  fragment.appendChild($item[0]);
              });
              $(fragment).insertBefore($loading);

              if (!data.data.length) {
                  mapping = TIMELINE_MAPPING['EndOfTimeline'];
                  context = {
                      author: "Sorry!",
                      action: mapping.action(),
                      object: mapping.object(),
                      timestamp: ""
                  }
                  var $item = $(template(context));
                  $loading.remove();
                  $timeline.append($item);
                  $('#tab-1').off('scroll');
              }
          });

    if (!starting_from) {
        $('#tab-1').on('scroll', function () {
            if($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
                populateTimeline(PER_PAGE, $timeline.children('.timeline-item').length);
            }
        });
    }
}

populateTimeline();
<|endoftext|>


<commit_before>'use strict';
/*global angular:false */

angular.module('argus.controllers.alerts.detail', ['ngResource'])
.controller('AlertsDetail', ['$q','$scope', '$routeParams', '$location', 'growl', 'Alerts', 'Triggers', 'Notifications', 'History', 'TriggersMap', 'JobExecutionDetails', '$sessionStorage', 'Auth',
	function ($q, $scope, $routeParams, $location, growl, Alerts, Triggers, Notifications, History, TriggersMap, JobExecutionDetails, $sessionStorage, Auth) {
		$scope.alertNotEditable = true;
		$scope.isAlertDirty = function () {
			return !angular.equals($scope.alert, $scope.unmodifiedAlert);
		};

		$scope.isTriggerDirty = function () {
			return !angular.equals($scope.triggers, $scope.unmodifiedTriggers);
		};

		$scope.isNotificationDirty = function () {
			return !angular.equals($scope.notifications, $scope.unmodifiedNotifications);
		};

		$scope.updateAlert = function () {
			if ($scope.isAlertDirty()) {
				var alert = $scope.alert;

				Alerts.update({alertId: alert.id}, alert, function () {
					$scope.unmodifiedAlert = angular.copy(alert);
					growl.success(('Updated "') + alert.name + '"');
					$scope.fetchHistory();
					$scope.fetchJobExecutionDetails();
					// remove existing session storage for update
					if ($sessionStorage.alerts !== undefined) {
						delete $sessionStorage.alerts.cachedData;
						$sessionStorage.alerts.emptyData = true;
					}
				}, function () {
					growl.error('Failed to update "' + alert.name + '"');
				});
			}
		};

		$scope.updateTriggers = function () {
			if ($scope.isTriggerDirty()) {
				var triggers = $scope.triggers;
				for (var i = 0; i < triggers.length; i++) {
					$scope.updateTrigger(triggers[i]);
				}
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
			}
		};

		$scope.updateTrigger = function (trigger) {
			var toUpdate = $scope.unmodifiedTriggers.filter(function (element) {
				return element.id === trigger.id;
			});

			if (toUpdate.length === 1 && !angular.equals(toUpdate[0], trigger)) {
				Triggers.update({alertId: trigger.alertId, triggerId: trigger.id}, trigger, function () {
					$scope.unmodifiedTriggers.filter(function (element) {
						if (element.id === trigger.id) {
							angular.copy(trigger, element);
							growl.success('Updated trigger "' + trigger.id + '".');
						}
					});
				}, function () {
					growl.error('Failed to update "' + trigger.name + '"');
				});
			}
		};

		$scope.updateNotifications = function () {
			if ($scope.isNotificationDirty()) {
				var notifications = $scope.notifications;
				for (var i = 0; i < notifications.length; i++) {
					$scope.updateNotification(notifications[i]);
				}
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
			}
		};

		$scope.updateNotification = function (notification) {
			var toUpdate = $scope.unmodifiedNotifications.filter(function (element) {
				return element.id === notification.id;
			});

			if (toUpdate.length === 1 && !angular.equals(toUpdate[0], notification)) {
				Notifications.update({alertId: notification.alertId, notificationId: notification.id}, notification, function () {
					$scope.unmodifiedNotifications.filter(function (element) {
						if (element.id === notification.id) {
							angular.copy(notification, element);
							growl.success('Updated notification "' + notification.id + '".');
						}
					});
					$scope.mapTriggers(notification);
				}, function () {
					growl.error('Failed to update "' + notification.name + '"');
				});
			}
		};

		// Restore the unmodified version.
		$scope.resetTriggers = function () {
			$scope.triggers = angular.copy($scope.unmodifiedTriggers);
		};

		$scope.resetAlert = function () {
			$scope.alert = angular.copy($scope.unmodifiedAlert);
		};

		// Restore the unmodified version.
		$scope.resetNotifications = function () {
			$scope.notifications = angular.copy($scope.unmodifiedNotifications);
		};

		$scope.addTrigger = function () {
			var trigger = {
				name: 'new-trigger-' + Date.now(),
				type: 'GREATER_THAN',
				threshold: 0,
				secondaryThreshold: 0,
				inertia: 0,
				alertId: $scope.alert.id
			};

			Triggers.save({alertId: $scope.alert.id}, trigger, function (result) {
				angular.copy(result, $scope.triggers);
				$scope.unmodifiedTriggers = angular.copy($scope.triggers);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Created "' + trigger.name + '"');
			}, function () {
				growl.error('Failed to create "' + trigger.name + '"');
			});
		};

		$scope.addNotification = function () {
			var notification = {
				name: 'new-notification-' + Date.now(),
				notifierName: 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier',
				subscriptions: [],
				metricsToAnnotate: [],
				cooldownPeriod: 0,
				sractionable:false,
				severityLevel:5,
				alertId: $scope.alert.id
			};

			Notifications.save({alertId: $scope.alert.id}, notification, function (result) {
				angular.copy(result, $scope.notifications);
				$scope.unmodifiedNotifications = angular.copy($scope.notifications);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Created "' + notification.name + '"');
			}, function () {
				growl.error('Failed to create "' + notification.name + '"');
			});
		};

		$scope.removeTrigger = function (trigger) {
			Triggers.delete({alertId: trigger.alertId, triggerId: trigger.id}, function () {
				$scope.triggers = $scope.triggers.filter(function (element) {
					return element.id !== trigger.id;
				});
				$scope.unmodifiedTriggers = angular.copy($scope.triggers);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Deleted "' + trigger.name + '"');
			}, function () {
				growl.error('Failed to delete "' + trigger.name + '"');
			});
		};

		$scope.removeNotification = function (notification) {
			Notifications.delete({alertId: notification.alertId, notificationId: notification.id}, function () {
				$scope.notifications = $scope.notifications.filter(function (element) {
					return element.id !== notification.id;
				});
				$scope.unmodifiedNotifications = angular.copy($scope.notifications);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Deleted "' + notification.name + '"');
			}, function () {
				growl.error('Failed to delete "' + notification.name + '"');
			});
		};

		$scope.mapTriggers = function (notification) {
			var promises = $scope.unmodifiedTriggers.map(function(trigger){
				return TriggersMap.unmap({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger.id}).$promise;
			});

			$q.all(promises).finally(function(){
				for (var i = 0; i < notification.triggersIds.length; i++) {
					var trigger = notification.triggersIds[i];
					TriggersMap.map({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger}, null);
				}
			});

			$scope.fetchHistory();
			$scope.fetchJobExecutionDetails();
		};

		$scope.isTabSelected = function (tab) {
			return $scope.selectedTab === tab;
		};

		$scope.selectTab = function (tab) {
			$scope.selectedTab = tab;
		};

		$scope.fetchHistory = function() {
			$scope.historyLoaded = false;
			History.query({id: $scope.alertId}, function (history) {
				$scope.history = history;
				$scope.historyLoaded = true;
			}, function () {
				growl.error('Failed to get history for alert "' + $scope.alertId + '"');
				$scope.historyLoaded = true;
			});
		};

		$scope.fetchJobExecutionDetails = function() {
			JobExecutionDetails.query({id: $scope.alertId}, function (jobExecutionDetails) {
				$scope.jobExecutionDetails = jobExecutionDetails;
				$scope.jobExecutionDetailsError='';
			}, function (error) {
				if(error.status==404){
					$scope.jobExecutionDetailsError = ' No alert evaluation details found.';
				}else if(error.status==403){
					$scope.jobExecutionDetailsError = 'You are not authorized to view this data.';
				}
				else {
					$scope.jobExecutionDetailsError = error.statusText;
					growl.error('Failed to get the job execution details "' + $scope.jobId + '"');
				}
			});
		};

		$scope.triggerTypes = [
			{label: '=', value: 'EQUAL'},
			{label: '!=', value: 'NOT_EQUAL'},
			{label: '>', value: 'GREATER_THAN'},
			{label: '<', value: 'LESS_THAN'},
			{label: '>=', value: 'GREATER_THAN_OR_EQ'},
			{label: '<=', value: 'LESS_THAN_OR_EQ'},
			{label: '<>', value: 'BETWEEN'},
			{label: '><', value: 'NOT_BETWEEN'},
			{label: 'no data', value: 'NO_DATA'}
		];

		$scope.notificationTypes = [
			{label: 'Callback', value: 'com.salesforce.dva.argus.service.alert.notifier.CallbackNotifier'},
			{label: 'Audit', value: 'com.salesforce.dva.argus.service.alert.notifier.AuditNotifier'},
			{label: 'Mail', value: 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier'},
			{label: 'GOC++', value: 'com.salesforce.dva.argus.service.alert.notifier.GOCNotifier'},
			{label: 'GUS', value: 'com.salesforce.dva.argus.service.alert.notifier.GusNotifier'},
			{label: 'Refocus', value: 'com.salesforce.dva.argus.service.alert.notifier.RefocusNotifier'}
		];

		$scope.getTriggerIds = function () {
			var ids = [];
			var triggers = $scope.unmodifiedTriggers;
			for (var i = 0; i < triggers.length; i++) {
				ids.push(triggers[i].id);
			}
			return ids;
		};

		$scope.alertId = $routeParams.alertId;
		$scope.triggers = [];
		$scope.notifications = [];
		$scope.unmodifiedTriggers = [];
		$scope.unmodifiedNotifications = [];

		if ($scope.alertId > 0) {
			Alerts.get({alertId: $scope.alertId}, function (alert) {
				$scope.alert = alert;
				$scope.alertNotEditable = Auth.isDisabled(alert);
				$scope.unmodifiedAlert = angular.copy(alert);
			}, function () {
				growl.error('Failed to get alert "' + $scope.alertId + '"');
				$location.path('/alerts');
			});

			Triggers.query({alertId: $scope.alertId}, function (triggers) {
				$scope.triggers = triggers;
				$scope.unmodifiedTriggers = angular.copy(triggers);
			}, function () {
				growl.error('Failed to get triggers for alert "' + $scope.alertId + '"');
			});

			Notifications.query({alertId: $scope.alertId}, function (notifications) {
				$scope.notifications = notifications;
				$scope.unmodifiedNotifications = angular.copy(notifications);
			}, function () {
				growl.error('Failed to get notifications for alert "' + $scope.alertId + '"');
			});
			$scope.fetchHistory();
			$scope.fetchJobExecutionDetails();
		} else {
			growl.error('Failed to get alert "' + $routeParams.alertId + '"');
			$location.path('alerts');
		}
		$scope.selectedTab = 1;

		$scope.resetAlert();
		$scope.resetTriggers();
		$scope.resetNotifications();
	}]);
<commit_msg>remove Refocus notifier from UI<commit_after>'use strict';
/*global angular:false */

angular.module('argus.controllers.alerts.detail', ['ngResource'])
.controller('AlertsDetail', ['$q','$scope', '$routeParams', '$location', 'growl', 'Alerts', 'Triggers', 'Notifications', 'History', 'TriggersMap', 'JobExecutionDetails', '$sessionStorage', 'Auth',
	function ($q, $scope, $routeParams, $location, growl, Alerts, Triggers, Notifications, History, TriggersMap, JobExecutionDetails, $sessionStorage, Auth) {
		$scope.alertNotEditable = true;
		$scope.isAlertDirty = function () {
			return !angular.equals($scope.alert, $scope.unmodifiedAlert);
		};

		$scope.isTriggerDirty = function () {
			return !angular.equals($scope.triggers, $scope.unmodifiedTriggers);
		};

		$scope.isNotificationDirty = function () {
			return !angular.equals($scope.notifications, $scope.unmodifiedNotifications);
		};

		$scope.updateAlert = function () {
			if ($scope.isAlertDirty()) {
				var alert = $scope.alert;

				Alerts.update({alertId: alert.id}, alert, function () {
					$scope.unmodifiedAlert = angular.copy(alert);
					growl.success(('Updated "') + alert.name + '"');
					$scope.fetchHistory();
					$scope.fetchJobExecutionDetails();
					// remove existing session storage for update
					if ($sessionStorage.alerts !== undefined) {
						delete $sessionStorage.alerts.cachedData;
						$sessionStorage.alerts.emptyData = true;
					}
				}, function () {
					growl.error('Failed to update "' + alert.name + '"');
				});
			}
		};

		$scope.updateTriggers = function () {
			if ($scope.isTriggerDirty()) {
				var triggers = $scope.triggers;
				for (var i = 0; i < triggers.length; i++) {
					$scope.updateTrigger(triggers[i]);
				}
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
			}
		};

		$scope.updateTrigger = function (trigger) {
			var toUpdate = $scope.unmodifiedTriggers.filter(function (element) {
				return element.id === trigger.id;
			});

			if (toUpdate.length === 1 && !angular.equals(toUpdate[0], trigger)) {
				Triggers.update({alertId: trigger.alertId, triggerId: trigger.id}, trigger, function () {
					$scope.unmodifiedTriggers.filter(function (element) {
						if (element.id === trigger.id) {
							angular.copy(trigger, element);
							growl.success('Updated trigger "' + trigger.id + '".');
						}
					});
				}, function () {
					growl.error('Failed to update "' + trigger.name + '"');
				});
			}
		};

		$scope.updateNotifications = function () {
			if ($scope.isNotificationDirty()) {
				var notifications = $scope.notifications;
				for (var i = 0; i < notifications.length; i++) {
					$scope.updateNotification(notifications[i]);
				}
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
			}
		};

		$scope.updateNotification = function (notification) {
			var toUpdate = $scope.unmodifiedNotifications.filter(function (element) {
				return element.id === notification.id;
			});

			if (toUpdate.length === 1 && !angular.equals(toUpdate[0], notification)) {
				Notifications.update({alertId: notification.alertId, notificationId: notification.id}, notification, function () {
					$scope.unmodifiedNotifications.filter(function (element) {
						if (element.id === notification.id) {
							angular.copy(notification, element);
							growl.success('Updated notification "' + notification.id + '".');
						}
					});
					$scope.mapTriggers(notification);
				}, function () {
					growl.error('Failed to update "' + notification.name + '"');
				});
			}
		};

		// Restore the unmodified version.
		$scope.resetTriggers = function () {
			$scope.triggers = angular.copy($scope.unmodifiedTriggers);
		};

		$scope.resetAlert = function () {
			$scope.alert = angular.copy($scope.unmodifiedAlert);
		};

		// Restore the unmodified version.
		$scope.resetNotifications = function () {
			$scope.notifications = angular.copy($scope.unmodifiedNotifications);
		};

		$scope.addTrigger = function () {
			var trigger = {
				name: 'new-trigger-' + Date.now(),
				type: 'GREATER_THAN',
				threshold: 0,
				secondaryThreshold: 0,
				inertia: 0,
				alertId: $scope.alert.id
			};

			Triggers.save({alertId: $scope.alert.id}, trigger, function (result) {
				angular.copy(result, $scope.triggers);
				$scope.unmodifiedTriggers = angular.copy($scope.triggers);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Created "' + trigger.name + '"');
			}, function () {
				growl.error('Failed to create "' + trigger.name + '"');
			});
		};

		$scope.addNotification = function () {
			var notification = {
				name: 'new-notification-' + Date.now(),
				notifierName: 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier',
				subscriptions: [],
				metricsToAnnotate: [],
				cooldownPeriod: 0,
				sractionable:false,
				severityLevel:5,
				alertId: $scope.alert.id
			};

			Notifications.save({alertId: $scope.alert.id}, notification, function (result) {
				angular.copy(result, $scope.notifications);
				$scope.unmodifiedNotifications = angular.copy($scope.notifications);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Created "' + notification.name + '"');
			}, function () {
				growl.error('Failed to create "' + notification.name + '"');
			});
		};

		$scope.removeTrigger = function (trigger) {
			Triggers.delete({alertId: trigger.alertId, triggerId: trigger.id}, function () {
				$scope.triggers = $scope.triggers.filter(function (element) {
					return element.id !== trigger.id;
				});
				$scope.unmodifiedTriggers = angular.copy($scope.triggers);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Deleted "' + trigger.name + '"');
			}, function () {
				growl.error('Failed to delete "' + trigger.name + '"');
			});
		};

		$scope.removeNotification = function (notification) {
			Notifications.delete({alertId: notification.alertId, notificationId: notification.id}, function () {
				$scope.notifications = $scope.notifications.filter(function (element) {
					return element.id !== notification.id;
				});
				$scope.unmodifiedNotifications = angular.copy($scope.notifications);
				$scope.fetchHistory();
				$scope.fetchJobExecutionDetails();
				growl.success('Deleted "' + notification.name + '"');
			}, function () {
				growl.error('Failed to delete "' + notification.name + '"');
			});
		};

		$scope.mapTriggers = function (notification) {
			var promises = $scope.unmodifiedTriggers.map(function(trigger){
				return TriggersMap.unmap({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger.id}).$promise;
			});

			$q.all(promises).finally(function(){
				for (var i = 0; i < notification.triggersIds.length; i++) {
					var trigger = notification.triggersIds[i];
					TriggersMap.map({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger}, null);
				}
			});

			$scope.fetchHistory();
			$scope.fetchJobExecutionDetails();
		};

		$scope.isTabSelected = function (tab) {
			return $scope.selectedTab === tab;
		};

		$scope.selectTab = function (tab) {
			$scope.selectedTab = tab;
		};

		$scope.fetchHistory = function() {
			$scope.historyLoaded = false;
			History.query({id: $scope.alertId}, function (history) {
				$scope.history = history;
				$scope.historyLoaded = true;
			}, function () {
				growl.error('Failed to get history for alert "' + $scope.alertId + '"');
				$scope.historyLoaded = true;
			});
		};

		$scope.fetchJobExecutionDetails = function() {
			JobExecutionDetails.query({id: $scope.alertId}, function (jobExecutionDetails) {
				$scope.jobExecutionDetails = jobExecutionDetails;
				$scope.jobExecutionDetailsError='';
			}, function (error) {
				if(error.status==404){
					$scope.jobExecutionDetailsError = ' No alert evaluation details found.';
				}else if(error.status==403){
					$scope.jobExecutionDetailsError = 'You are not authorized to view this data.';
				}
				else {
					$scope.jobExecutionDetailsError = error.statusText;
					growl.error('Failed to get the job execution details "' + $scope.jobId + '"');
				}
			});
		};

		$scope.triggerTypes = [
			{label: '=', value: 'EQUAL'},
			{label: '!=', value: 'NOT_EQUAL'},
			{label: '>', value: 'GREATER_THAN'},
			{label: '<', value: 'LESS_THAN'},
			{label: '>=', value: 'GREATER_THAN_OR_EQ'},
			{label: '<=', value: 'LESS_THAN_OR_EQ'},
			{label: '<>', value: 'BETWEEN'},
			{label: '><', value: 'NOT_BETWEEN'},
			{label: 'no data', value: 'NO_DATA'}
		];

		$scope.notificationTypes = [
			{label: 'Callback', value: 'com.salesforce.dva.argus.service.alert.notifier.CallbackNotifier'},
			{label: 'Audit', value: 'com.salesforce.dva.argus.service.alert.notifier.AuditNotifier'},
			{label: 'Mail', value: 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier'},
			{label: 'GOC++', value: 'com.salesforce.dva.argus.service.alert.notifier.GOCNotifier'},
			{label: 'GUS', value: 'com.salesforce.dva.argus.service.alert.notifier.GusNotifier'}
			//{label: 'Refocus', value: 'com.salesforce.dva.argus.service.alert.notifier.RefocusNotifier'}
		];

		$scope.getTriggerIds = function () {
			var ids = [];
			var triggers = $scope.unmodifiedTriggers;
			for (var i = 0; i < triggers.length; i++) {
				ids.push(triggers[i].id);
			}
			return ids;
		};

		$scope.alertId = $routeParams.alertId;
		$scope.triggers = [];
		$scope.notifications = [];
		$scope.unmodifiedTriggers = [];
		$scope.unmodifiedNotifications = [];

		if ($scope.alertId > 0) {
			Alerts.get({alertId: $scope.alertId}, function (alert) {
				$scope.alert = alert;
				$scope.alertNotEditable = Auth.isDisabled(alert);
				$scope.unmodifiedAlert = angular.copy(alert);
			}, function () {
				growl.error('Failed to get alert "' + $scope.alertId + '"');
				$location.path('/alerts');
			});

			Triggers.query({alertId: $scope.alertId}, function (triggers) {
				$scope.triggers = triggers;
				$scope.unmodifiedTriggers = angular.copy(triggers);
			}, function () {
				growl.error('Failed to get triggers for alert "' + $scope.alertId + '"');
			});

			Notifications.query({alertId: $scope.alertId}, function (notifications) {
				$scope.notifications = notifications;
				$scope.unmodifiedNotifications = angular.copy(notifications);
			}, function () {
				growl.error('Failed to get notifications for alert "' + $scope.alertId + '"');
			});
			$scope.fetchHistory();
			$scope.fetchJobExecutionDetails();
		} else {
			growl.error('Failed to get alert "' + $routeParams.alertId + '"');
			$location.path('alerts');
		}
		$scope.selectedTab = 1;

		$scope.resetAlert();
		$scope.resetTriggers();
		$scope.resetNotifications();
	}]);
<|endoftext|>


<commit_before>$.fn.adamSlideout = function($slideout) {
	var pageX;
	var originX;
	var slideoutWidth;
	var $panel = $(this);

	$('.js-slideout-toggle').on("click, tapend", function(){
		$('body').toggleClass('slideout-open');
	});

	$('#panel')[0].addEventListener('touchstart', function(event) {
		originX = event.changedTouches[0].pageX - $panel[0].getBoundingClientRect().left;
	});

	$($panel)[0].addEventListener('touchmove', function(event) {
		var slideX;
		pageX 				= event.changedTouches[0].pageX;
		slideoutWidth = $slideout.width();

		if($(event.target).hasClass('slideout-disabled')){
			return false;
		}

		if(slideoutWidth === $('body').width()){ //Disable via. CSS
			return false;
		}

		$panel.addClass('sliding');

		slideX = pageX - originX;

		//Subtract current movement
		slideX = slideX;

		if(slideX < 0){
			slideX = 0;
		}

		if(slideX >= slideoutWidth){
			slideX = slideoutWidth;
		}

		$panel.css({
			MozTransition:		"transform 0",
			WebkitTransition:	"transform 0",
			msTransition:			"transform 0",
			transition:				"transform 0",
			MozTransform: 		"translate3d(" + slideX + "px, 0, 0)",
			WebkitTransform: 	"translate3d(" + slideX + "px, 0, 0)",
			msTransform: 			"translate3d(" + slideX + "px, 0, 0)",
			transform: 				"translate3d(" + slideX	 + "px, 0, 0)"
		});
	});

	$('#panel')[0].addEventListener('touchend', function(event) {

		if(slideoutWidth === $('body').width()){ //Disable via. CSS
			return false;
		}

		pageX = event.changedTouches[0].pageX;
		$panel.removeAttr('style');
		$panel.removeClass('sliding');
		if(pageX <= (slideoutWidth / 2)){
			$('body').removeClass('slideout-open');
		} else {
			$('body').addClass('slideout-open');
		}
	});

};
<commit_msg>Update adamSlideout.js<commit_after>$.fn.adamSlideout = function($slideout) {
	var pageX;
	var originX;
	var slideoutWidth;
	var $panel = $(this);

	$('.js-slideout-toggle').on("click, tapend", function(){
		$('body').toggleClass('slideout-open');
	});

	$('#panel')[0].addEventListener('touchstart', function(event) {
		originX = event.changedTouches[0].pageX - $panel[0].getBoundingClientRect().left;
	});

	$($panel)[0].addEventListener('touchmove', function(event) {
		var slideX;
		pageX 				= event.changedTouches[0].pageX;
		slideoutWidth = $slideout.width();

		if($(event.target).hasClass('slideout-disabled')){
			return false;
		}

		if(slideoutWidth === $('body').width()){ //Disable via. CSS
			return false;
		}

		$panel.addClass('sliding');

		slideX = pageX - originX;

		//Subtract current movement
		slideX = slideX;

		if(slideX < 0){
			slideX = 0;
		}

		if(slideX >= slideoutWidth){
			slideX = slideoutWidth;
		}

		$panel.css({
			MozTransition:		"transform 0",
			WebkitTransition:	"transform 0",
			msTransition:			"transform 0",
			transition:				"transform 0",
			MozTransform: 		"translate3d(" + slideX + "px, 0, 0)",
			WebkitTransform: 	"translate3d(" + slideX + "px, 0, 0)",
			msTransform: 			"translate3d(" + slideX + "px, 0, 0)",
			transform: 				"translate3d(" + slideX	 + "px, 0, 0)"
		});
	});

	$('#panel')[0].addEventListener('touchend', function(event) {

		if(slideoutWidth === $('body').width()){ //Disable via. CSS
			return false;
		}

		pageX = event.changedTouches[0].pageX;
		$panel.removeAttr('style');
		$panel.removeClass('sliding');
		if($panel[0].getBoundingClientRect().left <= (slideoutWidth / 2)){
			$('body').removeClass('slideout-open');
		} else {
			$('body').addClass('slideout-open');
		}
	});

};
<|endoftext|>


<commit_before>import React from 'react';
import {
  Divider,
  InputGroup,
  TextInput,
  Title,
  Button,
  ButtonVariant,
  Toolbar,
  ToolbarContent,
  ToolbarItem,
  EmptyState,
  EmptyStateVariant,
  EmptyStateIcon,
  EmptyStateBody,
  Tooltip,
  TooltipPosition
} from '@patternfly/react-core';
import * as icons from '@patternfly/react-icons';
import './icons.css';
import {
  Table,
  TableHeader,
  TableBody,
  TableVariant,
  sortable,
  SortByDirection
} from '@patternfly/react-table';
import { iconsData } from './icons';
import { saveAs } from 'file-saver';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/react-styles/css/components/Table/table';

export class IconsTable extends React.Component {
  state = {
    searchValue: '',
    columns: [
      'Icon',
      { title: 'Name', transforms: [sortable], props: { className: css(styles.modifiers.fitContent)} },
      'Style',
      { title: 'Type', transforms: [sortable] },
      { title: 'React', props: { className: css(styles.modifiers.fitContent)} },
      { title: 'Contextual usage', transforms: [sortable] }
    ],
    sortBy: {}
  };

  handleSearchChange = (checked, event) => {
    const searchValue = event.target.value;
    this.setState(() => ({
      searchValue
    }));
  };

  onSort = (_event, index, direction) => {
    this.setState({
      sortBy: {
        index,
        direction
      }
    });
  }

  onDownloadSvg = ({ currentTarget }) => {
    const domNode = currentTarget.cloneNode(true);
    domNode.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    domNode.setAttribute("width", "100%");
    domNode.setAttribute("height", "100%");
    const { outerHTML } = domNode;
    const preface = '<?xml version="1.0" standalone="no"?>\r\n';
    const name = currentTarget.parentElement.nextSibling.textContent;
    const filename = `${name}.svg`;

    const blob = new Blob([preface, outerHTML], {
      type: 'image/svg+xml;charset=utf-8'
    });

    saveAs(blob, filename);
  };

  render() {
    const { searchValue, columns, sortBy } = this.state;
    const { direction, index } = sortBy;
    const SearchIcon = icons.SearchIcon;
    const searchRE = new RegExp(searchValue, 'i');
    const iconRows = iconsData
      .map(({Style, Name, React_name: ReactName, Type, Contextual_usage}) => {
        const Icon = icons[ReactName];
        return {
          cells: [
            {
              title: <Tooltip content="Download SVG" position={TooltipPosition.bottom}><Icon onClick={this.onDownloadSvg} /></Tooltip>,
              props: { column: 'Icon' }
            },
            {
              title: Name,
              props: { column: 'Name' }
            },
            Style,
            {
              title: Type,
              props: { column: 'Type' }
            },
            ReactName,
            {
              title: Contextual_usage,
              props: { column: 'Contextual usage' }
            }
          ]
        }
      });

    let filteredRows = iconRows.filter(row => {
      return row.cells.some(cell => {
        const searchField = typeof cell.title === 'string'
          ? cell.title
          : cell;
        return searchRE.test(searchField);
      })
    })

    if (direction) {
      const sortedRows = filteredRows.sort((a, b) => {
        return a.cells[index].title  b.cells[index].title
            ? 1 : 0});
      filteredRows = direction === SortByDirection.asc ? sortedRows : sortedRows.reverse();
    }

    return (
      <React.Fragment>
        <Toolbar id="data-toolbar">
          <ToolbarContent>
            <ToolbarItem>
              <InputGroup>
                <TextInput
                  name="iconsSearch"
                  id="iconsSearch" type="search"
                  aria-label="Search icons"
                  placeholder="Search for any icon, attribute, or usage guideline"
                  value={searchValue}
                  onChange={this.handleSearchChange}
                />
                <Button variant={ButtonVariant.control} aria-label="search button for search input">
                  <SearchIcon />
                </Button>
              </InputGroup>
            </ToolbarItem>
            <ToolbarItem alignment={{ default: 'alignRight' }}>
              {filteredRows.length} items
            </ToolbarItem>
          </ToolbarContent>
        </Toolbar>
        <Divider />

          <TableHeader />
          <TableBody />

        {filteredRows.length === 0 && (
          <EmptyState variant={EmptyStateVariant.full}>
            <EmptyStateIcon icon={icons.SearchIcon}/>
            <Title headingLevel="h5" size="2xl">
              No results found for "{ searchValue }".
            </Title>
            <EmptyStateBody>
              We couldn't find any icons that matched your search. Try entering a new search term to find what you're looking for.
            </EmptyStateBody>
          </EmptyState>
        )}
      </React.Fragment>
    );
  }
}
<commit_msg>change to search empty state<commit_after>import React from 'react';
import {
  Divider,
  InputGroup,
  TextInput,
  Title,
  Button,
  ButtonVariant,
  Toolbar,
  ToolbarContent,
  ToolbarItem,
  EmptyState,
  EmptyStateVariant,
  EmptyStateIcon,
  EmptyStateBody,
  Tooltip,
  TooltipPosition
} from '@patternfly/react-core';
import * as icons from '@patternfly/react-icons';
import './icons.css';
import {
  Table,
  TableHeader,
  TableBody,
  TableVariant,
  sortable,
  SortByDirection
} from '@patternfly/react-table';
import { iconsData } from './icons';
import { saveAs } from 'file-saver';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/react-styles/css/components/Table/table';

export class IconsTable extends React.Component {
  state = {
    searchValue: '',
    columns: [
      'Icon',
      { title: 'Name', transforms: [sortable], props: { className: css(styles.modifiers.fitContent)} },
      'Style',
      { title: 'Type', transforms: [sortable] },
      { title: 'React', props: { className: css(styles.modifiers.fitContent)} },
      { title: 'Contextual usage', transforms: [sortable] }
    ],
    sortBy: {}
  };

  handleSearchChange = (checked, event) => {
    const searchValue = event.target.value;
    this.setState(() => ({
      searchValue
    }));
  };

  onSort = (_event, index, direction) => {
    this.setState({
      sortBy: {
        index,
        direction
      }
    });
  }

  onDownloadSvg = ({ currentTarget }) => {
    const domNode = currentTarget.cloneNode(true);
    domNode.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    domNode.setAttribute("width", "100%");
    domNode.setAttribute("height", "100%");
    const { outerHTML } = domNode;
    const preface = '<?xml version="1.0" standalone="no"?>\r\n';
    const name = currentTarget.parentElement.nextSibling.textContent;
    const filename = `${name}.svg`;

    const blob = new Blob([preface, outerHTML], {
      type: 'image/svg+xml;charset=utf-8'
    });

    saveAs(blob, filename);
  };

  render() {
    const { searchValue, columns, sortBy } = this.state;
    const { direction, index } = sortBy;
    const SearchIcon = icons.SearchIcon;
    const searchRE = new RegExp(searchValue, 'i');
    const iconRows = iconsData
      .map(({Style, Name, React_name: ReactName, Type, Contextual_usage}) => {
        const Icon = icons[ReactName];
        return {
          cells: [
            {
              title: <Tooltip content="Download SVG" position={TooltipPosition.bottom}><Icon onClick={this.onDownloadSvg} /></Tooltip>,
              props: { column: 'Icon' }
            },
            {
              title: Name,
              props: { column: 'Name' }
            },
            Style,
            {
              title: Type,
              props: { column: 'Type' }
            },
            ReactName,
            {
              title: Contextual_usage,
              props: { column: 'Contextual usage' }
            }
          ]
        }
      });

    let filteredRows = iconRows.filter(row => {
      return row.cells.some(cell => {
        const searchField = typeof cell.title === 'string'
          ? cell.title
          : cell;
        return searchRE.test(searchField);
      })
    })

    if (direction) {
      const sortedRows = filteredRows.sort((a, b) => {
        return a.cells[index].title  b.cells[index].title
            ? 1 : 0});
      filteredRows = direction === SortByDirection.asc ? sortedRows : sortedRows.reverse();
    }

    return (
      <React.Fragment>
        <Toolbar id="data-toolbar">
          <ToolbarContent>
            <ToolbarItem>
              <InputGroup>
                <TextInput
                  name="iconsSearch"
                  id="iconsSearch" type="search"
                  aria-label="Search icons"
                  placeholder="Search for any icon, attribute, or usage guideline"
                  value={searchValue}
                  onChange={this.handleSearchChange}
                />
                <Button variant={ButtonVariant.control} aria-label="search button for search input">
                  <SearchIcon />
                </Button>
              </InputGroup>
            </ToolbarItem>
            <ToolbarItem alignment={{ default: 'alignRight' }}>
              {filteredRows.length} items
            </ToolbarItem>
          </ToolbarContent>
        </Toolbar>
        <Divider />

          <TableHeader />
          <TableBody />

        {filteredRows.length === 0 && (
          <EmptyState variant={EmptyStateVariant.full}>
            <EmptyStateIcon icon={icons.SearchIcon}/>
            <Title headingLevel="h5" size="2xl">
              No results found for "{ searchValue }"
            </Title>
            <EmptyStateBody>
            We couldn't find any icons that matched your search. If none of the icons listed fit your use case, you may use any additional 'fa' icons within Font Awesome's free set.
            </EmptyStateBody>
          </EmptyState>
        )}
      </React.Fragment>
    );
  }
}
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Canvas = require('../node-canvas/lib/canvas')
  , canvas = new Canvas(320, 320)
  , ctx = canvas.getContext('2d')
  , fs = require('fs');

function getX(angle) {
  return -Math.sin(angle + Math.PI);
}
function getY(angle) {
  return Math.cos(angle + Math.PI);
}

function clock(ctx){
  var now = new Date();
  ctx.clearRect(0,0,320,320);

  ctx.save();
  ctx.translate(160,160);
  ctx.beginPath();
  ctx.lineWidth = 14;
  ctx.strokeStyle = '#325FA2';
  ctx.fillStyle = '#eeeeee';
  ctx.arc(0,0,142,0,Math.PI*2,true);
  ctx.stroke();
  ctx.fill();

  ctx.strokeStyle = '#000000';
  // Hour marks
  ctx.lineWidth = 8;
  for (var i=0;i<12;i++){
    var x = getX(Math.PI/6*i);
    var y = getY(Math.PI/6*i);
    ctx.beginPath();
    ctx.moveTo(x*100,y*100);
    ctx.lineTo(x*125,y*125);
    ctx.stroke();
  }

  // Minute marks
  ctx.lineWidth = 5;
  for (i=0;i<60;i++){
    if (i%5!=0) {
      var x = getX(Math.PI/30*i);
      var y = getY(Math.PI/30*i);
      ctx.beginPath();
      ctx.moveTo(x*117,y*117);
      ctx.lineTo(x*125,y*125);
      ctx.stroke();
    }
  }

  var sec = now.getSeconds();
  var min = now.getMinutes();
  var hr  = now.getHours();
  hr = hr>=12 ? hr-12 : hr;

  ctx.fillStyle = "black";

  // write Hours
  var x = getX(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
  var y = getY(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
  ctx.lineWidth = 14;
  ctx.beginPath();
  ctx.moveTo(x*-20,y*-20);
  ctx.lineTo(x*80,y*80);
  ctx.stroke();

  // write Minutes
  var x = getX((Math.PI/30)*min + (Math.PI/1800)*sec);
  var y = getY((Math.PI/30)*min + (Math.PI/1800)*sec);

  ctx.lineWidth = 10;
  ctx.beginPath();
  ctx.moveTo(x*-28,y*-28);
  ctx.lineTo(x*112,y*112);
  ctx.stroke();

  // Write seconds
  var x = getX(sec * Math.PI/30);
  var y = getY(sec * Math.PI/30);
  ctx.strokeStyle = "#D40000";
  ctx.fillStyle = "#D40000";
  ctx.lineWidth = 6;
  ctx.beginPath();
  ctx.moveTo(x*-30,y*-30);
  ctx.lineTo(x*83,y*83);
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(0,0,10,0,Math.PI*2,true);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(x*95,y*95,10,0,Math.PI*2,true);
  ctx.stroke();
  ctx.fillStyle = "#555";
  ctx.arc(0,0,3,0,Math.PI*2,true);
  ctx.fill();

  ctx.restore();
}

var xcb = require('../xcb/xcb')
new xcb.Connection(function(display) {
var X = this
  , screen = X.getScreen()
  , wid = X.generateId()
  , gc  = X.generateId()
X.CreateWindow(
  { depth: 0
  , wid: wid
  , parent: screen.root
  , x: 10
  , y: 10
  , width: 320
  , height: 320
  , border_width: 1
  , _class: 1
  , visual: 0
  , value_mask: 2050
  , value_list: [screen.white_pixel, 32768 | xcb.EventMask.KeyPress]
});
X.MapWindow({ window: wid });

var tween = (function() {
  var interval
  return function(props, duration, func, done) {
    var time = 0
      , last = Date.now()
      , diff
    clearInterval(interval)
    interval = setInterval(function() {
      var now = Date.now()
      time += now - last
      last = now
      if (time > duration) {
        time = duration
        clearInterval(interval)
        done()
      }
      diff = time / duration
      var curProps = {}
      Object.keys(props).forEach(function(propName) {
        var prop = props[propName]
        curProps[propName] = prop[0] + (prop[1] - prop[0]) * diff
      })
      func(curProps)
    }, 15)
  }
})()

function configWin(vals) {
  X.ConfigureWindow({ window: wid, value_mask: 3, value_list: [vals.x, vals.y] })
  X.flush()
}

X.ConfigureWindow({ window: screen.root, value_mask: 2048 | 512, value_list: [true, 1] })

X.onKeyPress = function(event) {
  console.log(event)
  switch (event.detail) {
    case 113: return twin()
    case 114: return twin(true)
  }
}

function twin(a) {
  a = a || false
  var b = a ? [-319, 0] : [0, -319]
  tween({ x: b, y: b }, 500, configWin, function () {
    setTimeout(twin.bind(null, !a), 1000)
  })
}

X.SetInputFocus({ focus: wid, revert_to: screen.root, time: Date.now()})

var vis = screen.allowed_depths[5].visuals[0]
  , xcbCanvas = require('./build/default/xcb-canvas')
setInterval(drawIt, 1000)
drawIt()
function drawIt() {
  clock(ctx)
  xcbCanvas.displayCanvas.call(X, wid, vis, canvas)
  X.flush()
}
})
<commit_msg>making example much more minimal<commit_after>
/**
 * Module dependencies.
 */

var Canvas = require('../node-canvas/lib/canvas')
  , canvas = new Canvas(320, 320)
  , ctx = canvas.getContext('2d')
  , fs = require('fs');

function getX(angle) {
  return -Math.sin(angle + Math.PI);
}
function getY(angle) {
  return Math.cos(angle + Math.PI);
}

function clock(ctx){
  var now = new Date();
  ctx.clearRect(0,0,320,320);

  ctx.save();
  ctx.translate(160,160);
  ctx.beginPath();
  ctx.lineWidth = 14;
  ctx.strokeStyle = '#325FA2';
  ctx.fillStyle = '#eeeeee';
  ctx.arc(0,0,142,0,Math.PI*2,true);
  ctx.stroke();
  ctx.fill();

  ctx.strokeStyle = '#000000';
  // Hour marks
  ctx.lineWidth = 8;
  for (var i=0;i<12;i++){
    var x = getX(Math.PI/6*i);
    var y = getY(Math.PI/6*i);
    ctx.beginPath();
    ctx.moveTo(x*100,y*100);
    ctx.lineTo(x*125,y*125);
    ctx.stroke();
  }

  // Minute marks
  ctx.lineWidth = 5;
  for (i=0;i<60;i++){
    if (i%5!=0) {
      var x = getX(Math.PI/30*i);
      var y = getY(Math.PI/30*i);
      ctx.beginPath();
      ctx.moveTo(x*117,y*117);
      ctx.lineTo(x*125,y*125);
      ctx.stroke();
    }
  }

  var sec = now.getSeconds();
  var min = now.getMinutes();
  var hr  = now.getHours();
  hr = hr>=12 ? hr-12 : hr;

  ctx.fillStyle = "black";

  // write Hours
  var x = getX(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
  var y = getY(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
  ctx.lineWidth = 14;
  ctx.beginPath();
  ctx.moveTo(x*-20,y*-20);
  ctx.lineTo(x*80,y*80);
  ctx.stroke();

  // write Minutes
  var x = getX((Math.PI/30)*min + (Math.PI/1800)*sec);
  var y = getY((Math.PI/30)*min + (Math.PI/1800)*sec);

  ctx.lineWidth = 10;
  ctx.beginPath();
  ctx.moveTo(x*-28,y*-28);
  ctx.lineTo(x*112,y*112);
  ctx.stroke();

  // Write seconds
  var x = getX(sec * Math.PI/30);
  var y = getY(sec * Math.PI/30);
  ctx.strokeStyle = "#D40000";
  ctx.fillStyle = "#D40000";
  ctx.lineWidth = 6;
  ctx.beginPath();
  ctx.moveTo(x*-30,y*-30);
  ctx.lineTo(x*83,y*83);
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(0,0,10,0,Math.PI*2,true);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(x*95,y*95,10,0,Math.PI*2,true);
  ctx.stroke();
  ctx.fillStyle = "#555";
  ctx.arc(0,0,3,0,Math.PI*2,true);
  ctx.fill();

  ctx.restore();
}

var xcb = require('../xcb/xcb')
new xcb.Connection(function(display) {
var X = this
  , screen = X.getScreen()
  , wid = X.generateId()
  , gc  = X.generateId()
X.CreateWindow(
  { depth: 0
  , wid: wid
  , parent: screen.root
  , x: 10
  , y: 10
  , width: 320
  , height: 320
  , border_width: 1
  , _class: 1
  , visual: 0
  , value_mask: 2050
  , value_list: [screen.white_pixel, 32768 | xcb.EventMask.KeyPress]
});
X.MapWindow({ window: wid });

function configWin(vals) {
  X.ConfigureWindow({ window: wid, value_mask: 3, value_list: [vals.x, vals.y] })
  X.flush()
}

X.ConfigureWindow({ window: screen.root, value_mask: 2048 | 512, value_list: [true, 1] })

var vis = screen.allowed_depths[5].visuals[0]
  , xcbCanvas = require('./build/default/xcb-canvas')
setInterval(drawIt, 1000)
drawIt()
function drawIt() {
  clock(ctx)
  xcbCanvas.displayCanvas.call(X, wid, vis, canvas)
  X.flush()
}
})
<|endoftext|>


<commit_before>var files =
	[
	 	"lib/underscore.js",
	 	"lib/backbone.js",
	 	"src/bcapi.js",
	 	"src/helper.js",
	 	"src/config.js",
	 	"src/models.js",
	 	"src/webapp.js",
	 	"src/webapp_item.js",
	 	"src/webapp_customfield.js"
    ];

module.exports = files;<commit_msg>Added categories to the grunt loop<commit_after>var files =
	[
	 	"lib/underscore.js",
	 	"lib/backbone.js",
	 	"src/bcapi.js",
	 	"src/helper.js",
	 	"src/config.js",
	 	"src/models.js",
	 	"src/webapp.js",
	 	"src/webapp_item.js",
	 	"src/webapp_customfield.js",
        "src/category.js"
    ];

module.exports = files;<|endoftext|>


<commit_before>
//TODO uncomment and write more tests
/* Tests for fileBrowser.js for My Projects in Dashboard */
/*global describe, it, expect, example, before, after, beforeEach, afterEach, mocha, sinon*/
'use strict';
var assert = require('chai').assert;

var $ = require('jquery');
var $osf = require('js/osfHelpers');
var fb = require('js/fileBrowser.js');
var m = require('mithril');

var FileBrowser = fb.FileBrowser;
var LinkObject = fb.LinkObject;

describe('fileBrowser', function() {
    describe('LinkObject', function () {
        var collection;
        var tag;
        var name;
        var node;

        before(function () {
            collection = new LinkObject('collection', {
                path: 'users/me/nodes/',
                query: {'related_counts': true},
                systemCollection: true
            }, 'All My Projects');
            tag = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else');
            name = new LinkObject('name', { id : '8q36f', query : { 'related_counts' : true }}, 'Caner Uguz');
            node = new LinkObject('node', { uid : 'qwerty'}, 'Node Title');
        });

        describe('#attributes', function () {
            it('should return an id of 1', function () {
                assert.equal(collection.id, 1);
            });
            it('should throw error when no arguments passed', function () {
                assert.throws(function(){ var missing = new LinkObject(); }, Error);
            });
            it('should throw error when index is not number and  > 0', function () {
                assert.throws(function(){ var missing = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else', 'index'); }, Error);
                assert.throws(function(){ var missing = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else', -1); }, Error);
            });
        });

        describe('#generateLinks', function () {
            it('should return correct collection link', function () {
                assert.equal(collection.link, 'users/me/nodes/?related_counts=true');
            });
            it('should return correct tag link', function () {
                assert.equal(tag.link, 'nodes/?filter%5Btags%5D=something&related_counts=true&embed=contributors');
            });
            it('should return correct name link', function () {
                assert.equal(name.link, 'users/8q36f/nodes/?related_counts=true&embed=contributors');
            });
            it('should return correct node link', function () {
                assert.equal(node.link, 'nodes/qwerty/children/?related_counts=true&embed=contributors');
            });
        });
    });
});<commit_msg>Fix name for file in test file<commit_after>
//TODO uncomment and write more tests
/* Tests for fileBrowser.js for My Projects in Dashboard */
/*global describe, it, expect, example, before, after, beforeEach, afterEach, mocha, sinon*/
'use strict';
var assert = require('chai').assert;

var $ = require('jquery');
var $osf = require('js/osfHelpers');
var fb = require('js/dashboard.js');
var m = require('mithril');

var FileBrowser = fb.Dashboard;
var LinkObject = fb.LinkObject;

describe('fileBrowser', function() {
    describe('LinkObject', function () {
        var collection;
        var tag;
        var name;
        var node;

        before(function () {
            collection = new LinkObject('collection', {
                path: 'users/me/nodes/',
                query: {'related_counts': true},
                systemCollection: true
            }, 'All My Projects');
            tag = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else');
            name = new LinkObject('name', { id : '8q36f', query : { 'related_counts' : true }}, 'Caner Uguz');
            node = new LinkObject('node', { uid : 'qwerty'}, 'Node Title');
        });

        describe('#attributes', function () {
            it('should return an id of 1', function () {
                assert.equal(collection.id, 1);
            });
            it('should throw error when no arguments passed', function () {
                assert.throws(function(){ var missing = new LinkObject(); }, Error);
            });
            it('should throw error when index is not number and  > 0', function () {
                assert.throws(function(){ var missing = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else', 'index'); }, Error);
                assert.throws(function(){ var missing = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else', -1); }, Error);
            });
        });

        describe('#generateLinks', function () {
            it('should return correct collection link', function () {
                assert.equal(collection.link, 'users/me/nodes/?related_counts=true');
            });
            it('should return correct tag link', function () {
                assert.equal(tag.link, 'nodes/?filter%5Btags%5D=something&related_counts=true&embed=contributors');
            });
            it('should return correct name link', function () {
                assert.equal(name.link, 'users/8q36f/nodes/?related_counts=true&embed=contributors');
            });
            it('should return correct node link', function () {
                assert.equal(node.link, 'nodes/qwerty/children/?related_counts=true&embed=contributors');
            });
        });
    });
});<|endoftext|>


<commit_before>/*!
{
  "name": "Transition end event",
  "authors": ["Ivan Nikolić"],
  "notes": [{
    "name": "Modernizr Methods documentation",
    "href": "http://modernizr.com/docs/#s25"
   },
   {
    "name": "Prefixes",
    "href": "https://github.com/twbs/bootstrap/issues/2870#issue-3887306"
   }],
  "tags": ["transition"]
}
!*/
define(['Modernizr','prefixed'], function( Modernizr, prefixed ) {
  Modernizr.prefixedEvent = Modernizr.prefixedEvent || {};
  var transitionEndEventNames = {
    'WebkitTransition' : 'webkitTransitionEnd',
    'msTransition'     : 'MSTransitionEnd',
    'OTransition'      : 'oTransitionEnd',
    'MozTransition'    : 'transitionend',
    'transition'       : 'transitionend'
  };
  var eventValue = transitionEndEventNames[prefixed('transition')];
  // Falsy value on Android 4.1-4.3 default browser
  if ( /Android 4\.[123]/.test(navigator.userAgent) ) {
    eventValue = 'webkitTransitionEnd';
  }
  Modernizr.prefixedEvent.transitionend = eventValue;
});
<commit_msg>Update event fetching<commit_after>/*!
{
  "name": "Transition end event",
  "authors": ["Ivan Nikolić"],
  "notes": [{
    "name": "Modernizr Methods documentation",
    "href": "http://modernizr.com/docs/#s25"
   },
   {
    "name": "Prefixes",
    "href": "https://github.com/twbs/bootstrap/issues/2870#issue-3887306"
   }],
  "tags": ["transition"]
}
!*/
define(['Modernizr','prefixed'], function( Modernizr, prefixed ) {
  Modernizr.prefixedEvent = Modernizr.prefixedEvent || {};
  var transitionEndEventNames = {
    'WebkitTransition' : 'webkitTransitionEnd',
    'msTransition'     : 'MSTransitionEnd',
    'OTransition'      : 'oTransitionEnd',
    'MozTransition'    : 'transitionend',
    'transition'       : 'transitionend'
  };
  var eventValue = transitionEndEventNames[prefixed('transition')];
  // Falsy value on Android 4.1-4.3 default browser
  if ( /Android 4\.[123]/.test(navigator.userAgent) ) {
    eventValue = transitionEndEventNames['WebkitTransition'];
  }
  Modernizr.prefixedEvent.transitionend = eventValue;
});
<|endoftext|>


<commit_before>/* global MD5 */

import { ReducerRegistry } from '../redux';

import {
    DOMINANT_SPEAKER_CHANGED,
    PARTICIPANT_ID_CHANGED,
    PARTICIPANT_JOINED,
    PARTICIPANT_LEFT,
    PARTICIPANT_UPDATED,
    PIN_PARTICIPANT
} from './actionTypes';
import {
    LOCAL_PARTICIPANT_DEFAULT_ID,
    PARTICIPANT_ROLE
} from './constants';

/**
 * Participant object.
 * @typedef {Object} Participant
 * @property {string} id - Participant ID.
 * @property {string} name - Participant name.
 * @property {string} avatar - Path to participant avatar if any.
 * @property {string} role - Participant role.
 * @property {boolean} local - If true, participant is local.
 * @property {boolean} pinned - If true, participant is current
 *      "PINNED_ENDPOINT".
 * @property {boolean} speaking - If true, participant is currently a
 *      dominant speaker.
 * @property {boolean} videoStarted -  If true, participant video stream has
 *      already started.
 * @property {('camera'|'desktop'|undefined)} videoType - Type of participant's
 *      current video stream if any.
 * @property {string} email - participant email.
 */

/**
 * These properties should not be bulk assigned when updating a particular
 * @see Participant.
 * @type {string[]}
 */
const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE =
    [ 'id', 'local', 'pinned', 'speaking' ];

/**
 * Reducer function for a single participant.
 *
 * @param {Participant|undefined} state - Participant to be modified.
 * @param {Object} action - Action object.
 * @param {string} action.type - Type of action.
 * @param {Participant} action.participant - Information about participant to be
 * added/modified.
 * @param {JitsiConference} action.conference - Conference instance.
 * @returns {Participant|undefined}
 */
function participant(state, action) {
    switch (action.type) {
    case DOMINANT_SPEAKER_CHANGED:
        // Only one dominant speaker is allowed.
        return Object.assign({}, state, {
            speaking: state.id === action.participant.id
        });

    case PARTICIPANT_ID_CHANGED:
        if (state.id === action.oldValue) {
            let id = action.newValue;

            return {
                ...state,
                id,
                avatar: state.avatar || _getAvatarURL(id, state.email)
            };
        }
        return state;

    case PARTICIPANT_JOINED:
        let participant = action.participant;
        let id = participant.id
            || (participant.local && LOCAL_PARTICIPANT_DEFAULT_ID);
        let avatar = participant.avatar || _getAvatarURL(id, participant.email);
        // TODO: get these names from config/localized
        let name =
            participant.name || (participant.local ? 'me' : 'Fellow Jitster');

        return {
            avatar,
            email: participant.email,
            id,
            local: participant.local || false,
            name,
            pinned: participant.pinned || false,
            role: participant.role || PARTICIPANT_ROLE.NONE,
            speaking: participant.speaking || false,
            videoStarted: false,
            videoType: participant.videoType || undefined
        };

    case PARTICIPANT_UPDATED:
        if (state.id === action.participant.id) {
            let updateObj = {};

            for (let key in action.participant) {
                if (action.participant.hasOwnProperty(key) &&
                    PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE.indexOf(key) === -1) {
                    updateObj[key] = action.participant[key];
                }
            }

            updateObj = Object.assign({}, state, updateObj);

            updateObj.avatar = updateObj.avatar
                || _getAvatarURL(action.participant.id, updateObj.email);

            return updateObj;
        }
        return state;

    case PIN_PARTICIPANT:
        // Currently, only one pinned participant is allowed.
        return {
            ...state,
            pinned: state.id === action.participant.id
        };

    default:
        return state;
    }
}

/**
 * Listen for actions which add, remove, or update the set of participants
 * in the conference.
 *
 * @param {Participant[]} state - List of participants to be modified.
 * @param {Object} action - Action object.
 * @param {string} action.type - Type of action.
 * @param {Participant} action.participant - Information about participant to be
 * added/removed/modified.
 * @returns {Participant[]}
 */
ReducerRegistry.register('features/base/participants', (state = [], action) => {
    switch (action.type) {
    case PARTICIPANT_JOINED:
        return [ ...state, participant(undefined, action) ];

    case PARTICIPANT_LEFT:
        return state.filter(p => p.id !== action.participant.id);

    case DOMINANT_SPEAKER_CHANGED:
    case PARTICIPANT_ID_CHANGED:
    case PARTICIPANT_UPDATED:
    case PIN_PARTICIPANT:
        return state.map(p => participant(p, action));

    default:
        return state;
    }
});

/**
 * Returns the URL of the image for the avatar of a particular participant
 * identified by their id and/or e-mail address.
 *
 * @param {string} participantId - Participant's id.
 * @param {string} [email] - Participant's email.
 * @returns {string} The URL of the image for the avatar of the participant
 * identified by the specified participantId and/or email.
 */
function _getAvatarURL(participantId, email) {
    // TODO: Use disableThirdPartyRequests config

    let avatarId = email || participantId;

    // If the ID looks like an email, we'll use gravatar.
    // Otherwise, it's a random avatar, and we'll use the configured
    // URL.
    let random = !avatarId || avatarId.indexOf('@') < 0;

    if (!avatarId) {
        avatarId = participantId;
    }
    // MD5 is provided by Strophe
    avatarId = MD5.hexdigest(avatarId.trim().toLowerCase());

    let urlPref = null;
    let urlSuf = null;
    if (!random) {
        urlPref = 'https://www.gravatar.com/avatar/';
        urlSuf = '?d=wavatar&size=200';
    }
    // TODO: Use RANDOM_AVATAR_URL_PREFIX from interface config
    else {
        urlPref = 'https://robohash.org/';
        urlSuf = '.png?size=200x200';
    }

    return urlPref + avatarId + urlSuf;
}
<commit_msg>Added comment on participant ID selection in PARTICIPANT_JOINED reducer case<commit_after>/* global MD5 */

import { ReducerRegistry } from '../redux';

import {
    DOMINANT_SPEAKER_CHANGED,
    PARTICIPANT_ID_CHANGED,
    PARTICIPANT_JOINED,
    PARTICIPANT_LEFT,
    PARTICIPANT_UPDATED,
    PIN_PARTICIPANT
} from './actionTypes';
import {
    LOCAL_PARTICIPANT_DEFAULT_ID,
    PARTICIPANT_ROLE
} from './constants';

/**
 * Participant object.
 * @typedef {Object} Participant
 * @property {string} id - Participant ID.
 * @property {string} name - Participant name.
 * @property {string} avatar - Path to participant avatar if any.
 * @property {string} role - Participant role.
 * @property {boolean} local - If true, participant is local.
 * @property {boolean} pinned - If true, participant is current
 *      "PINNED_ENDPOINT".
 * @property {boolean} speaking - If true, participant is currently a
 *      dominant speaker.
 * @property {boolean} videoStarted -  If true, participant video stream has
 *      already started.
 * @property {('camera'|'desktop'|undefined)} videoType - Type of participant's
 *      current video stream if any.
 * @property {string} email - participant email.
 */

/**
 * These properties should not be bulk assigned when updating a particular
 * @see Participant.
 * @type {string[]}
 */
const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE =
    [ 'id', 'local', 'pinned', 'speaking' ];

/**
 * Reducer function for a single participant.
 *
 * @param {Participant|undefined} state - Participant to be modified.
 * @param {Object} action - Action object.
 * @param {string} action.type - Type of action.
 * @param {Participant} action.participant - Information about participant to be
 * added/modified.
 * @param {JitsiConference} action.conference - Conference instance.
 * @returns {Participant|undefined}
 */
function participant(state, action) {
    switch (action.type) {
    case DOMINANT_SPEAKER_CHANGED:
        // Only one dominant speaker is allowed.
        return Object.assign({}, state, {
            speaking: state.id === action.participant.id
        });

    case PARTICIPANT_ID_CHANGED:
        if (state.id === action.oldValue) {
            let id = action.newValue;

            return {
                ...state,
                id,
                avatar: state.avatar || _getAvatarURL(id, state.email)
            };
        }
        return state;

    case PARTICIPANT_JOINED:
        let participant = action.participant;
        // The logic of selecting participant's ID is following:
        // 1) if ID was provided, use it.
        // 2) if ID was not provided:
        //  a) if it's a local participant, then we use
        //  LOCAL_PARTICIPANT_DEFAULT_ID as ID.
        //  b) if it's not a local participant, we leave participant ID
        //  undefined. But actually this situation should not happen, maybe
        //  we should raise an error in this case or generate a random ID.
        let id = participant.id
            || (participant.local && LOCAL_PARTICIPANT_DEFAULT_ID);
        let avatar = participant.avatar || _getAvatarURL(id, participant.email);
        // TODO: get these names from config/localized
        let name =
            participant.name || (participant.local ? 'me' : 'Fellow Jitster');

        return {
            avatar,
            email: participant.email,
            id,
            local: participant.local || false,
            name,
            pinned: participant.pinned || false,
            role: participant.role || PARTICIPANT_ROLE.NONE,
            speaking: participant.speaking || false,
            videoStarted: false,
            videoType: participant.videoType || undefined
        };

    case PARTICIPANT_UPDATED:
        if (state.id === action.participant.id) {
            let updateObj = {};

            for (let key in action.participant) {
                if (action.participant.hasOwnProperty(key) &&
                    PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE.indexOf(key) === -1) {
                    updateObj[key] = action.participant[key];
                }
            }

            updateObj = Object.assign({}, state, updateObj);

            updateObj.avatar = updateObj.avatar
                || _getAvatarURL(action.participant.id, updateObj.email);

            return updateObj;
        }
        return state;

    case PIN_PARTICIPANT:
        // Currently, only one pinned participant is allowed.
        return {
            ...state,
            pinned: state.id === action.participant.id
        };

    default:
        return state;
    }
}

/**
 * Listen for actions which add, remove, or update the set of participants
 * in the conference.
 *
 * @param {Participant[]} state - List of participants to be modified.
 * @param {Object} action - Action object.
 * @param {string} action.type - Type of action.
 * @param {Participant} action.participant - Information about participant to be
 * added/removed/modified.
 * @returns {Participant[]}
 */
ReducerRegistry.register('features/base/participants', (state = [], action) => {
    switch (action.type) {
    case PARTICIPANT_JOINED:
        return [ ...state, participant(undefined, action) ];

    case PARTICIPANT_LEFT:
        return state.filter(p => p.id !== action.participant.id);

    case DOMINANT_SPEAKER_CHANGED:
    case PARTICIPANT_ID_CHANGED:
    case PARTICIPANT_UPDATED:
    case PIN_PARTICIPANT:
        return state.map(p => participant(p, action));

    default:
        return state;
    }
});

/**
 * Returns the URL of the image for the avatar of a particular participant
 * identified by their id and/or e-mail address.
 *
 * @param {string} participantId - Participant's id.
 * @param {string} [email] - Participant's email.
 * @returns {string} The URL of the image for the avatar of the participant
 * identified by the specified participantId and/or email.
 */
function _getAvatarURL(participantId, email) {
    // TODO: Use disableThirdPartyRequests config

    let avatarId = email || participantId;

    // If the ID looks like an email, we'll use gravatar.
    // Otherwise, it's a random avatar, and we'll use the configured
    // URL.
    let random = !avatarId || avatarId.indexOf('@') < 0;

    if (!avatarId) {
        avatarId = participantId;
    }
    // MD5 is provided by Strophe
    avatarId = MD5.hexdigest(avatarId.trim().toLowerCase());

    let urlPref = null;
    let urlSuf = null;
    if (!random) {
        urlPref = 'https://www.gravatar.com/avatar/';
        urlSuf = '?d=wavatar&size=200';
    }
    // TODO: Use RANDOM_AVATAR_URL_PREFIX from interface config
    else {
        urlPref = 'https://robohash.org/';
        urlSuf = '.png?size=200x200';
    }

    return urlPref + avatarId + urlSuf;
}
<|endoftext|>