<commit_before>import React from 'react';
import {shallow, mount} from 'enzyme';

import RecentCommitsController from '../../lib/controllers/recent-commits-controller';
import {commitBuilder} from '../builder/commit';
import {cloneRepository, buildRepository} from '../helpers';
import * as reporterProxy from '../../lib/reporter-proxy';

describe('RecentCommitsController', function() {
  let atomEnv, workdirPath, app;

  beforeEach(async function() {
    workdirPath = await cloneRepository('three-files');
    const repository = await buildRepository(workdirPath);

    atomEnv = global.buildAtomEnvironment();

    app = (
      <RecentCommitsController
        commits={[]}
        isLoading={false}
        undoLastCommit={() => { }}
        workspace={atomEnv.workspace}
        commandRegistry={atomEnv.commands}
        repository={repository}
      />
    );
  });

  afterEach(function() {
    atomEnv.destroy();
  });

  it('passes recent commits to the RecentCommitsView', function() {
    const commits = [commitBuilder().build(), commitBuilder().build(), commitBuilder().build()];
    app = React.cloneElement(app, {commits});
    const wrapper = shallow(app);
    assert.deepEqual(wrapper.find('RecentCommitsView').prop('commits'), commits);
  });

  it('passes fetch progress to the RecentCommitsView', function() {
    app = React.cloneElement(app, {isLoading: true});
    const wrapper = shallow(app);
    assert.isTrue(wrapper.find('RecentCommitsView').prop('isLoading'));
  });

  describe('openCommit({sha, preserveFocus})', function() {
    it('opens a commit detail item', async function() {
      sinon.stub(atomEnv.workspace, 'open').resolves();

      const sha = 'asdf1234';
      const commits = [commitBuilder().sha(sha).build()];
      app = React.cloneElement(app, {commits});

      const wrapper = shallow(app);
      await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234', preserveFocus: false});

      assert.isTrue(atomEnv.workspace.open.calledWith(
        `atom-github://commit-detail?workdir=${encodeURIComponent(workdirPath)}` +
        `&sha=${encodeURIComponent(sha)}`,
      ));
    });

    it('preserves keyboard focus within the RecentCommitsView when requested', async function() {
      sinon.stub(atomEnv.workspace, 'open').resolves();

      const sha = 'asdf1234';
      const commits = [commitBuilder().sha(sha).build()];
      app = React.cloneElement(app, {commits});

      const wrapper = mount(app);
      const focusSpy = sinon.stub(wrapper.find('RecentCommitsView').instance(), 'setFocus').returns(true);

      await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234', preserveFocus: true});
      assert.isTrue(focusSpy.called);
    });

    it('records an event', async function() {
      sinon.stub(atomEnv.workspace, 'open').resolves();
      sinon.stub(reporterProxy, 'addEvent');

      const sha = 'asdf1234';
      const commits = [commitBuilder().sha(sha).build()];
      app = React.cloneElement(app, {commits});
      const wrapper = shallow(app);

      await wrapper.instance().openCommit({sha: 'asdf1234', preserveFocus: true});
      assert.isTrue(reporterProxy.addEvent.calledWith('open-commit-in-pane', {
        package: 'github',
        from: RecentCommitsController.name,
      }));
    });
  });

  describe('commit navigation', function() {
    let wrapper;

    beforeEach(function() {
      const commits = ['1', '2', '3', '4', '5'].map(s => commitBuilder().sha(s).build());
      app = React.cloneElement(app, {commits});
      wrapper = shallow(app);
    });

    describe('selectNextCommit', function() {
      it('selects the first commit if there is no selection', async function() {
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '');
        await wrapper.find('RecentCommitsView').prop('selectNextCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '1');
      });

      it('selects the next commit in sequence', async function() {
        wrapper.setState({selectedCommitSha: '2'});
        await wrapper.find('RecentCommitsView').prop('selectNextCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '3');
      });

      it('remains on the last commit', async function() {
        wrapper.setState({selectedCommitSha: '5'});
        await wrapper.find('RecentCommitsView').prop('selectNextCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '5');
      });
    });

    describe('selectPreviousCommit', function() {
      it('selects the first commit if there is no selection', async function() {
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '');
        await wrapper.find('RecentCommitsView').prop('selectPreviousCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '1');
      });

      it('selects the previous commit in sequence', async function() {
        wrapper.setState({selectedCommitSha: '3'});
        await wrapper.find('RecentCommitsView').prop('selectPreviousCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '2');
      });

      it('remains on the first commit', async function() {
        wrapper.setState({selectedCommitSha: '1'});
        await wrapper.find('RecentCommitsView').prop('selectPreviousCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '1');
      });
    });
  });

  it('forwards focus management methods to its view', async function() {
    const wrapper = mount(app);

    const setFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'setFocus');
    const rememberFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'getFocus');
    const advanceFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'advanceFocusFrom');
    const retreatFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'retreatFocusFrom');

    wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT);
    assert.isTrue(setFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT));

    wrapper.instance().getFocus(document.body);
    assert.isTrue(rememberFocusSpy.calledWith(document.body));

    await wrapper.instance().advanceFocusFrom(RecentCommitsController.focus.RECENT_COMMIT);
    assert.isTrue(advanceFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT));

    await wrapper.instance().retreatFocusFrom(RecentCommitsController.focus.RECENT_COMMIT);
    assert.isTrue(retreatFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT));
  });
});
<commit_msg>Test coverate for RecentCommitController's workspace tracking<commit_after>import React from 'react';
import {shallow, mount} from 'enzyme';

import RecentCommitsController from '../../lib/controllers/recent-commits-controller';
import CommitDetailItem from '../../lib/items/commit-detail-item';
import URIPattern from '../../lib/atom/uri-pattern';
import {commitBuilder} from '../builder/commit';
import {cloneRepository, buildRepository} from '../helpers';
import * as reporterProxy from '../../lib/reporter-proxy';

describe('RecentCommitsController', function() {
  let atomEnv, workdirPath, app;

  beforeEach(async function() {
    workdirPath = await cloneRepository('three-files');
    const repository = await buildRepository(workdirPath);

    atomEnv = global.buildAtomEnvironment();

    app = (
      <RecentCommitsController
        commits={[]}
        isLoading={false}
        undoLastCommit={() => { }}
        workspace={atomEnv.workspace}
        commandRegistry={atomEnv.commands}
        repository={repository}
      />
    );
  });

  afterEach(function() {
    atomEnv.destroy();
  });

  it('passes recent commits to the RecentCommitsView', function() {
    const commits = [commitBuilder().build(), commitBuilder().build(), commitBuilder().build()];
    app = React.cloneElement(app, {commits});
    const wrapper = shallow(app);
    assert.deepEqual(wrapper.find('RecentCommitsView').prop('commits'), commits);
  });

  it('passes fetch progress to the RecentCommitsView', function() {
    app = React.cloneElement(app, {isLoading: true});
    const wrapper = shallow(app);
    assert.isTrue(wrapper.find('RecentCommitsView').prop('isLoading'));
  });

  describe('openCommit({sha, preserveFocus})', function() {
    it('opens a commit detail item', async function() {
      sinon.stub(atomEnv.workspace, 'open').resolves();

      const sha = 'asdf1234';
      const commits = [commitBuilder().sha(sha).build()];
      app = React.cloneElement(app, {commits});

      const wrapper = shallow(app);
      await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234', preserveFocus: false});

      assert.isTrue(atomEnv.workspace.open.calledWith(
        `atom-github://commit-detail?workdir=${encodeURIComponent(workdirPath)}` +
        `&sha=${encodeURIComponent(sha)}`,
      ));
    });

    it('preserves keyboard focus within the RecentCommitsView when requested', async function() {
      sinon.stub(atomEnv.workspace, 'open').resolves();

      const sha = 'asdf1234';
      const commits = [commitBuilder().sha(sha).build()];
      app = React.cloneElement(app, {commits});

      const wrapper = mount(app);
      const focusSpy = sinon.stub(wrapper.find('RecentCommitsView').instance(), 'setFocus').returns(true);

      await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234', preserveFocus: true});
      assert.isTrue(focusSpy.called);
    });

    it('records an event', async function() {
      sinon.stub(atomEnv.workspace, 'open').resolves();
      sinon.stub(reporterProxy, 'addEvent');

      const sha = 'asdf1234';
      const commits = [commitBuilder().sha(sha).build()];
      app = React.cloneElement(app, {commits});
      const wrapper = shallow(app);

      await wrapper.instance().openCommit({sha: 'asdf1234', preserveFocus: true});
      assert.isTrue(reporterProxy.addEvent.calledWith('open-commit-in-pane', {
        package: 'github',
        from: RecentCommitsController.name,
      }));
    });
  });

  describe('commit navigation', function() {
    let wrapper;

    beforeEach(function() {
      const commits = ['1', '2', '3', '4', '5'].map(s => commitBuilder().sha(s).build());
      app = React.cloneElement(app, {commits});
      wrapper = shallow(app);
    });

    describe('selectNextCommit', function() {
      it('selects the first commit if there is no selection', async function() {
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '');
        await wrapper.find('RecentCommitsView').prop('selectNextCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '1');
      });

      it('selects the next commit in sequence', async function() {
        wrapper.setState({selectedCommitSha: '2'});
        await wrapper.find('RecentCommitsView').prop('selectNextCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '3');
      });

      it('remains on the last commit', async function() {
        wrapper.setState({selectedCommitSha: '5'});
        await wrapper.find('RecentCommitsView').prop('selectNextCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '5');
      });
    });

    describe('selectPreviousCommit', function() {
      it('selects the first commit if there is no selection', async function() {
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '');
        await wrapper.find('RecentCommitsView').prop('selectPreviousCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '1');
      });

      it('selects the previous commit in sequence', async function() {
        wrapper.setState({selectedCommitSha: '3'});
        await wrapper.find('RecentCommitsView').prop('selectPreviousCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '2');
      });

      it('remains on the first commit', async function() {
        wrapper.setState({selectedCommitSha: '1'});
        await wrapper.find('RecentCommitsView').prop('selectPreviousCommit')();
        assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '1');
      });
    });
  });

  it('forwards focus management methods to its view', async function() {
    const wrapper = mount(app);

    const setFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'setFocus');
    const rememberFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'getFocus');
    const advanceFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'advanceFocusFrom');
    const retreatFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'retreatFocusFrom');

    wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT);
    assert.isTrue(setFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT));

    wrapper.instance().getFocus(document.body);
    assert.isTrue(rememberFocusSpy.calledWith(document.body));

    await wrapper.instance().advanceFocusFrom(RecentCommitsController.focus.RECENT_COMMIT);
    assert.isTrue(advanceFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT));

    await wrapper.instance().retreatFocusFrom(RecentCommitsController.focus.RECENT_COMMIT);
    assert.isTrue(retreatFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT));
  });

  describe('workspace tracking', function() {
    beforeEach(function() {
      const pattern = new URIPattern(CommitDetailItem.uriPattern);
      // Prevent the Workspace from normalizing CommitDetailItem URIs
      atomEnv.workspace.addOpener(uri => {
        if (pattern.matches(uri).ok()) {
          return {
            getURI() { return uri; },
          };
        }
        return undefined;
      });
    });

    it('updates the selected sha when its CommitDetailItem is activated', async function() {
      const wrapper = shallow(app);
      await atomEnv.workspace.open(CommitDetailItem.buildURI(workdirPath, 'abcdef'));
      assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), 'abcdef');
    });

    it('silently disregards items with no getURI method', async function() {
      const wrapper = shallow(app);
      await atomEnv.workspace.open({item: {}});
      assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '');
    });

    it('silently disregards items that do not match the CommitDetailItem URI pattern', async function() {
      const wrapper = shallow(app);
      await atomEnv.workspace.open(__filename);
      assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '');
    });
  });
});
<|endoftext|>


<commit_before>/* jshint: true */
/* globals: expect:false,beforeAll:false,expect:false,browser:false,element:false,by:false,describe:false,protractor:false,it:false */

describe("tbForm Connection Error", function () {
    var errorText;

    beforeAll(function () {
        // Go to test
        browser.get('index.html');
        element(by.id('testsSelector')).click();
        element(by.id('tbFormConnErrorNoServerUrlTest2')).click();

        /**********************/
        // * Test variables * //
        /**********************/
        // Get component
        errorText = element(by.id('error')).getText();
    });

    it("tbForm connection error functionality",function(){
        expect(errorText).toEqual('');
    });
});<commit_msg>Fixed tbFormConnErrorNoServerUrl-scen2<commit_after>/* jshint: true */
/* globals: expect:false,beforeAll:false,expect:false,browser:false,element:false,by:false,describe:false,protractor:false,it:false */

describe("tbForm Connection Error", function () {
    var errorText;

    beforeAll(function () {
        // Go to test
        browser.get('index.html');
        element(by.id('testsSelector')).click();
        element(by.id('tbFormConnErrorNoServerUrlTest2')).click();

        /**********************/
        // * Test variables * //
        /**********************/
        // Get component
        errorText = element(by.id('error')).getText();
    });

    it("tbForm connection error functionality",function(){
        expect(errorText).toEqual('No data found');
    });
});<|endoftext|>


<commit_before>/* jshint node: true */
/* global io, Hammer */
'use strict';

var touchElem = document.getElementById('touchpad');
var socket = io();
var delta = null;
var moving = false;
var ori = "portrait";
var control = "touch";

var pos = {x: 0, y: 0, cmd: null};
/**
 * pass `pos` object to socket.emit('mouse', pos) function
 *
 * {Object} pos
 * {integer} pos.x mouse x offset
 * {integer} pos.y mouse y offset
 * {string} pos.cmd key command or mouse click (not implemented yet)
 */
var emitMouse = function (x, y, cmd) {
    pos.x = x;
    pos.y = y;
    pos.cmd = cmd;

    socket.emit('mouse', pos);
};

// receive msg
//socket.on('mouse', function(msg) {
//console.log(msg);
//console.info(msg.x + ',' + msg.y);
//});

var handlePan = function (eventName, e) {
    if (e.type == eventName + 'start') {
        delta = null;
        moving = true;
        console.log('start ' + eventName);
        emitMouse(0, 0, eventName + 'start');
    }
    if (e.type == eventName + 'end') {
        delta = null;
        moving = false;
        emitMouse(0, 0, eventName + 'end');
    }
    if (moving && delta != null) {
        emitMouse(e.deltaX - delta.x, e.deltaY - delta.y, eventName);
    }
    delta = {x: e.deltaX, y: e.deltaY};
};

var mc = new Hammer.Manager(touchElem);
mc.add(new Hammer.Pan({event: 'move', threshold: 0, pointers: 1,
    direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Pan({event: 'scroll', threshold: 0, pointers: 2,
    direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Pan({event: 'drag', threshold: 0, pointers: 3,
    direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Tap({event: 'click', pointers: 1}));
mc.add(new Hammer.Tap({event: 'rightclick', pointers: 2}));
mc.on('movestart moveend moveup movedown moveleft moveright', function (e) {
    if (control == "touch") {
        handlePan('move', e);
    }
});
mc.on('scrollstart scrollend scrollup scrolldown scrollleft scrollright',
    function (e) {
        handlePan('scroll', e);
    });
mc.on('dragstart dragend dragup dragdown dragleft dragright', function (e) {
    handlePan('drag', e);
});
mc.on('click', function (e) {
    console.info('click');
    emitMouse(0, 0, 'click');
});
mc.on('rightclick', function (e) {
    console.info('rightclick');
    emitMouse(0, 0, 'rightclick');
});

document.body.requestFullscreen = document.body.requestFullScreen || document.body.webkitRequestFullScreen || document.body.mozRequestFullScreen || document.body.msRequestFullScreen;
document.cancelFullscreen = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen;

$('#fullscreen-toggle').click(function () {
    if (this.checked) {
        document.body.requestFullscreen();
    }
    else {
        document.cancelFullscreen();
    }
});

var lockOrientation = function () {
    if (document.fullscreen) {
        screen.lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation;
        if (screen.lockOrientation) {
            return screen.lockOrientation(ori + '-primary');
        }
        else {
            return screen.orientation.lock(ori + '-primary');
        }
    }
};

$(window).on('fullscreenchange mozfullscreenchange webkitfullscreenchange msfullscreenchange', function () {
    document.fullscreen = (document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreen) == true;
    $('#fullscreen-toggle').prop('checked', document.fullscreen);
    lockOrientation();
});

$('#portrait').click(function () {
    ori = "portrait";
    lockOrientation();
});
$('#landscape').click(function () {
    ori = "landscape";
    lockOrientation();
});
$('#touch-ctrl').click(function () {
    if (this.checked) {
        control = "touch";
    }
});

$('#motion-ctrl').click(function () {
    if (this.checked) {
        control = "motion";
    }
});

window.addEventListener("deviceorientation", function (e) {
    if (control == "motion") {
        var x = e.gamma;
        var y = e.beta;
        if (y > 90) {
            y = 90
        }
        if (y < -90) {
            y = -90
        }
        x += 90;
        y += 90;
        emitMouse(x, y, 'motion')
    }
});<commit_msg>Minor code style change.<commit_after>/* jshint node: true */
/* global io, Hammer */
'use strict';

var touchElem = document.getElementById('touchpad');
var socket = io();
var delta = null;
var moving = false;
var ori = "portrait";
var control = "touch";

var pos = {x: 0, y: 0, cmd: null};
/**
 * pass `pos` object to socket.emit('mouse', pos) function
 *
 * {Object} pos
 * {integer} pos.x mouse x offset
 * {integer} pos.y mouse y offset
 * {string} pos.cmd key command or mouse click (not implemented yet)
 */
var emitMouse = function (x, y, cmd) {
    pos.x = x;
    pos.y = y;
    pos.cmd = cmd;

    socket.emit('mouse', pos);
};

// receive msg
//socket.on('mouse', function(msg) {
//console.log(msg);
//console.info(msg.x + ',' + msg.y);
//});

var handlePan = function (eventName, e) {
    if (e.type == eventName + 'start') {
        delta = null;
        moving = true;
        console.log('start ' + eventName);
        emitMouse(0, 0, eventName + 'start');
    }
    if (e.type == eventName + 'end') {
        delta = null;
        moving = false;
        emitMouse(0, 0, eventName + 'end');
    }
    if (moving && delta != null) {
        emitMouse(e.deltaX - delta.x, e.deltaY - delta.y, eventName);
    }
    delta = {x: e.deltaX, y: e.deltaY};
};

var mc = new Hammer.Manager(touchElem);
mc.add(new Hammer.Pan({event: 'move', threshold: 0, pointers: 1,
    direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Pan({event: 'scroll', threshold: 0, pointers: 2,
    direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Pan({event: 'drag', threshold: 0, pointers: 3,
    direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Tap({event: 'click', pointers: 1}));
mc.add(new Hammer.Tap({event: 'rightclick', pointers: 2}));
mc.on('movestart moveend moveup movedown moveleft moveright', function (e) {
    if (control == "touch") {
        handlePan('move', e);
    }
});
mc.on('scrollstart scrollend scrollup scrolldown scrollleft scrollright',
    function (e) {
        handlePan('scroll', e);
    });
mc.on('dragstart dragend dragup dragdown dragleft dragright', function (e) {
    handlePan('drag', e);
});
mc.on('click', function (e) {
    console.info('click');
    emitMouse(0, 0, 'click');
});
mc.on('rightclick', function (e) {
    console.info('rightclick');
    emitMouse(0, 0, 'rightclick');
});

document.body.requestFullscreen = document.body.requestFullScreen || document.body.webkitRequestFullScreen || document.body.mozRequestFullScreen || document.body.msRequestFullScreen;
document.cancelFullscreen = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen;

$('#fullscreen-toggle').click(function () {
    if (this.checked) {
        document.body.requestFullscreen();
    }
    else {
        document.cancelFullscreen();
    }
});

var lockOrientation = function () {
    if (document.fullscreen) {
        screen.lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation;
        if (screen.lockOrientation) {
            return screen.lockOrientation(ori + '-primary');
        }
        else {
            return screen.orientation.lock(ori + '-primary');
        }
    }
};

$(window).on('fullscreenchange mozfullscreenchange webkitfullscreenchange msfullscreenchange', function () {
    document.fullscreen = (document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreen) == true;
    $('#fullscreen-toggle').prop('checked', document.fullscreen);
    lockOrientation();
});

$('#portrait').click(function () {
    ori = "portrait";
    lockOrientation();
});
$('#landscape').click(function () {
    ori = "landscape";
    lockOrientation();
});
$('#touch-ctrl').click(function () {
    if (this.checked) {
        control = "touch";
    }
});

$('#motion-ctrl').click(function () {
    if (this.checked) {
        control = "motion";
    }
});

window.addEventListener("deviceorientation", function (e) {
    if (control == "motion") {
        var x = e.gamma;
        var y = e.beta;
        y = (y > 90) ? 90 : y;
        y = (y < -90) ? -90 : y;

        x += 90;
        y += 90;
        emitMouse(x, y, 'motion')
    }
});
<|endoftext|>


<commit_before>'use strict';

const NodeType = require('../nodeType');
const _ = require('underscore');

/*
 * Check whether a node has any content.
 * @param {!DOMElement} node
 * @return {!Boolean} whether the node is empty after all whitespace is stripped.
 */
function isEmpty(node) {
    return node.textContent.trim().length === 0;
}

/*
 * Extracts the first non-empty paragraph from an article and any
 * nodes that follow it that are not themselves paragraphs.
 * @param {!Document} doc representing article
 * @param {Boolean} removeNodes when set the lead introduction will
 *  be removed from the input DOM tree.
 * @return {String} representing article introduction
 */
function extractLeadIntroduction(doc, removeNodes) {
    let p = '';
    const remove = [];
    const blacklist = [ 'P', 'TABLE', 'CENTER', 'FIGURE', 'DIV' ];
    const nodes = doc.querySelectorAll('body > p');

    Array.prototype.forEach.call(nodes, (node) => {
        let nextSibling;
        if (!p && node && !isEmpty(node)) {
            p = node.outerHTML;
            remove.push(node);
            nextSibling = node.nextSibling;
            // check the next element is a text node or not in list of blacklisted elements
            while (nextSibling && (nextSibling.nodeType === NodeType.TEXT_NODE ||
                blacklist.indexOf(nextSibling.tagName) === -1
            )) {
                // Deal with text nodes
                if (nextSibling.nodeType === NodeType.TEXT_NODE) {
                    if (!isEmpty(nextSibling)) {
                        p += _.escape(nextSibling.textContent);
                    }
                } else {
                    p += nextSibling.outerHTML;
                }
                remove.push(nextSibling);
                nextSibling = nextSibling.nextSibling;
            }
        }
    });
    // cleanup all the nodes.
    if (removeNodes) {
        remove.forEach((node) => {
            node.parentNode.removeChild(node);
        });
    }
    return p;
}

module.exports = extractLeadIntroduction;
<commit_msg>Hygiene: fix jsdoc in extractLeadIntroduction<commit_after>'use strict';

const NodeType = require('../nodeType');
const _ = require('underscore');

/**
 * Check whether a node has any content.
 * @param {!Element} node
 * @return {!boolean} whether the node is empty after all whitespace is stripped.
 */
function isEmpty(node) {
    return node.textContent.trim().length === 0;
}

/**
 * Extracts the first non-empty paragraph from an article and any
 * nodes that follow it that are not themselves paragraphs.
 * @param {!Document} doc representing article
 * @param {boolean} removeNodes when set the lead introduction will
 *  be removed from the input DOM tree.
 * @return {string} representing article introduction
 */
function extractLeadIntroduction(doc, removeNodes) {
    let p = '';
    const remove = [];
    const blacklist = [ 'P', 'TABLE', 'CENTER', 'FIGURE', 'DIV' ];
    const nodes = doc.querySelectorAll('body > p');

    Array.prototype.forEach.call(nodes, (node) => {
        let nextSibling;
        if (!p && node && !isEmpty(node)) {
            p = node.outerHTML;
            remove.push(node);
            nextSibling = node.nextSibling;
            // check the next element is a text node or not in list of blacklisted elements
            while (nextSibling && (nextSibling.nodeType === NodeType.TEXT_NODE ||
                blacklist.indexOf(nextSibling.tagName) === -1
            )) {
                // Deal with text nodes
                if (nextSibling.nodeType === NodeType.TEXT_NODE) {
                    if (!isEmpty(nextSibling)) {
                        p += _.escape(nextSibling.textContent);
                    }
                } else {
                    p += nextSibling.outerHTML;
                }
                remove.push(nextSibling);
                nextSibling = nextSibling.nextSibling;
            }
        }
    });
    // cleanup all the nodes.
    if (removeNodes) {
        remove.forEach((node) => {
            node.parentNode.removeChild(node);
        });
    }
    return p;
}

module.exports = extractLeadIntroduction;
<|endoftext|>


<commit_before>/**
 * @file dev.js
 * @since 2.2.0
 */

const path = require('path');
const util = require('util');
const fs = require('fs-extra');
const colors = require('colors/safe');
const formidable = require('formidable');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');

const contentBase = path.resolve(__dirname, '..', '..');

module.exports = {
    mode: 'development',
    devServer: {
        port: 8080,
        static: [
            {
                directory: contentBase,
                staticOptions: {},
                publicPath: '/',
                // serveIndex: {} (options for the `serveIndex` option you can find https://github.com/expressjs/serve-index)
                serveIndex: true,
                watch: {
                    ignored: [
                        /.build_cache/,
                        /.chrome/,
                        /docs/,
                        /node_modules/,
                        /bower_components/,
                        /coverage/,
                        /build-config/,
                        /test/,
                        /vendor/
                    ]
                }
            }
        ],
        // webpack-dev-server middleware
        onBeforeSetupMiddleware(args) {
            // =============================================
            // use proper mime-type for wasm files
            // =============================================
            args.app.get('*.wasm', (req, res, next) => {
                let options = {
                    root: contentBase,
                    dotfiles: 'deny',
                    headers: {
                        'Content-Type': 'application/wasm'
                    }
                };

                res.sendFile(req.url, options, (err) => {
                    if (err) {
                        next(err);
                    }
                });
            });

            console.log('');
            console.log(colors.green(' [examples] wasm mime-type handler ready'));
            console.log('');

            // ========================================================
            // use proper headers for SharedArrayBuffer on Firefox
            // see https://github.com/ffmpegwasm/ffmpeg.wasm/issues/102
            // ========================================================
            args.app.use((req, res, next) => {
                res.header('Cross-Origin-Opener-Policy', 'same-origin');
                res.header('Cross-Origin-Embedder-Policy', 'require-corp');
                next();
            });

            // =============================================
            // file upload handler for simple upload example
            // =============================================
            // make sure 'uploads' directory exists (and
            // create it otherwise)
            const targetDir = 'uploads';
            fs.ensureDirSync(targetDir);

            // file upload handler for examples
            args.app.post('/upload', (req, res) => {
                // save uploaded file
                let form = new formidable.IncomingForm();
                form.uploadDir = targetDir;
                form.keepExtensions = true;

                console.log('saving uploaded file...');

                form.on('error', (err) => {
                    console.log(colors.red('upload error:'));
                    console.log(err);
                });

                form.on('fileBegin', (name, file) => {
                    // use original filename in this example
                    file.path = form.uploadDir + '/' + file.name;
                    console.log(colors.yellow('filename:', file.name));
                });

                form.on('end', () => {
                    console.log(colors.green('saved file.'));
                    console.log('');
                });

                form.parse(req, (err, fields, files) => {
                    res.writeHead(200, {'content-type': 'text/plain'});
                    res.write('received upload:\n\n');
                    res.end(util.inspect({fields: fields, files: files}));
                });

                return;
            });
            console.log('');
            console.log(colors.green(' [examples] /upload handler ready'));
            console.log('');
        }
    },
    plugins: [
        new RemoveEmptyScriptsPlugin(),
        new MiniCssExtractPlugin({
            filename: 'css/videojs.record.css',
            chunkFilename: 'css/[id].css'
        })
    ]
};
<commit_msg>dev: remove publicPath option<commit_after>/**
 * @file dev.js
 * @since 2.2.0
 */

const path = require('path');
const util = require('util');
const fs = require('fs-extra');
const colors = require('colors/safe');
const formidable = require('formidable');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');

const contentBase = path.resolve(__dirname, '..', '..');

module.exports = {
    mode: 'development',
    devServer: {
        port: 8080,
        static: [
            {
                directory: contentBase,
                staticOptions: {},
                serveIndex: true,
                watch: {
                    ignored: [
                        /.build_cache/,
                        /.chrome/,
                        /docs/,
                        /node_modules/,
                        /bower_components/,
                        /coverage/,
                        /build-config/,
                        /test/,
                        /vendor/
                    ]
                }
            }
        ],
        // webpack-dev-server middleware
        onBeforeSetupMiddleware(args) {
            // =============================================
            // use proper mime-type for wasm files
            // =============================================
            args.app.get('*.wasm', (req, res, next) => {
                let options = {
                    root: contentBase,
                    dotfiles: 'deny',
                    headers: {
                        'Content-Type': 'application/wasm'
                    }
                };

                res.sendFile(req.url, options, (err) => {
                    if (err) {
                        next(err);
                    }
                });
            });

            console.log('');
            console.log(colors.green(' [examples] wasm mime-type handler ready'));
            console.log('');

            // ========================================================
            // use proper headers for SharedArrayBuffer on Firefox
            // see https://github.com/ffmpegwasm/ffmpeg.wasm/issues/102
            // ========================================================
            args.app.use((req, res, next) => {
                res.header('Cross-Origin-Opener-Policy', 'same-origin');
                res.header('Cross-Origin-Embedder-Policy', 'require-corp');
                next();
            });

            // =============================================
            // file upload handler for simple upload example
            // =============================================
            // make sure 'uploads' directory exists (and
            // create it otherwise)
            const targetDir = 'uploads';
            fs.ensureDirSync(targetDir);

            // file upload handler for examples
            args.app.post('/upload', (req, res) => {
                // save uploaded file
                let form = new formidable.IncomingForm();
                form.uploadDir = targetDir;
                form.keepExtensions = true;

                console.log('saving uploaded file...');

                form.on('error', (err) => {
                    console.log(colors.red('upload error:'));
                    console.log(err);
                });

                form.on('fileBegin', (name, file) => {
                    // use original filename in this example
                    file.path = form.uploadDir + '/' + file.name;
                    console.log(colors.yellow('filename:', file.name));
                });

                form.on('end', () => {
                    console.log(colors.green('saved file.'));
                    console.log('');
                });

                form.parse(req, (err, fields, files) => {
                    res.writeHead(200, {'content-type': 'text/plain'});
                    res.write('received upload:\n\n');
                    res.end(util.inspect({fields: fields, files: files}));
                });

                return;
            });
            console.log('');
            console.log(colors.green(' [examples] /upload handler ready'));
            console.log('');
        }
    },
    plugins: [
        new RemoveEmptyScriptsPlugin(),
        new MiniCssExtractPlugin({
            filename: 'css/videojs.record.css',
            chunkFilename: 'css/[id].css'
        })
    ]
};
<|endoftext|>


<commit_before>// Opens create wopi modal on the click of the button
function applyCreateWopiFileCallback()  {
  $(".create-wopi-file-btn").off().on('click', function(e){
    var $modal = $('#new-office-file-modal');
    $($modal).find('form').clearFormErrors();
    $($modal).find('#new-wopi-file-name').val('');

    // Append element info to which the new file will be attached
    $modal.find('#element_id').val($(this).data('id'));
    $modal.find('#element_type').val($(this).data('type'));
    $modal.modal('show');

    return false;
  });
}

// Show errors on create wopi modal
function initCreateWopiFileModal() {
  // Ajax actions
  $("#new-office-file-modal form")
    .on('ajax:success', function(ev, data) {
      window.open(data.edit_url, '_blank');
      $('#new-office-file-modal').modal('hide');

      //location.reload();
    })
    .on('ajax:error', function(ev, response) {
      $(this).clearFormErrors();
      var element, msg;

      if (response.status === 400) {
        element = $(this).find('#new-wopi-file-name');
        msg = response.responseJSON.message.file.toString();
      } else if (response.status === 403) {
        element = $(this).find('#other-wopi-errors');
        msg = I18n.t('assets.create_wopi_file.errors.forbidden');
      } else if (response.status === 404) {
        element = $(this).find('#other-wopi-errors');
        msg = I18n.t('assets.create_wopi_file.errors.not_found');
      }
      renderFormError(undefined, element, msg);
    });
}

function applyImageChangeOnButtons() {
  var modal = $('#new-office-file-modal');
  modal.find('.btn-group label').off().click(function() {
    modal.find('img.act').hide();
    modal.find('img.inactive').show();

    $(this).find('img.act').show();
    $(this).find('img.inactive').hide();
  });

  // Set default value
  modal.find('label#word-btn').click();
}

$(document).ready(function() {
  initCreateWopiFileModal();
  applyImageChangeOnButtons();
});
<commit_msg>Hound formatting<commit_after>// Opens create wopi modal on the click of the button
function applyCreateWopiFileCallback() {
  $('.create-wopi-file-btn').off().on('click', function(e) {
    var $modal = $('#new-office-file-modal');
    $($modal).find('form').clearFormErrors();
    $($modal).find('#new-wopi-file-name').val('');

    // Append element info to which the new file will be attached
    $modal.find('#element_id').val($(this).data('id'));
    $modal.find('#element_type').val($(this).data('type'));
    $modal.modal('show');

    return false;
  });
}

// Show errors on create wopi modal
function initCreateWopiFileModal() {
  // Ajax actions
  $('#new-office-file-modal form')
    .on('ajax:success', function(ev, data) {
      window.open(data.edit_url, '_blank');
      $('#new-office-file-modal').modal('hide');

      // location.reload();
    })
    .on('ajax:error', function(ev, response) {
      var element;
      var msg;

      $(this).clearFormErrors();

      if (response.status === 400) {
        element = $(this).find('#new-wopi-file-name');
        msg = response.responseJSON.message.file.toString();
      } else if (response.status === 403) {
        element = $(this).find('#other-wopi-errors');
        msg = I18n.t('assets.create_wopi_file.errors.forbidden');
      } else if (response.status === 404) {
        element = $(this).find('#other-wopi-errors');
        msg = I18n.t('assets.create_wopi_file.errors.not_found');
      }
      renderFormError(undefined, element, msg);
    });
}

function applyImageChangeOnButtons() {
  var modal = $('#new-office-file-modal');
  modal.find('.btn-group label').off().click(function() {
    modal.find('img.act').hide();
    modal.find('img.inactive').show();

    $(this).find('img.act').show();
    $(this).find('img.inactive').hide();
  });

  // Set default value
  modal.find('label#word-btn').click();
}

$(document).ready(function() {
  initCreateWopiFileModal();
  applyImageChangeOnButtons();
});
<|endoftext|>


<commit_before>"use strict";

var $ = require('jquery'),
    Bacon = require('baconjs'),
    R = require('ramda'),
    BU = require('treemap/lib/baconUtils.js'),
    U = require('treemap/lib/utility.js'),
    _ = require('lodash'),
    FH = require('treemap/lib/fieldHelpers.js'),
    console = require('console-browserify'),
    editableForm = require('treemap/lib/editableForm.js'),

    eventsLandingInEditMode = [editableForm.editStartAction, 'save:start', 'save:error'],
    eventsLandingInDisplayMode = ['idle', 'save:ok', 'cancel'];

exports.init = function(options) {
    var updateUrl = options.updateUrl,
        section = options.section || 'body',
        form = options.form || section + ' form',
        $section = $(section),
        $edit = options.edit ? $(options.edit) : $section.find('.editBtn'),
        $save = options.save ? $(options.save) : $section.find('.saveBtn'),
        $cancel = options.cancel ? $(options.cancel) : $section.find('.cancelBtn'),
        $spinner = options.spinner ? $(options.spinner) : $section.find('.spinner'),
        displayFields = options.displayFields || section + ' [data-class="display"]',
        editFields = options.editFields || section + ' [data-class="edit"]',
        validationFields = options.validationFields || section + ' [data-class="error"]',
        globalErrorSection = options.globalErrorSection,
        errorCallback = options.errorCallback || $.noop,
        onSaveAfter = options.onSaveAfter || _.identity,

        showSavePending = function (saveIsPending) {
            $spinner.toggle(saveIsPending);
            $save.prop('disabled', saveIsPending);
            $cancel.prop('disabled', saveIsPending);
        },

        editStream = $edit.asEventStream('click').map(editableForm.editStartAction),
        saveStream = (options.saveStream || $save.asEventStream('click'))
            .doAction(showSavePending, true)
            .map('save:start'),
        externalCancelStream = BU.triggeredObjectStream('cancel'),
        cancelStream = $cancel.asEventStream('click').map('cancel'),
        globalCancelStream = cancelStream.merge(externalCancelStream),

        actionStream = new Bacon.Bus(),

        editForm = editableForm.init(options),

        logError = function(error) {
            console.error("Error uploading to " + updateUrl, error);
        },

        resetCollectionUdfs = function() {
            // Hide the edit row
            $("table[data-udf-id] .editrow").hide();

            // If there are no 'data' rows on a given table
            // hide the header and show the placeholder
            $("table[data-udf-id]").map(function() {
                var $table = $(this);

                // If the table has 3 rows they are:
                //
                // header, edit row (hidden), placeholder row (hidden)
                //
                // This means there is no user data, so
                // show the placeholder and hide the header
                if ($table.find('tr').length === 3) {
                    $table.find('.placeholder').show();
                    $table.find('.headerrow').hide();
                } else {
                    // We have some data rows so show the header
                    // and not the placeholder
                    $table.find('.placeholder').hide();
                    $table.find('.headerrow').show();
                }
            });
        },

        showCollectionUdfs = function() {
            // By default collection udfs have their input row
            // hidden, so show that row
            $("table[data-udf-id] .editrow").css('display', '');

            // The header row may also be hidden if there are no
            // items so show that as well
            $("table[data-udf-id] .headerrow").css('display', '');

            $("table[data-udf-id] .placeholder").css('display', 'none');
        },

        getDataToSave = function() {
            var data = FH.formToDictionary($(form), $(editFields), $(displayFields));

            // Extract data for all rows of the collection,
            // whether entered in this session or pre-existing.
            $('table[data-udf-name]').map(function() {
                var $table = $(this);
                var name = $table.data('udf-name');

                var headers = $table.find('tr.headerrow th')
                        .map(function() {
                            return $(this).html();
                        });

                headers = _.compact(headers);

                data[name] =
                    _.map($table.find('tr[data-value-id]').toArray(), function(row) {
                        var $row = $(row),
                            $tds = $row.find('td'),
                            id = $row.attr('data-value-id'),

                            rowData = _.object(headers, $tds
                                        .map(function() {
                                            return $.trim($(this).attr('data-value'));
                                        }));
                        if (! _.isEmpty(id)) {
                            rowData.id = id;
                        }
                        return rowData;
                    });
            });

            return data;
        },

        showGlobalErrors = function (errors) {
            var $globalErrorSection = $(globalErrorSection);

            if ($globalErrorSection.length > 0) {
                $globalErrorSection.html(errors.join(','));
                $globalErrorSection.show();
            } else {
                console.log('Global error returned from server, ' +
                            'but no dom element bound from client.',
                            errors);
            }
        },

        showValidationErrorsInline = function (errors) {
            $(validationFields).not(globalErrorSection).each(function() {
                $(this).html('');
            });
            _.each(errors, function (errorList, fieldName) {
                var $field = FH.getField($(validationFields), fieldName);

                if ($field.length > 0) {
                    $field.html(errorList.join(','));
                    $field.show();
                } else {
                    console.log('Field error returned from server, ' +
                                'but no dom element bound from client.',
                                fieldName, errorList);
                }
            });
        },

        isEditStart = function (action) {
            return action === 'edit:start';
        },

        responseStream = saveStream
            .map(getDataToSave)
            .flatMapLatest(function (data) {
                // onSaveBefore is a function that takes form data
                // and carries out arbitrary, potentially blocking
                // actions before allowing the save process to
                // continue.
                //
                // the return value of an onSaveBefore callback can be:
                // * null - for non-blocking side effects and mutation
                //          of the data object
                // * an eventStream - for blocking side effects,
                //                    failure cases and early exits.
                //
                // when providing an eventStream as the return value for
                // onSaveBefore, it should meet the following criteria:
                // * it should be a stream of data objects. If you are using
                //   eventStreams to block on IO, map them to the `data`
                //   object provided.
                // * it should pust a new stream value when it's ok to
                //   proceed and block until then. There is no concept
                //   of exiting, just failing to stop blocking.
                var result = options.onSaveBefore ?
                        options.onSaveBefore(data) : null;
                if (_.isNull(result) || _.isUndefined(result)) {
                    return Bacon.once(data);
                } else if (_.isObject(result) && result.hasOwnProperty('takeUntil')) {
                    return result;
                } else {
                    throw "onSaveBefore returned something other than a stream or null";
                }
            })
            .flatMap(function(data) {
                return Bacon.fromPromise($.ajax({
                    url: updateUrl,
                    type: 'PUT',
                    contentType: "application/json",
                    data: JSON.stringify(data)
                }));
            }),

        responseErrorStream = responseStream
            .errors()
            .mapError(function (e) {
                showSavePending(false);
                var result = ('responseJSON' in e) ? e.responseJSON : {};
                if ('error' in result) {
                    U.warnDeprecatedErrorMessage(result);
                    result.unstructuredError = result.error;
                }
                if (!('unstructuredError' in result)) {
                    // Make sure there's an 'unstructuredError' property
                    // we look for it in the stream that responds to this.
                    // Give it the error object to help with debugging.
                    result.unstructuredError = e;
                }
                return result;
            }),

        saveOkStream = responseStream.map(function(responseData) {
            showSavePending(false);
            return {
                formData: getDataToSave(),
                responseData: responseData
            };
        }),

        validationErrorsStream = responseErrorStream
            .filter('.fieldErrors')
            .map('.fieldErrors'),

        globalErrorsStream = responseErrorStream
            .filter('.globalErrors')
            .map('.globalErrors'),

        unhandledErrorStream = responseErrorStream
            .filter(R.and(BU.isPropertyUndefined('fieldErrors'),
                          BU.isPropertyUndefined('globalErrors')))
            .map('.unstructuredError'),

        editStartStream = actionStream.filter(isEditStart),

        inEditModeProperty = actionStream.map(function (event) {
            return _.contains(eventsLandingInEditMode, event);
        })
            .toProperty()
            .skipDuplicates(),

        saveOKFormDataStream = saveOkStream.map('.formData'),

        eventsLandingInDisplayModeStream =
            actionStream.filter(_.contains, eventsLandingInDisplayMode),

        shouldBeInEditModeStream = options.shouldBeInEditModeStream || Bacon.never(),
        modeChangeStream = shouldBeInEditModeStream
            .map(function(isInEdit) {
                return isInEdit ? 'edit:start' : 'cancel';
            });

    // Prevent default form submission from clicking on buttons or pressing
    // enter. Event is delegated on window since sometimes <form>s are inserted
    // into the page via AJAX without reiniting inlineEditForm
    $(window).on('submit', form, function(event) { event.preventDefault(); });

    // Merge the major streams on the page together so that it can centrally
    // manage the cleanup of ui forms after the change in run mode
    actionStream.plug(editStream);
    actionStream.plug(saveStream);
    actionStream.plug(cancelStream);
    actionStream.plug(externalCancelStream);
    actionStream.plug(saveOkStream.map('save:ok'));
    actionStream.plug(responseErrorStream.map('save:error'));
    actionStream.plug(modeChangeStream);
    actionStream.onValue(editForm.hideAndShowElements, editFields, eventsLandingInEditMode);
    actionStream.onValue(editForm.hideAndShowElements, displayFields, eventsLandingInDisplayMode);
    actionStream.onValue(editForm.hideAndShowElements, validationFields, ['save:error']);

    responseStream.onValue(onSaveAfter);

    globalCancelStream.onValue(showSavePending, false);

    saveOKFormDataStream.onValue(editForm.formFieldsToDisplayValues);

    globalErrorsStream.onValue(showGlobalErrors);
    validationErrorsStream.onValue(showValidationErrorsInline);

    unhandledErrorStream.onValue(errorCallback);
    unhandledErrorStream.onValue(logError);

    editStartStream.onValue(editForm.displayValuesToFormFields);
    editStartStream.onValue(showCollectionUdfs);

    eventsLandingInDisplayModeStream.onValue(resetCollectionUdfs);

    return {
        // immutable access to all actions
        actionStream: actionStream.map(_.identity),
        cancel: externalCancelStream.trigger,
        saveOkStream: saveOkStream,
        // TODO: audit all uses of cancelStream, external cancel, and
        // global cancel stream and merge these streams in the api
        cancelStream: cancelStream,
        globalCancelStream: globalCancelStream,
        inEditModeProperty: inEditModeProperty,
        showGlobalErrors: showGlobalErrors,
        showValidationErrorsInline: showValidationErrorsInline,
        setUpdateUrl: function (url) { updateUrl = url; }
    };
};
<commit_msg>Inline edit form - make event streams resilient to reload<commit_after>"use strict";

var $ = require('jquery'),
    Bacon = require('baconjs'),
    R = require('ramda'),
    BU = require('treemap/lib/baconUtils.js'),
    U = require('treemap/lib/utility.js'),
    _ = require('lodash'),
    FH = require('treemap/lib/fieldHelpers.js'),
    console = require('console-browserify'),
    editableForm = require('treemap/lib/editableForm.js'),

    eventsLandingInEditMode = [editableForm.editStartAction, 'save:start', 'save:error'],
    eventsLandingInDisplayMode = ['idle', 'save:ok', 'cancel'];

exports.init = function(options) {
    var updateUrl = options.updateUrl,
        section = options.section || 'body',
        form = options.form || section + ' form',
        $section = $(section),
        edit = options.edit || '.editBtn',
        save = options.save || '.saveBtn',
        cancel = options.cancel || '.cancelBtn',
        spinner = options.spinner || '.spinner',
        displayFields = options.displayFields || section + ' [data-class="display"]',
        editFields = options.editFields || section + ' [data-class="edit"]',
        validationFields = options.validationFields || section + ' [data-class="error"]',
        globalErrorSection = options.globalErrorSection,
        errorCallback = options.errorCallback || $.noop,
        onSaveAfter = options.onSaveAfter || _.identity,

        showSavePending = function (saveIsPending) {
            $section.find(spinner).toggle(saveIsPending);
            $section.find(save).prop('disabled', saveIsPending);
            $section.find(cancel).prop('disabled', saveIsPending);
        },

        editStream = $section.asEventStream('click', edit).map(editableForm.editStartAction),
        saveStream = (options.saveStream || $section.asEventStream('click', save))
            .doAction(showSavePending, true)
            .map('save:start'),
        externalCancelStream = BU.triggeredObjectStream('cancel'),
        cancelStream = $section.asEventStream('click', cancel).map('cancel'),
        globalCancelStream = cancelStream.merge(externalCancelStream),

        actionStream = new Bacon.Bus(),

        editForm = editableForm.init(options),

        logError = function(error) {
            console.error("Error uploading to " + updateUrl, error);
        },

        resetCollectionUdfs = function() {
            // Hide the edit row
            $("table[data-udf-id] .editrow").hide();

            // If there are no 'data' rows on a given table
            // hide the header and show the placeholder
            $("table[data-udf-id]").map(function() {
                var $table = $(this);

                // If the table has 3 rows they are:
                //
                // header, edit row (hidden), placeholder row (hidden)
                //
                // This means there is no user data, so
                // show the placeholder and hide the header
                if ($table.find('tr').length === 3) {
                    $table.find('.placeholder').show();
                    $table.find('.headerrow').hide();
                } else {
                    // We have some data rows so show the header
                    // and not the placeholder
                    $table.find('.placeholder').hide();
                    $table.find('.headerrow').show();
                }
            });
        },

        showCollectionUdfs = function() {
            // By default collection udfs have their input row
            // hidden, so show that row
            $("table[data-udf-id] .editrow").css('display', '');

            // The header row may also be hidden if there are no
            // items so show that as well
            $("table[data-udf-id] .headerrow").css('display', '');

            $("table[data-udf-id] .placeholder").css('display', 'none');
        },

        getDataToSave = function() {
            var data = FH.formToDictionary($(form), $(editFields), $(displayFields));

            // Extract data for all rows of the collection,
            // whether entered in this session or pre-existing.
            $('table[data-udf-name]').map(function() {
                var $table = $(this);
                var name = $table.data('udf-name');

                var headers = $table.find('tr.headerrow th')
                        .map(function() {
                            return $(this).html();
                        });

                headers = _.compact(headers);

                data[name] =
                    _.map($table.find('tr[data-value-id]').toArray(), function(row) {
                        var $row = $(row),
                            $tds = $row.find('td'),
                            id = $row.attr('data-value-id'),

                            rowData = _.object(headers, $tds
                                        .map(function() {
                                            return $.trim($(this).attr('data-value'));
                                        }));
                        if (! _.isEmpty(id)) {
                            rowData.id = id;
                        }
                        return rowData;
                    });
            });

            return data;
        },

        showGlobalErrors = function (errors) {
            var $globalErrorSection = $(globalErrorSection);

            if ($globalErrorSection.length > 0) {
                $globalErrorSection.html(errors.join(','));
                $globalErrorSection.show();
            } else {
                console.log('Global error returned from server, ' +
                            'but no dom element bound from client.',
                            errors);
            }
        },

        showValidationErrorsInline = function (errors) {
            $(validationFields).not(globalErrorSection).each(function() {
                $(this).html('');
            });
            _.each(errors, function (errorList, fieldName) {
                var $field = FH.getField($(validationFields), fieldName);

                if ($field.length > 0) {
                    $field.html(errorList.join(','));
                    $field.show();
                } else {
                    console.log('Field error returned from server, ' +
                                'but no dom element bound from client.',
                                fieldName, errorList);
                }
            });
        },

        isEditStart = function (action) {
            return action === 'edit:start';
        },

        responseStream = saveStream
            .map(getDataToSave)
            .flatMapLatest(function (data) {
                // onSaveBefore is a function that takes form data
                // and carries out arbitrary, potentially blocking
                // actions before allowing the save process to
                // continue.
                //
                // the return value of an onSaveBefore callback can be:
                // * null - for non-blocking side effects and mutation
                //          of the data object
                // * an eventStream - for blocking side effects,
                //                    failure cases and early exits.
                //
                // when providing an eventStream as the return value for
                // onSaveBefore, it should meet the following criteria:
                // * it should be a stream of data objects. If you are using
                //   eventStreams to block on IO, map them to the `data`
                //   object provided.
                // * it should pust a new stream value when it's ok to
                //   proceed and block until then. There is no concept
                //   of exiting, just failing to stop blocking.
                var result = options.onSaveBefore ?
                        options.onSaveBefore(data) : null;
                if (_.isNull(result) || _.isUndefined(result)) {
                    return Bacon.once(data);
                } else if (_.isObject(result) && result.hasOwnProperty('takeUntil')) {
                    return result;
                } else {
                    throw "onSaveBefore returned something other than a stream or null";
                }
            })
            .flatMap(function(data) {
                return Bacon.fromPromise($.ajax({
                    url: updateUrl,
                    type: 'PUT',
                    contentType: "application/json",
                    data: JSON.stringify(data)
                }));
            }),

        responseErrorStream = responseStream
            .errors()
            .mapError(function (e) {
                showSavePending(false);
                var result = ('responseJSON' in e) ? e.responseJSON : {};
                if ('error' in result) {
                    U.warnDeprecatedErrorMessage(result);
                    result.unstructuredError = result.error;
                }
                if (!('unstructuredError' in result)) {
                    // Make sure there's an 'unstructuredError' property
                    // we look for it in the stream that responds to this.
                    // Give it the error object to help with debugging.
                    result.unstructuredError = e;
                }
                return result;
            }),

        saveOkStream = responseStream.map(function(responseData) {
            showSavePending(false);
            return {
                formData: getDataToSave(),
                responseData: responseData
            };
        }),

        validationErrorsStream = responseErrorStream
            .filter('.fieldErrors')
            .map('.fieldErrors'),

        globalErrorsStream = responseErrorStream
            .filter('.globalErrors')
            .map('.globalErrors'),

        unhandledErrorStream = responseErrorStream
            .filter(R.and(BU.isPropertyUndefined('fieldErrors'),
                          BU.isPropertyUndefined('globalErrors')))
            .map('.unstructuredError'),

        editStartStream = actionStream.filter(isEditStart),

        inEditModeProperty = actionStream.map(function (event) {
            return _.contains(eventsLandingInEditMode, event);
        })
            .toProperty()
            .skipDuplicates(),

        saveOKFormDataStream = saveOkStream.map('.formData'),

        eventsLandingInDisplayModeStream =
            actionStream.filter(_.contains, eventsLandingInDisplayMode),

        shouldBeInEditModeStream = options.shouldBeInEditModeStream || Bacon.never(),
        modeChangeStream = shouldBeInEditModeStream
            .map(function(isInEdit) {
                return isInEdit ? 'edit:start' : 'cancel';
            });

    // Prevent default form submission from clicking on buttons or pressing
    // enter. Event is delegated on window since sometimes <form>s are inserted
    // into the page via AJAX without reiniting inlineEditForm
    $(window).on('submit', form, function(event) { event.preventDefault(); });

    // Merge the major streams on the page together so that it can centrally
    // manage the cleanup of ui forms after the change in run mode
    actionStream.plug(editStream);
    actionStream.plug(saveStream);
    actionStream.plug(cancelStream);
    actionStream.plug(externalCancelStream);
    actionStream.plug(saveOkStream.map('save:ok'));
    actionStream.plug(responseErrorStream.map('save:error'));
    actionStream.plug(modeChangeStream);
    actionStream.onValue(editForm.hideAndShowElements, editFields, eventsLandingInEditMode);
    actionStream.onValue(editForm.hideAndShowElements, displayFields, eventsLandingInDisplayMode);
    actionStream.onValue(editForm.hideAndShowElements, validationFields, ['save:error']);

    responseStream.onValue(onSaveAfter);

    globalCancelStream.onValue(showSavePending, false);

    saveOKFormDataStream.onValue(editForm.formFieldsToDisplayValues);

    globalErrorsStream.onValue(showGlobalErrors);
    validationErrorsStream.onValue(showValidationErrorsInline);

    unhandledErrorStream.onValue(errorCallback);
    unhandledErrorStream.onValue(logError);

    editStartStream.onValue(editForm.displayValuesToFormFields);
    editStartStream.onValue(showCollectionUdfs);

    eventsLandingInDisplayModeStream.onValue(resetCollectionUdfs);

    return {
        // immutable access to all actions
        actionStream: actionStream.map(_.identity),
        cancel: externalCancelStream.trigger,
        saveOkStream: saveOkStream,
        // TODO: audit all uses of cancelStream, external cancel, and
        // global cancel stream and merge these streams in the api
        cancelStream: cancelStream,
        globalCancelStream: globalCancelStream,
        inEditModeProperty: inEditModeProperty,
        showGlobalErrors: showGlobalErrors,
        showValidationErrorsInline: showValidationErrorsInline,
        setUpdateUrl: function (url) { updateUrl = url; }
    };
};
<|endoftext|>


<commit_before>const versioning = require('../../../../versioning');
const { getRollbackUpdate } = require('./rollback');
const { getRangeStrategy } = require('../../../../manager');
const { filterVersions } = require('./filter');
const {
  getPkgReleases,
  supportsDigests,
  getDigest,
} = require('../../../../datasource');

module.exports = {
  lookupUpdates,
};

async function lookupUpdates(config) {
  const { depName, currentValue, lockedVersion } = config;
  logger.trace({ dependency: depName, currentValue }, 'lookupUpdates');
  const {
    equals,
    getMajor,
    getMinor,
    isGreaterThan,
    isSingleVersion,
    isCompatible,
    isValid,
    isVersion,
    matches,
    getNewValue,
    valueToVersion,
  } = versioning.get(config.versionScheme);
  const res = { updates: [], warnings: [] };
  if (isValid(currentValue)) {
    const dependency = await getPkgReleases(config);
    if (!dependency) {
      // If dependency lookup fails then warn and return
      const result = {
        updateType: 'warning',
        message: `Failed to look up dependency ${depName}`,
      };
      logger.info(
        { dependency: depName, packageFile: config.packageFile },
        result.message
      );
      // TODO: return warnings in own field
      res.warnings.push(result);
      return res;
    }
    // istanbul ignore if
    if (dependency.deprecationMessage) {
      logger.info({ dependency: depName }, 'Found deprecationMessage');
      res.deprecationMessage = dependency.deprecationMessage;
    }
    res.sourceUrl =
      dependency.sourceUrl && dependency.sourceUrl.length
        ? dependency.sourceUrl
        : null;
    res.homepage = dependency.homepage;
    res.changelogUrl = dependency.changelogUrl;
    const { releases } = dependency;
    // Filter out any results from datasource that don't comply with our versioning scheme
    let allVersions = releases
      .map(release => release.version)
      .filter(v => isVersion(v));
    // istanbul ignore if
    if (allVersions.length === 0) {
      const message = `No valid versions returned from registry for this package`;
      logger.debug({ dependency: depName, result: dependency }, message);
      if (!config.currentDigest) {
        return res;
      }
    }
    if (config.followTag) {
      const taggedVersion = dependency.tags[config.followTag];
      if (!taggedVersion) {
        res.warnings.push({
          updateType: 'warning',
          message: `Can't find version with tag ${
            config.followTag
          } for ${depName}`,
        });
        return res;
      }
      allVersions = allVersions.filter(
        v =>
          v === taggedVersion ||
          (v === currentValue && isGreaterThan(taggedVersion, currentValue))
      );
    }
    // Check that existing constraint can be satisfied
    const allSatisfyingVersions = allVersions.filter(version =>
      matches(version, currentValue)
    );
    if (config.rollbackPrs && !allSatisfyingVersions.length) {
      const rollback = getRollbackUpdate(config, allVersions);
      // istanbul ignore if
      if (!rollback) {
        res.warnings.push([
          {
            updateType: 'warning',
            message: `Can't find version matching ${currentValue} for ${depName}`,
          },
        ]);
        return res;
      }
      res.updates.push(rollback);
    }
    const rangeStrategy = getRangeStrategy(config);
    const fromVersion = getFromVersion(config, rangeStrategy, allVersions);
    if (
      fromVersion &&
      rangeStrategy === 'pin' &&
      !isSingleVersion(currentValue)
    ) {
      res.updates.push({
        updateType: 'pin',
        isPin: true,
        newValue: getNewValue(
          currentValue,
          rangeStrategy,
          fromVersion,
          fromVersion
        ),
        newMajor: getMajor(fromVersion),
      });
    }
    let filterStart = fromVersion;
    if (lockedVersion && rangeStrategy === 'lockfile-update') {
      // Look for versions greater than the current locked version that still satisfy the package.json range
      filterStart = lockedVersion;
    }
    // Filter latest, unstable, etc
    const filteredVersions = filterVersions(
      config,
      filterStart,
      dependency.latestVersion,
      allVersions,
      releases
    ).filter(version =>
      // Leave only compatible versions
      isCompatible(version, currentValue)
    );
    const buckets = {};
    for (const toVersion of filteredVersions) {
      const update = { fromVersion, toVersion };
      update.newValue = getNewValue(
        currentValue,
        rangeStrategy,
        fromVersion,
        toVersion
      );
      if (!update.newValue || update.newValue === currentValue) {
        if (!config.lockedVersion) {
          continue; // eslint-disable-line no-continue
        }
        update.updateType = 'lockfileUpdate';
        update.fromVersion = lockedVersion;
        update.displayFrom = lockedVersion;
        update.displayTo = toVersion;
        update.isSingleVersion = true;
      }
      update.newMajor = getMajor(toVersion);
      update.newMinor = getMinor(toVersion);
      update.updateType =
        update.updateType || getType(config, update.fromVersion, toVersion);
      update.isSingleVersion =
        update.isSingleVersion || !!isSingleVersion(update.newValue);
      if (!isVersion(update.newValue)) {
        update.isRange = true;
      }
      const updateRelease = releases.find(release =>
        equals(release.version, toVersion)
      );
      // TODO: think more about whether to just Object.assign this
      const releaseFields = [
        'releaseTimestamp',
        'canBeUnpublished',
        'downloadUrl',
        'checksumUrl',
      ];
      releaseFields.forEach(field => {
        if (updateRelease[field] !== undefined) {
          update[field] = updateRelease[field];
        }
      });

      const bucket = getBucket(config, update);
      if (buckets[bucket]) {
        if (isGreaterThan(update.toVersion, buckets[bucket].toVersion)) {
          buckets[bucket] = update;
        }
      } else {
        buckets[bucket] = update;
      }
    }
    res.updates = res.updates.concat(Object.values(buckets));
    res.releases = releases.filter(
      release =>
        filteredVersions.length &&
        (filteredVersions.includes(release.version) ||
          release.version === filterStart)
    );
  } else if (!currentValue) {
    res.skipReason = 'unsupported-value';
  } else {
    logger.debug(`Dependency ${depName} has unsupported value ${currentValue}`);
    if (!config.pinDigests && !config.currentDigest) {
      res.skipReason = 'unsupported-value';
    }
  }
  // Add digests if necessary
  if (supportsDigests(config)) {
    if (config.currentDigest) {
      if (!config.digestOneAndOnly || !res.updates.length) {
        // digest update
        res.updates.push({
          updateType: 'digest',
          newValue: config.currentValue,
        });
      }
    } else if (config.pinDigests) {
      // Create a pin only if one doesn't already exists
      if (!res.updates.some(update => update.updateType === 'pin')) {
        // pin digest
        res.updates.push({
          updateType: 'pin',
          newValue: config.currentValue,
        });
      }
    }
    if (valueToVersion) {
      for (const release of res.releases || []) {
        release.version = valueToVersion(release.version);
      }
      for (const update of res.updates || []) {
        update.newVersion = valueToVersion(update.newValue);
        update.fromVersion = valueToVersion(update.fromVersion);
        update.toVersion = valueToVersion(update.toVersion);
      }
    }
    // update digest for all
    for (const update of res.updates) {
      if (config.pinDigests || config.currentDigest) {
        update.newDigest = await getDigest(config, update.newValue);
        if (update.newDigest) {
          update.newDigestShort = update.newDigest
            .replace('sha256:', '')
            .substring(0, 7);
        } else {
          logger.info({ newValue: update.newValue }, 'Could not getDigest');
        }
      }
    }
  }
  for (const update of res.updates) {
    const { updateType, fromVersion, toVersion } = update;
    if (['bump', 'lockfileUpdate'].includes(updateType)) {
      update[updateType === 'bump' ? 'isBump' : 'isLockfileUpdate'] = true;
      if (getMajor(toVersion) > getMajor(fromVersion)) {
        update.updateType = 'major';
      } else if (
        config.separateMinorPatch &&
        getMinor(toVersion) === getMinor(fromVersion)
      ) {
        update.updateType = 'patch';
      } else {
        update.updateType = 'minor';
      }
    }
  }
  // Strip out any non-changed ones
  res.updates = res.updates
    .filter(update => update.newDigest !== null)
    .filter(
      update =>
        update.newValue !== config.currentValue ||
        update.isLockfileUpdate ||
        (update.newDigest && !update.newDigest.startsWith(config.currentDigest))
    );
  if (res.updates.some(update => update.updateType === 'pin')) {
    for (const update of res.updates) {
      if (update.updateType !== 'pin' && update.updateType !== 'rollback') {
        update.blockedByPin = true;
      }
    }
  }
  return res;
}

function getType(config, fromVersion, toVersion) {
  const { versionScheme, rangeStrategy, currentValue } = config;
  const { getMajor, getMinor, matches } = versioning.get(versionScheme);
  if (rangeStrategy === 'bump' && matches(toVersion, currentValue)) {
    return 'bump';
  }
  if (getMajor(toVersion) > getMajor(fromVersion)) {
    return 'major';
  }
  if (getMinor(toVersion) > getMinor(fromVersion)) {
    return 'minor';
  }
  if (config.separateMinorPatch) {
    return 'patch';
  }
  if (config.patch.automerge && !config.minor.automerge) {
    return 'patch';
  }
  return 'minor';
}

function getBucket(config, update) {
  const { separateMajorMinor, separateMultipleMajor } = config;
  const { updateType, newMajor } = update;
  if (updateType === 'lockfileUpdate') {
    return updateType;
  }
  if (
    !separateMajorMinor ||
    config.major.automerge === true ||
    (config.automerge && config.major.automerge !== false)
  ) {
    return 'latest';
  }
  if (separateMultipleMajor && updateType === 'major') {
    return `major-${newMajor}`;
  }
  return updateType;
}

function getFromVersion(config, rangeStrategy, allVersions) {
  const { currentValue, lockedVersion, versionScheme } = config;
  const {
    isVersion,
    maxSatisfyingVersion,
    minSatisfyingVersion,
  } = versioning.get(versionScheme);
  if (isVersion(currentValue)) {
    return currentValue;
  }
  logger.trace(`currentValue ${currentValue} is range`);
  if (rangeStrategy === 'pin') {
    return lockedVersion || maxSatisfyingVersion(allVersions, currentValue);
  }
  if (rangeStrategy === 'bump') {
    // Use the lowest version in the current range
    return minSatisfyingVersion(allVersions, currentValue);
  }
  // Use the highest version in the current range
  return maxSatisfyingVersion(allVersions, currentValue);
}
<commit_msg>fix: copy dockerRegistry and dockerRepository<commit_after>const versioning = require('../../../../versioning');
const { getRollbackUpdate } = require('./rollback');
const { getRangeStrategy } = require('../../../../manager');
const { filterVersions } = require('./filter');
const {
  getPkgReleases,
  supportsDigests,
  getDigest,
} = require('../../../../datasource');

module.exports = {
  lookupUpdates,
};

async function lookupUpdates(config) {
  const { depName, currentValue, lockedVersion } = config;
  logger.trace({ dependency: depName, currentValue }, 'lookupUpdates');
  const {
    equals,
    getMajor,
    getMinor,
    isGreaterThan,
    isSingleVersion,
    isCompatible,
    isValid,
    isVersion,
    matches,
    getNewValue,
    valueToVersion,
  } = versioning.get(config.versionScheme);
  const res = { updates: [], warnings: [] };
  if (isValid(currentValue)) {
    const dependency = await getPkgReleases(config);
    if (!dependency) {
      // If dependency lookup fails then warn and return
      const result = {
        updateType: 'warning',
        message: `Failed to look up dependency ${depName}`,
      };
      logger.info(
        { dependency: depName, packageFile: config.packageFile },
        result.message
      );
      // TODO: return warnings in own field
      res.warnings.push(result);
      return res;
    }
    // istanbul ignore if
    if (dependency.deprecationMessage) {
      logger.info({ dependency: depName }, 'Found deprecationMessage');
      res.deprecationMessage = dependency.deprecationMessage;
    }
    res.sourceUrl =
      dependency.sourceUrl && dependency.sourceUrl.length
        ? dependency.sourceUrl
        : null;
    res.homepage = dependency.homepage;
    res.changelogUrl = dependency.changelogUrl;
    // TODO: improve this
    // istanbul ignore if
    if (dependency.dockerRegistry) {
      res.dockerRegistry = dependency.dockerRegistry;
      res.dockerRepository = dependency.dockerRespository;
    }
    const { releases } = dependency;
    // Filter out any results from datasource that don't comply with our versioning scheme
    let allVersions = releases
      .map(release => release.version)
      .filter(v => isVersion(v));
    // istanbul ignore if
    if (allVersions.length === 0) {
      const message = `No valid versions returned from registry for this package`;
      logger.debug({ dependency: depName, result: dependency }, message);
      if (!config.currentDigest) {
        return res;
      }
    }
    if (config.followTag) {
      const taggedVersion = dependency.tags[config.followTag];
      if (!taggedVersion) {
        res.warnings.push({
          updateType: 'warning',
          message: `Can't find version with tag ${
            config.followTag
          } for ${depName}`,
        });
        return res;
      }
      allVersions = allVersions.filter(
        v =>
          v === taggedVersion ||
          (v === currentValue && isGreaterThan(taggedVersion, currentValue))
      );
    }
    // Check that existing constraint can be satisfied
    const allSatisfyingVersions = allVersions.filter(version =>
      matches(version, currentValue)
    );
    if (config.rollbackPrs && !allSatisfyingVersions.length) {
      const rollback = getRollbackUpdate(config, allVersions);
      // istanbul ignore if
      if (!rollback) {
        res.warnings.push([
          {
            updateType: 'warning',
            message: `Can't find version matching ${currentValue} for ${depName}`,
          },
        ]);
        return res;
      }
      res.updates.push(rollback);
    }
    const rangeStrategy = getRangeStrategy(config);
    const fromVersion = getFromVersion(config, rangeStrategy, allVersions);
    if (
      fromVersion &&
      rangeStrategy === 'pin' &&
      !isSingleVersion(currentValue)
    ) {
      res.updates.push({
        updateType: 'pin',
        isPin: true,
        newValue: getNewValue(
          currentValue,
          rangeStrategy,
          fromVersion,
          fromVersion
        ),
        newMajor: getMajor(fromVersion),
      });
    }
    let filterStart = fromVersion;
    if (lockedVersion && rangeStrategy === 'lockfile-update') {
      // Look for versions greater than the current locked version that still satisfy the package.json range
      filterStart = lockedVersion;
    }
    // Filter latest, unstable, etc
    const filteredVersions = filterVersions(
      config,
      filterStart,
      dependency.latestVersion,
      allVersions,
      releases
    ).filter(version =>
      // Leave only compatible versions
      isCompatible(version, currentValue)
    );
    const buckets = {};
    for (const toVersion of filteredVersions) {
      const update = { fromVersion, toVersion };
      update.newValue = getNewValue(
        currentValue,
        rangeStrategy,
        fromVersion,
        toVersion
      );
      if (!update.newValue || update.newValue === currentValue) {
        if (!config.lockedVersion) {
          continue; // eslint-disable-line no-continue
        }
        update.updateType = 'lockfileUpdate';
        update.fromVersion = lockedVersion;
        update.displayFrom = lockedVersion;
        update.displayTo = toVersion;
        update.isSingleVersion = true;
      }
      update.newMajor = getMajor(toVersion);
      update.newMinor = getMinor(toVersion);
      update.updateType =
        update.updateType || getType(config, update.fromVersion, toVersion);
      update.isSingleVersion =
        update.isSingleVersion || !!isSingleVersion(update.newValue);
      if (!isVersion(update.newValue)) {
        update.isRange = true;
      }
      const updateRelease = releases.find(release =>
        equals(release.version, toVersion)
      );
      // TODO: think more about whether to just Object.assign this
      const releaseFields = [
        'releaseTimestamp',
        'canBeUnpublished',
        'downloadUrl',
        'checksumUrl',
      ];
      releaseFields.forEach(field => {
        if (updateRelease[field] !== undefined) {
          update[field] = updateRelease[field];
        }
      });

      const bucket = getBucket(config, update);
      if (buckets[bucket]) {
        if (isGreaterThan(update.toVersion, buckets[bucket].toVersion)) {
          buckets[bucket] = update;
        }
      } else {
        buckets[bucket] = update;
      }
    }
    res.updates = res.updates.concat(Object.values(buckets));
    res.releases = releases.filter(
      release =>
        filteredVersions.length &&
        (filteredVersions.includes(release.version) ||
          release.version === filterStart)
    );
  } else if (!currentValue) {
    res.skipReason = 'unsupported-value';
  } else {
    logger.debug(`Dependency ${depName} has unsupported value ${currentValue}`);
    if (!config.pinDigests && !config.currentDigest) {
      res.skipReason = 'unsupported-value';
    }
  }
  // Add digests if necessary
  if (supportsDigests(config)) {
    if (config.currentDigest) {
      if (!config.digestOneAndOnly || !res.updates.length) {
        // digest update
        res.updates.push({
          updateType: 'digest',
          newValue: config.currentValue,
        });
      }
    } else if (config.pinDigests) {
      // Create a pin only if one doesn't already exists
      if (!res.updates.some(update => update.updateType === 'pin')) {
        // pin digest
        res.updates.push({
          updateType: 'pin',
          newValue: config.currentValue,
        });
      }
    }
    if (valueToVersion) {
      for (const release of res.releases || []) {
        release.version = valueToVersion(release.version);
      }
      for (const update of res.updates || []) {
        update.newVersion = valueToVersion(update.newValue);
        update.fromVersion = valueToVersion(update.fromVersion);
        update.toVersion = valueToVersion(update.toVersion);
      }
    }
    // update digest for all
    for (const update of res.updates) {
      if (config.pinDigests || config.currentDigest) {
        update.newDigest = await getDigest(config, update.newValue);
        if (update.newDigest) {
          update.newDigestShort = update.newDigest
            .replace('sha256:', '')
            .substring(0, 7);
        } else {
          logger.info({ newValue: update.newValue }, 'Could not getDigest');
        }
      }
    }
  }
  for (const update of res.updates) {
    const { updateType, fromVersion, toVersion } = update;
    if (['bump', 'lockfileUpdate'].includes(updateType)) {
      update[updateType === 'bump' ? 'isBump' : 'isLockfileUpdate'] = true;
      if (getMajor(toVersion) > getMajor(fromVersion)) {
        update.updateType = 'major';
      } else if (
        config.separateMinorPatch &&
        getMinor(toVersion) === getMinor(fromVersion)
      ) {
        update.updateType = 'patch';
      } else {
        update.updateType = 'minor';
      }
    }
  }
  // Strip out any non-changed ones
  res.updates = res.updates
    .filter(update => update.newDigest !== null)
    .filter(
      update =>
        update.newValue !== config.currentValue ||
        update.isLockfileUpdate ||
        (update.newDigest && !update.newDigest.startsWith(config.currentDigest))
    );
  if (res.updates.some(update => update.updateType === 'pin')) {
    for (const update of res.updates) {
      if (update.updateType !== 'pin' && update.updateType !== 'rollback') {
        update.blockedByPin = true;
      }
    }
  }
  return res;
}

function getType(config, fromVersion, toVersion) {
  const { versionScheme, rangeStrategy, currentValue } = config;
  const { getMajor, getMinor, matches } = versioning.get(versionScheme);
  if (rangeStrategy === 'bump' && matches(toVersion, currentValue)) {
    return 'bump';
  }
  if (getMajor(toVersion) > getMajor(fromVersion)) {
    return 'major';
  }
  if (getMinor(toVersion) > getMinor(fromVersion)) {
    return 'minor';
  }
  if (config.separateMinorPatch) {
    return 'patch';
  }
  if (config.patch.automerge && !config.minor.automerge) {
    return 'patch';
  }
  return 'minor';
}

function getBucket(config, update) {
  const { separateMajorMinor, separateMultipleMajor } = config;
  const { updateType, newMajor } = update;
  if (updateType === 'lockfileUpdate') {
    return updateType;
  }
  if (
    !separateMajorMinor ||
    config.major.automerge === true ||
    (config.automerge && config.major.automerge !== false)
  ) {
    return 'latest';
  }
  if (separateMultipleMajor && updateType === 'major') {
    return `major-${newMajor}`;
  }
  return updateType;
}

function getFromVersion(config, rangeStrategy, allVersions) {
  const { currentValue, lockedVersion, versionScheme } = config;
  const {
    isVersion,
    maxSatisfyingVersion,
    minSatisfyingVersion,
  } = versioning.get(versionScheme);
  if (isVersion(currentValue)) {
    return currentValue;
  }
  logger.trace(`currentValue ${currentValue} is range`);
  if (rangeStrategy === 'pin') {
    return lockedVersion || maxSatisfyingVersion(allVersions, currentValue);
  }
  if (rangeStrategy === 'bump') {
    // Use the lowest version in the current range
    return minSatisfyingVersion(allVersions, currentValue);
  }
  // Use the highest version in the current range
  return maxSatisfyingVersion(allVersions, currentValue);
}
<|endoftext|>


<commit_before>$(document).ready(function () {
    $('.choose-pricing button').on('click', function () {
        var target = $(this).attr('data-target');
        $(target).attr('value', $(this).text());

    });
    $('.choose-pricing input.form-control').change(function() {
        var target = $(this).attr('data-target');
        $(target).attr('value', $(this).val());
    });
    $(document).on('submit', '#donate-form', function(event) {
        $.pjax.submit(event, '#pjax-container');
    })
});

$(".donationbtn-group .btn, .donationbtn-group .inpt-first").click(
function changeActiveButtonForDonationAmount(){
    var btngroup = $(this).parent();
    var activeButton = $(this);
    var valueKeeper = $('#' + btngroup.attr('id') + ' .valueKeeper')

    $('#' + btngroup.attr('id') + ' .btn').removeClass('active');
    $('#' + btngroup.attr('id') + ' .inpt-first').removeClass('active');
    activeButton.addClass('active');

    function activateDonateButton() {
        $('#donate-submit').removeAttr('disabled');
    }

    function deactivateDonateButton() {
        $('#donate-submit').prop('disabled', true);
    }

    if (parseInt($(this).text()) > 0) {
        activateDonateButton();
    } else {
        deactivateDonateButton();
    }

    if($(this).hasClass('inpt-first')) {
        if($(this).val() === ''){
            // Custom Field is empty
            valueKeeper.val('0');
        }
    }
});<commit_msg>If clicked twice on button it deactivates<commit_after>$(document).ready(function () {
    $('.choose-pricing button').on('click', function () {
        var target = $(this).attr('data-target');
        $(target).attr('value', $(this).text());

    });
    $('.choose-pricing input.form-control').change(function() {
        var target = $(this).attr('data-target');
        $(target).attr('value', $(this).val());
    });
    $(document).on('submit', '#donate-form', function(event) {
        $.pjax.submit(event, '#pjax-container');
    })
});

$(".donationbtn-group .btn, .donationbtn-group .inpt-first").click(
function changeActiveButtonForDonationAmount(){
    var btngroup = $(this).parent();
    var activeButton = $(this);
    var valueKeeper = $('#' + btngroup.attr('id') + ' .valueKeeper')

    $('#' + btngroup.attr('id') + ' .btn').removeClass('active');
    $('#' + btngroup.attr('id') + ' .inpt-first').removeClass('active');
    activeButton.addClass('active');

    function activateDonateButton() {
        $('#donate-submit').removeAttr('disabled');
    }

    function deactivateDonateButton() {
        $('#donate-submit').prop('disabled', true);
    }

    function resetToZeroDonations() {
        activeButton.removeClass('active');
        valueKeeper.val('0');
    }

    if (parseInt($(this).text()) > 0) {
        activateDonateButton();
    } else {
        deactivateDonateButton();
    }

    if ($(this).text() === valueKeeper.val()) {
        resetToZeroDonations();
    }

    if($(this).hasClass('inpt-first')) {
        if($(this).val() === ''){
            // Custom Field is empty
            valueKeeper.val('0');
        }
    }
});<|endoftext|>