<commit_before>import {expect} from 'chai'
import {$hook} from 'ember-hook'
import wait from 'ember-test-helpers/wait'
import {beforeEach, describe, it} from 'mocha'

import {
  expectBunsenWhenRendererWithState,
  expectClockpickerBunsenDatetimeRenderer,
  expectCollapsibleHandles,
  expectInputsBunsenWhenRenderer,
  expectOnChangeStateDatetime,
  expectOnValidationState,
  openDatepickerBunsenDatetimeRenderer,
  selectRadioButtonBunsenWhenRenderer
} from 'dummy/tests/helpers/ember-frost-bunsen'

import {setupFormComponentTest} from 'dummy/tests/helpers/utils'

/**
 * Click outside the date picker to close it
 * @param {Object} context - the test context
 */
function closePikaday (context) {
  context.$().click()
}

describe('Integration: Component / frost-bunsen-form / renderer / when', function () {
  const ctx = setupFormComponentTest({
    bunsenModel: {
      properties: {
        foo: {
          type: 'string'
        }
      },
      type: 'object'
    },
    bunsenView: {
      cells: [
        {
          children: [
            {
              model: 'foo',
              renderer: {
                name: 'when',
                value: 'RIGHT_NOW'
              }
            }
          ]
        }
      ],
      type: 'form',
      version: '2.0'
    }
  })

  it('renders as expected', function () {
    expectCollapsibleHandles(0)
    expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
    expectOnValidationState(ctx, {count: 2})
  })

  it('should have an input for date and time', function () {
    expectInputsBunsenWhenRenderer()
  })

  describe('when label defined in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            label: 'FooBar Baz',
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'FooBar Baz'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when collapsible set to true in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            collapsible: true,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(1)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when collapsible set to false in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            collapsible: false,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when hideLabel is set to true in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            hideLabel: true,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: null})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when hideLabel is set to false in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            hideLabel: false,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when render.label defined in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              label: 'BarBaz',
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        firstButtonLabel: 'BarBaz'
      })
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when user clicks second radio button', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    describe('when nothing is set', function () {
      beforeEach(function () {
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})
      })

      it('enables the date-time-picker', function () {
        expectCollapsibleHandles(0)
        expectBunsenWhenRendererWithState('foo', {
          label: 'Foo',
          selectedButton: 'second'
        })
        expectOnValidationState(ctx, {count: 3})
      })
    })

    describe('when date is set', function () {
      beforeEach(function () {
        ctx.props.onValidation.reset()
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})
        const interactor = openDatepickerBunsenDatetimeRenderer('bunsenForm-foo-radio-button-date-picker-input')
        interactor.selectDate(new Date(2017, 0, 24))
        closePikaday(this)

        return wait()
      })

      it('functions as expected', function () {
        expectCollapsibleHandles(0)
        expectOnChangeStateDatetime(ctx, {foo: '2017-01-24'})
        expectOnValidationState(ctx, {count: 3})
      })
    })

    describe('when time is set', function () {
      beforeEach(function () {
        ctx.props.onValidation.reset()
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})

        return wait()
      })

      it('functions as expected', function () {
        expectClockpickerBunsenDatetimeRenderer('bunsenForm-foo-radio-button-time-picker-input')
      })
    })
  })

  describe('when user leaves second radio button and clicks first', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})

      return wait()
    })

    it('enables the date-time-picker', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        selectedButton: 'second'
      })
    })

    describe('when user clicks first', function () {
      beforeEach(function () {
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 1})
      })

      it('disables the date-time-picker', function () {
        expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
        expectOnValidationState(ctx, {count: 4})
      })
    })
  })

  describe('when property renderer.label in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              label: 'Test',
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        firstButtonLabel: 'Test'
      })
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when property renderer.size in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              size: 'medium',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        size: 'medium'
      })
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when property renderer.dateFormat in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              dateFormat: 'YYYY MM DD',
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders using provided dateFormat', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      const dateValue = $hook('bunsenForm-foo-radio-button-date-picker-input').val()
      const dateTest = /^\d{4}\s\d\d\s\d\d$/.test(dateValue)
      expect(dateTest).to.equal(true)
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when property renderer.timeFormat in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              timeFormat: 'HH:mm',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders using provided timeFormat', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      const timeFormat = $hook('bunsenForm-foo-radio-button-time-picker-input').val()
      const timeTest = /^\d\d:\d\d$/.test(timeFormat)
      expect(timeTest).to.equal(true)
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when REQUIRED property renderer.value in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders using provided value', function () {
      expect(
        $hook('bunsenForm-foo-radio-group-button-input', {value: 'RIGHT_NOW'}).val()
      ).to.equal('RIGHT_NOW')
    })
  })
})
<commit_msg>fix test in firefox<commit_after>import {expect} from 'chai'
import {$hook} from 'ember-hook'
import wait from 'ember-test-helpers/wait'
import {beforeEach, describe, it} from 'mocha'

import {
  expectBunsenWhenRendererWithState,
  expectClockpickerBunsenDatetimeRenderer,
  expectCollapsibleHandles,
  expectInputsBunsenWhenRenderer,
  expectOnChangeStateDatetime,
  expectOnValidationState,
  openDatepickerBunsenDatetimeRenderer,
  selectRadioButtonBunsenWhenRenderer
} from 'dummy/tests/helpers/ember-frost-bunsen'

import {setupFormComponentTest} from 'dummy/tests/helpers/utils'

/**
 * Click outside the date picker to close it
 * @param {Object} context - the test context
 */
function closePikaday (context) {
  context.$().click()
}

describe('Integration: Component / frost-bunsen-form / renderer / when', function () {
  const ctx = setupFormComponentTest({
    bunsenModel: {
      properties: {
        foo: {
          type: 'string'
        }
      },
      type: 'object'
    },
    bunsenView: {
      cells: [
        {
          children: [
            {
              model: 'foo',
              renderer: {
                name: 'when',
                value: 'RIGHT_NOW'
              }
            }
          ]
        }
      ],
      type: 'form',
      version: '2.0'
    }
  })

  it('renders as expected', function () {
    expectCollapsibleHandles(0)
    expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
    expectOnValidationState(ctx, {count: 2})
  })

  it('should have an input for date and time', function () {
    expectInputsBunsenWhenRenderer()
  })

  describe('when label defined in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            label: 'FooBar Baz',
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'FooBar Baz'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when collapsible set to true in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            collapsible: true,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(1)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when collapsible set to false in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            collapsible: false,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when hideLabel is set to true in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            hideLabel: true,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: null})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when hideLabel is set to false in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            hideLabel: false,
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when render.label defined in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              label: 'BarBaz',
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        firstButtonLabel: 'BarBaz'
      })
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when user clicks second radio button', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    describe('when nothing is set', function () {
      beforeEach(function () {
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})
      })

      it('enables the date-time-picker', function () {
        expectCollapsibleHandles(0)
        expectBunsenWhenRendererWithState('foo', {
          label: 'Foo',
          selectedButton: 'second'
        })
        expectOnValidationState(ctx, {count: 3})
      })
    })

    describe('when date is set', function () {
      beforeEach(function () {
        ctx.props.onValidation.reset()
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})

        return wait().then(() => {
          const interactor = openDatepickerBunsenDatetimeRenderer('bunsenForm-foo-radio-button-date-picker-input')
          interactor.selectDate(new Date(2017, 0, 24))
          closePikaday(this)
        })
      })

      it('functions as expected', function () {
        expectCollapsibleHandles(0)
        expectOnChangeStateDatetime(ctx, {foo: '2017-01-24'})
        expectOnValidationState(ctx, {count: 3})
      })
    })

    describe('when time is set', function () {
      beforeEach(function () {
        ctx.props.onValidation.reset()
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})

        return wait()
      })

      it('functions as expected', function () {
        expectClockpickerBunsenDatetimeRenderer('bunsenForm-foo-radio-button-time-picker-input')
      })
    })
  })

  describe('when user leaves second radio button and clicks first', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 2})

      return wait()
    })

    it('enables the date-time-picker', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        selectedButton: 'second'
      })
    })

    describe('when user clicks first', function () {
      beforeEach(function () {
        selectRadioButtonBunsenWhenRenderer('foo', {buttonNumber: 1})
      })

      it('disables the date-time-picker', function () {
        expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
        expectOnValidationState(ctx, {count: 4})
      })
    })
  })

  describe('when property renderer.label in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              label: 'Test',
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        firstButtonLabel: 'Test'
      })
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when property renderer.size in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              size: 'medium',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders as expected', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {
        label: 'Foo',
        size: 'medium'
      })
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when property renderer.dateFormat in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              dateFormat: 'YYYY MM DD',
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders using provided dateFormat', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      const dateValue = $hook('bunsenForm-foo-radio-button-date-picker-input').val()
      const dateTest = /^\d{4}\s\d\d\s\d\d$/.test(dateValue)
      expect(dateTest).to.equal(true)
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when property renderer.timeFormat in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              timeFormat: 'HH:mm',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders using provided timeFormat', function () {
      expectCollapsibleHandles(0)
      expectBunsenWhenRendererWithState('foo', {label: 'Foo'})
      const timeFormat = $hook('bunsenForm-foo-radio-button-time-picker-input').val()
      const timeTest = /^\d\d:\d\d$/.test(timeFormat)
      expect(timeTest).to.equal(true)
      expectOnValidationState(ctx, {count: 2})
    })
  })

  describe('when REQUIRED property renderer.value in view', function () {
    beforeEach(function () {
      this.set('bunsenView', {
        cells: [
          {
            model: 'foo',
            renderer: {
              name: 'when',
              value: 'RIGHT_NOW'
            }
          }
        ],
        type: 'form',
        version: '2.0'
      })

      return wait()
    })

    it('renders using provided value', function () {
      expect(
        $hook('bunsenForm-foo-radio-group-button-input', {value: 'RIGHT_NOW'}).val()
      ).to.equal('RIGHT_NOW')
    })
  })
})
<|endoftext|>


<commit_before>const refresh = require('./lib/refresh');
const bot = require('./bot.js');
const settings = require('./../settings.json');
const modules = require('./modules.js');
const Message = require('./../orm/Message')
const commands = require('./commands');
const request = require('request-promise-native');
let lock = false;
bot.on('error', (err) => {
    /**
     * Catch errors here
     */
    console.log("Stack Trace: " + err.stack);
})
process.on('unhandledRejection', (err) => {
    console.log("UNHANDLED REJECTION AT " + err.stack);
    if (err.toString().includes('Request to use token, but token was unavailable to the client'))
        process.exit();//restart
});
process.on('uncaughtException', (err) => console.log("UNHANDLED EXCEPTION AT " + err.stack));
bot.on('message', (message) => {
    /**
     * if locked, reject everything except dm
     */

    new Message({
        messageID: message.id,
        channel: message.channel.id
    }).save();
    if (message.author.bot) return;
    if (lock) {
        if (!settings.owners.includes(message.author.id))
            //  if (message.channel.guild)
            return;//not DM
    }
    /**
     * Listen to messages and convert into params
     */
    if (message.content.startsWith(settings.identifier)) {
        /**Extracting params */
        let params = message.content.substring(settings.identifier.length).trim();
        params = params.split(settings.delimiter || ' ');
        let cmd = params.shift().trim();
        commands.execute(cmd.toLowerCase(), params, message)
    }
    else if (message.isMentioned(bot.user)) {
        /**remove mentions and then get params */
        let params = message.cleancontent.trim().replace(bot.user.toString(), "").trim();
        params = params.split(settings.delimiter || ' ');
        let cmd = params.shift.trim();
        commands.execute(cmd.toLowerCase(), params, message)
    }
    else {
        //ignore because normal message
    }
});
bot.on('lock', () => { lock = true; });
bot.on('unlock', () => { lock = false; });
bot.on("guildMemberAdd", async function (member) {
    var user = member.user;
    if (member.guild.id === "184536578654339072") {
        if (member.user.bot) return console.log(member.user.tag + " is a bot who joined " + member.guild.name)
        user.send("Welcome to the Revive Network");
        if (! await refresh(user)) {
            await member.addRole(bot.guilds.get("184536578654339072").roles.get("317854639431221248"));
            const ma = await bot.channels.get("317859245309689856").send(user.toString() + "Type `accept` to continue. You will be kicked if you don't type `accept` within 10 minutes");
            ma.delete();
            // Await !vote messages
            const filter = (message) => {
                if (message.author.id === member.user.id)
                {
                    message.delete();
                    if (message.content.toLowerCase().includes("accept") && message.member.roles.get("317854639431221248")) {
                        message.member.removeRole("317854639431221248");
                        return message;
                    }
                }
            }
            // Errors: ['time'] treats ending because of the time limit as an error
            bot.channels.get("317859245309689856").awaitMessages(filter, { max: 1, time: 600000, errors: ['time'] })
                .then(collected => {
                    if (collected.size < 1  && !message.member.roles.get("317854639431221248")) {
                        member.kick();
                    }
                    return collected;
                })

        }
    }
});/**
bot.on('disconnect', function(event) {
    if (event.code === 0) return console.error(event);
    process.exit();//force restart
});*/

bot.on('ready', () => {
    console.log("ReviveBot Ready");
});
bot.on("guildMemberUpdate", async function (member, newMem) {
    let user = member.user;
    if (member.guild && (member.guild.id === "184536578654339072")) {
        let oldMem = member;
        if (!oldMem.roles.has("273105185566359562") && newMem.roles.has("273105185566359562")) return;
        if (!oldMem.roles.has("275317218911322112") && newMem.roles.has("275317218911322112")) return;
        if ((!oldMem.roles.has("184684916833779712") && newMem.roles.has("184684916833779712")) || (!oldMem.roles.has("200849956796497920") && newMem.roles.has("200849956796497920")) || (!oldMem.roles.has("184676864630063104") && newMem.roles.has("184676864630063104")) || (!oldMem.roles.has("286646245198528523") && newMem.roles.has("286646245198528523"))) {
            await request('http://revive-bot-discord.revive.systems/v0/discord/reverse_link/' + user.id);
        }
    }
});
<commit_msg>force get new member information<commit_after>const refresh = require('./lib/refresh');
const bot = require('./bot.js');
const settings = require('./../settings.json');
const modules = require('./modules.js');
const Message = require('./../orm/Message')
const commands = require('./commands');
const request = require('request-promise-native');
let lock = false;
bot.on('error', (err) => {
    /**
     * Catch errors here
     */
    console.log("Stack Trace: " + err.stack);
})
process.on('unhandledRejection', (err) => {
    console.log("UNHANDLED REJECTION AT " + err.stack);
    if (err.toString().includes('Request to use token, but token was unavailable to the client'))
        process.exit();//restart
});
process.on('uncaughtException', (err) => console.log("UNHANDLED EXCEPTION AT " + err.stack));
bot.on('message', (message) => {
    /**
     * if locked, reject everything except dm
     */

    new Message({
        messageID: message.id,
        channel: message.channel.id
    }).save();
    if (message.author.bot) return;
    if (lock) {
        if (!settings.owners.includes(message.author.id))
            //  if (message.channel.guild)
            return;//not DM
    }
    /**
     * Listen to messages and convert into params
     */
    if (message.content.startsWith(settings.identifier)) {
        /**Extracting params */
        let params = message.content.substring(settings.identifier.length).trim();
        params = params.split(settings.delimiter || ' ');
        let cmd = params.shift().trim();
        commands.execute(cmd.toLowerCase(), params, message)
    }
    else if (message.isMentioned(bot.user)) {
        /**remove mentions and then get params */
        let params = message.cleancontent.trim().replace(bot.user.toString(), "").trim();
        params = params.split(settings.delimiter || ' ');
        let cmd = params.shift.trim();
        commands.execute(cmd.toLowerCase(), params, message)
    }
    else {
        //ignore because normal message
    }
});
bot.on('lock', () => { lock = true; });
bot.on('unlock', () => { lock = false; });
bot.on("guildMemberAdd", async function (member) {
    var user = member.user;
    if (member.guild.id === "184536578654339072") {
        if (member.user.bot) return console.log(member.user.tag + " is a bot who joined " + member.guild.name)
        user.send("Welcome to the Revive Network");
        if (! await refresh(user)) {
            await member.addRole(bot.guilds.get("184536578654339072").roles.get("317854639431221248"));
            const ma = await bot.channels.get("317859245309689856").send(user.toString() + "Type `accept` to continue. You will be kicked if you don't type `accept` within 10 minutes");
            ma.delete();
            // Await !vote messages
            const filter = (message) => {
                if (message.author.id === member.user.id)
                {
                    message.delete();
                    if (message.content.toLowerCase().includes("accept") && message.member.roles.get("317854639431221248")) {
                        message.member.removeRole("317854639431221248");
                        return message;
                    }
                }
            }
            // Errors: ['time'] treats ending because of the time limit as an error
            bot.channels.get("317859245309689856").awaitMessages(filter, { max: 1, time: 600000, errors: ['time'] })
                .then(collected => {
                    if (collected.size < 1  && member.guild.member(member.user).roles.get("317854639431221248")) {
                        member.kick();
                    }
                    return collected;
                })

        }
    }
});/**
bot.on('disconnect', function(event) {
    if (event.code === 0) return console.error(event);
    process.exit();//force restart
});*/

bot.on('ready', () => {
    console.log("ReviveBot Ready");
});
bot.on("guildMemberUpdate", async function (member, newMem) {
    let user = member.user;
    if (member.guild && (member.guild.id === "184536578654339072")) {
        let oldMem = member;
        if (!oldMem.roles.has("273105185566359562") && newMem.roles.has("273105185566359562")) return;
        if (!oldMem.roles.has("275317218911322112") && newMem.roles.has("275317218911322112")) return;
        if ((!oldMem.roles.has("184684916833779712") && newMem.roles.has("184684916833779712")) || (!oldMem.roles.has("200849956796497920") && newMem.roles.has("200849956796497920")) || (!oldMem.roles.has("184676864630063104") && newMem.roles.has("184676864630063104")) || (!oldMem.roles.has("286646245198528523") && newMem.roles.has("286646245198528523"))) {
            await request('http://revive-bot-discord.revive.systems/v0/discord/reverse_link/' + user.id);
        }
    }
});
<|endoftext|>


<commit_before>odoo.define('web.SwitchCompanyMenu', function(require) {
    "use strict";

    var Model = require('web.Model');
    var session = require('web.session');
    var SystrayMenu = require('web.SystrayMenu');
    var Widget = require('web.Widget');

    var SwitchCompanyMenu = Widget.extend({
        template: 'SwitchCompanyMenu',
        willStart: function(){
            var self = this;
            var def = $.Deferred();
            new Model("res.users").call("read_companies").then(function(res) {
                if (res){
                    self.all_allowed_companies = res.all_allowed_companies;
                    self.current_company = res.current_company;
                    def.resolve();
                } else {
                    def.reject();
                }
            });
            return $.when(this._super(), def);
        },
        start: function() {
            var self = this;

            this.$el.on('click', '.dropdown-menu li a[data-menu]', function(ev) {
                ev.preventDefault();
                self['on_menu_company']($(this));
            });

            self.$('.oe_topbar_name').text(self.current_company[1]);

            var companies_list = '';
            _.each(self.all_allowed_companies, function(company) {
                var a = '';
                if(company[0] == self.current_company[0]) {
                    a = '';
                } else {
                    a = '';
                }
                companies_list += '
' + a + company[1] + '
';
            });
            self.$('.dropdown-menu').html(companies_list);
            return this._super();
        },
        on_menu_company: function(selected) {
            var company_id = selected.data('company-id');
            new Model('res.users').call('write', [[session.uid], {'company_id': company_id}]).then(function() {
                location.reload();
            });
        },
    });

    SystrayMenu.Items.push(SwitchCompanyMenu);
});
<commit_msg>[FIX] web: avoid infinite pending state in case of RPC call fail<commit_after>odoo.define('web.SwitchCompanyMenu', function(require) {
    "use strict";

    var Model = require('web.Model');
    var session = require('web.session');
    var SystrayMenu = require('web.SystrayMenu');
    var Widget = require('web.Widget');

    var SwitchCompanyMenu = Widget.extend({
        template: 'SwitchCompanyMenu',
        willStart: function(){
            var self = this;
            var def = $.Deferred();
            new Model("res.users").call("read_companies").then(function(res) {
                if (res){
                    self.all_allowed_companies = res.all_allowed_companies;
                    self.current_company = res.current_company;
                    def.resolve();
                } else {
                    def.reject();
                }
            }).fail(function(){
                def.reject();
            });
            return $.when(this._super(), def);
        },
        start: function() {
            var self = this;

            this.$el.on('click', '.dropdown-menu li a[data-menu]', function(ev) {
                ev.preventDefault();
                var company_id = $(ev.currentTarget).data('company-id');
                new Model('res.users').call('write', [[session.uid], {'company_id': company_id}]).then(function() {
                    location.reload();
                });
            });

            self.$('.oe_topbar_name').text(self.current_company[1]);

            var companies_list = '';
            _.each(self.all_allowed_companies, function(company) {
                var a = '';
                if(company[0] == self.current_company[0]) {
                    a = '';
                } else {
                    a = '';
                }
                companies_list += '
' + a + company[1] + '
';
            });
            self.$('.dropdown-menu').html(companies_list);
            return this._super();
        },
    });

    SystrayMenu.Items.push(SwitchCompanyMenu);
});
<|endoftext|>


<commit_before>'use strict';

if ('ontouchstart' in window) {
 console.log("Событие касания есть");
}

let mutator,
    figureClass,
    figureColor,
    figureForm,
    sizes,
    figureX,
    figureY,
    arrCoords,
    count;

const forms = ["circle", "square"],
      sizeValues = ["30px", "40px", "50px", "60px"],
      greenRange = ['#abf977','#a8f877','#a5f776','#a0f775','#9cf575','#99f574','#96f474','#93f473','#8ff273','#8af172','#86f172','#81f071','#7eef71','#7bee70','#77ed70','#72ed6f','#6deb6f','#68eb6e','#62ea6d','#5ee96d','#5ae86d','#56e76c','#50e76c','#49e56b','#42e46b','#39e36a','#30e369','#23e269','#18e168','#00e068'],
      orangeRange = ['#e05900','#e05c00','#e05f00','#e06100','#e06400','#e16700','#e16900','#e16c00','#e16f00','#e17100','#e17300','#e17700','#e17800','#e17b00','#e17e00','#e18000','#e18300','#e18500','#e18700','#e18900','#e18b00','#e18e00','#e19000','#e19300','#e19400','#e19600','#e09a00','#e09c00','#e09d00','#e0a000'];

arrCoords = [];

const changePosition = () => {
  figureX = getRandom(0, (document.body.clientWidth - 60));;
  figureY = getRandom(35, (document.body.clientHeight - 60 - 200));
};

const countPosition = () => {
  return arrCoords.some(function(item, index) {
    return ( (figureX <= item.left + 70 && figureX >= item.left - 70) && (figureY <= item.top + 70 && figureY >= item.top - 70));
  });
};

let getRandom = (min, max) => {
  return Math.round(Math.random() * (max - min) + min);
}

if (document.body.clientWidth > 500) {
  count = getRandom(12, 18);
} else {
  count = getRandom(4, 8);
}

document.querySelector('.countFigure').innerHTML = `Количество фигурок: ${count}`;

for(let i = 0; i < count; i++) {

    mutator = getRandom(0, 4);

    figureForm = forms[getRandom(0, 1)];
    sizes = sizeValues[getRandom(0, 3)];

    if (mutator > 2) {
      figureClass = "orange";
      figureColor = orangeRange[getRandom(0, orangeRange.length)];
    } else {
      figureClass = "green";
      figureColor = greenRange[getRandom(0, greenRange.length)];
    }

    changePosition();
    countPosition();

    if (countPosition() === true) {
      changePosition();
      countPosition();
    }

    if (countPosition() === false) {
      arrCoords.push({left: figureX, top: figureY});
      document.body.innerHTML += `<div
                                  class='figure draggable ${figureForm} ${figureClass}'
                                  style='left: ${figureX}px; top: ${figureY}px;
                                  height: ${sizes}; width: ${sizes};
                                  background-color: ${figureColor}'>
                                  </div>`;
    }
}

let getCoords = (elem) => {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + pageYOffset,
    left: box.left + pageXOffset,
    width: box.width
  };
}

let DragManager = new function() {

  let dragObject = {};

  let self = this;

  let onMouseDown = (e) => {

    // if (e.which != 1) return;

    let elem = e.target.closest('.draggable');
    if (!elem) return;

    dragObject.elem = elem;

    // запомним, что элемент нажат на текущих координатах pageX/pageY
    if ((e.pageX)&&(e.pageY)) {
      dragObject.downX = e.pageX;
      dragObject.downY = e.pageY;
    } else if (e.targetTouches) {
      dragObject.downX = e.targetTouches[0].pageX;
      dragObject.downY = e.targetTouches[0].pageY;
      e.preventDefault();
    }

    return false;
  };

  let startDrag = (e) => {
    let avatar = dragObject.avatar;

    // инициировать начало переноса
    document.body.appendChild(avatar);
    avatar.style.zIndex = 9999;
    avatar.style.position = 'absolute';
  };

  let createAvatar = (e) => {

    // запомнить старые свойства, чтобы вернуться к ним при отмене переноса
    let avatar = dragObject.elem;
    let old = {
      parent: avatar.parentNode,
      nextSibling: avatar.nextSibling,
      position: avatar.position || '',
      left: avatar.left || '',
      top: avatar.top || '',
      zIndex: avatar.zIndex || ''
    };

    // функция для отмены переноса
    avatar.rollback = function() {
      old.parent.insertBefore(avatar, old.nextSibling);
      avatar.style.position = old.position;
      avatar.style.left = old.left;
      avatar.style.top = old.top;
      avatar.style.zIndex = old.zIndex
    };

    return avatar;
  }

  let onMouseMove = (e) => {
    e.preventDefault();
    if (!dragObject.elem) return; // элемент не зажат

    if (!dragObject.avatar) { // если перенос неначат...
      let moveX,
          moveY;
      if ((e.pageX)&&(e.pageY)) {
        moveX = e.pageX - dragObject.downX;
        moveY = e.pageY - dragObject.downY;
      } else if (e.targetTouches) {
        moveX = e.targetTouches[0].pageX - dragObject.downX;
        moveY = e.targetTouches[0].pageY - dragObject.downY;
        e.preventDefault();
      }

      // если мышь передвинулась в нажатом состоянии недостаточно далеко
      if (Math.abs(moveX) < 3 && Math.abs(moveY) < 3) {
        return;
      }

      // начинаем перенос
      dragObject.avatar = createAvatar(e); // создать аватар
      if (!dragObject.avatar) { // отмена переноса, нельзя "захватить" за эту часть элемента
        dragObject = {};
        return;
      }

      // аватар создан успешно
      // создать вспомогательные свойства shiftX/shiftY
      coords = getCoords(dragObject.avatar);
      dragObject.shiftX = dragObject.downX - coords.left;
      dragObject.shiftY = dragObject.downY - coords.top;
      console.log(document.body.scrollWidth);
      startDrag(e); // отобразить начало переноса
    }

    let coords = getCoords(dragObject.avatar);
    // отобразить перенос объекта при каждом движении мыши
    if ((e.pageX)&&(e.pageY)) {
      dragObject.avatar.style.left = e.pageX - dragObject.shiftX + 'px';
      dragObject.avatar.style.top = e.pageY - dragObject.shiftY + 'px';
    } else if (e.targetTouches) {
      dragObject.avatar.style.left = e.targetTouches[0].pageX - dragObject.shiftX + 'px';
      dragObject.avatar.style.top = e.targetTouches[0].pageY - dragObject.shiftY + 'px';
      e.preventDefault();
    }

    console.log(coords);
    if ((parseInt(dragObject.avatar.style.left)) > (document.body.clientWidth - coords.width))  {
      dragObject.avatar.style.left = document.body.clientWidth - coords.width + 'px';
    } else if (parseInt(dragObject.avatar.style.left) < 0) {
      dragObject.avatar.style.left = 0 + 'px';
    }

    return false;
  };

  let findDroppable = (event) => {
    // спрячем переносимый элемент
    dragObject.avatar.hidden = true;
    let elem,
        touch,
        coordX,
        coordY;
    // получить самый вложенный элемент под курсором мыши
    // if ((event.clientX)&&(event.clientY)) {
      elem = document.elementFromPoint(event.clientX, event.clientY);

    // } else if (event.targetTouches) {
    //   touch = event.targetTouches[0];
    //   coordX = touch.clientX;
    //   coordY = touch.clientY;
    //   elem = document.elementFromPoint(coordX, coordY);
    //   event.preventDefault();
    // }

    // показать переносимый элемент обратно
    dragObject.avatar.hidden = false;

    if (elem == null) {
      // такое возможно, если курсор мыши "вылетел" за границу окна
      return null;
    }
    console.log(elem);
    return elem.closest('.droppable');
  };

  let finishDrag = (e) => {
    let dropElem = findDroppable(e);

    // if (!dropElem) {
    //   self.onDragCancel(dragObject);
    // } else {
    //   self.onDragEnd(dragObject, dropElem);
    // }
  };

  let onMouseUp = (e) => {
    if (dragObject.avatar) { // если перенос идет
      finishDrag(e);
    }

    // перенос либо не начинался, либо завершился
    // в любом случае очистим "состояние переноса" dragObject
    dragObject = {};
  };

  document.addEventListener("mousemove", onMouseMove);
  document.addEventListener("touchstart", onMouseDown, true);
  document.addEventListener("touchmove", onMouseMove, true);

  document.addEventListener("mouseup", onMouseUp);
  document.addEventListener("touchend", onMouseUp, true);
  document.addEventListener("touchcancel", onMouseUp, true);
  document.addEventListener("mousedown", onMouseDown);

  this.onDragEnd = function(dragObject, dropElem) {};
  this.onDragCancel = function(dragObject) {};

};
<commit_msg>Update findDroppable()<commit_after>'use strict';

if ('ontouchstart' in window) {
 console.log("Событие касания есть");
}

let mutator,
    figureClass,
    figureColor,
    figureForm,
    sizes,
    figureX,
    figureY,
    arrCoords,
    count;

const forms = ["circle", "square"],
      sizeValues = ["30px", "40px", "50px", "60px"],
      greenRange = ['#abf977','#a8f877','#a5f776','#a0f775','#9cf575','#99f574','#96f474','#93f473','#8ff273','#8af172','#86f172','#81f071','#7eef71','#7bee70','#77ed70','#72ed6f','#6deb6f','#68eb6e','#62ea6d','#5ee96d','#5ae86d','#56e76c','#50e76c','#49e56b','#42e46b','#39e36a','#30e369','#23e269','#18e168','#00e068'],
      orangeRange = ['#e05900','#e05c00','#e05f00','#e06100','#e06400','#e16700','#e16900','#e16c00','#e16f00','#e17100','#e17300','#e17700','#e17800','#e17b00','#e17e00','#e18000','#e18300','#e18500','#e18700','#e18900','#e18b00','#e18e00','#e19000','#e19300','#e19400','#e19600','#e09a00','#e09c00','#e09d00','#e0a000'];

arrCoords = [];

const changePosition = () => {
  figureX = getRandom(0, (document.body.clientWidth - 60));;
  figureY = getRandom(35, (document.body.clientHeight - 60 - 200));
};

const countPosition = () => {
  return arrCoords.some(function(item, index) {
    return ( (figureX <= item.left + 70 && figureX >= item.left - 70) && (figureY <= item.top + 70 && figureY >= item.top - 70));
  });
};

let getRandom = (min, max) => {
  return Math.round(Math.random() * (max - min) + min);
}

if (document.body.clientWidth > 500) {
  count = getRandom(12, 18);
} else {
  count = getRandom(4, 8);
}

document.querySelector('.countFigure').innerHTML = `Количество фигурок: ${count}`;

for(let i = 0; i < count; i++) {

    mutator = getRandom(0, 4);

    figureForm = forms[getRandom(0, 1)];
    sizes = sizeValues[getRandom(0, 3)];

    if (mutator > 2) {
      figureClass = "orange";
      figureColor = orangeRange[getRandom(0, orangeRange.length)];
    } else {
      figureClass = "green";
      figureColor = greenRange[getRandom(0, greenRange.length)];
    }

    changePosition();
    countPosition();

    if (countPosition() === true) {
      changePosition();
      countPosition();
    }

    if (countPosition() === false) {
      arrCoords.push({left: figureX, top: figureY});
      document.body.innerHTML += `<div
                                  class='figure draggable ${figureForm} ${figureClass}'
                                  style='left: ${figureX}px; top: ${figureY}px;
                                  height: ${sizes}; width: ${sizes};
                                  background-color: ${figureColor}'>
                                  </div>`;
    }
}

let getCoords = (elem) => {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + pageYOffset,
    left: box.left + pageXOffset,
    width: box.width
  };
}

let DragManager = new function() {

  let dragObject = {};

  let self = this;

  let onMouseDown = (e) => {

    // if (e.which != 1) return;

    let elem = e.target.closest('.draggable');
    if (!elem) return;

    dragObject.elem = elem;

    // запомним, что элемент нажат на текущих координатах pageX/pageY
    if ((e.pageX)&&(e.pageY)) {
      dragObject.downX = e.pageX;
      dragObject.downY = e.pageY;
    } else if (e.targetTouches) {
      dragObject.downX = e.targetTouches[0].pageX;
      dragObject.downY = e.targetTouches[0].pageY;
      e.preventDefault();
    }

    return false;
  };

  let startDrag = (e) => {
    let avatar = dragObject.avatar;

    // инициировать начало переноса
    document.body.appendChild(avatar);
    avatar.style.zIndex = 9999;
    avatar.style.position = 'absolute';
  };

  let createAvatar = (e) => {

    // запомнить старые свойства, чтобы вернуться к ним при отмене переноса
    let avatar = dragObject.elem;
    let old = {
      parent: avatar.parentNode,
      nextSibling: avatar.nextSibling,
      position: avatar.position || '',
      left: avatar.left || '',
      top: avatar.top || '',
      zIndex: avatar.zIndex || ''
    };

    // функция для отмены переноса
    avatar.rollback = function() {
      old.parent.insertBefore(avatar, old.nextSibling);
      avatar.style.position = old.position;
      avatar.style.left = old.left;
      avatar.style.top = old.top;
      avatar.style.zIndex = old.zIndex
    };

    return avatar;
  };

  let onMouseMove = (e) => {
    e.preventDefault();
    if (!dragObject.elem) return; // элемент не зажат

    if (!dragObject.avatar) { // если перенос неначат...
      let moveX,
          moveY;
      if ((e.pageX)&&(e.pageY)) {
        moveX = e.pageX - dragObject.downX;
        moveY = e.pageY - dragObject.downY;
      } else if (e.targetTouches) {
        moveX = e.targetTouches[0].pageX - dragObject.downX;
        moveY = e.targetTouches[0].pageY - dragObject.downY;
        e.preventDefault();
      }

      // если мышь передвинулась в нажатом состоянии недостаточно далеко
      if (Math.abs(moveX) < 3 && Math.abs(moveY) < 3) {
        return;
      }

      // начинаем перенос
      dragObject.avatar = createAvatar(e); // создать аватар
      if (!dragObject.avatar) { // отмена переноса, нельзя "захватить" за эту часть элемента
        dragObject = {};
        return;
      }

      // аватар создан успешно
      // создать вспомогательные свойства shiftX/shiftY
      coords = getCoords(dragObject.avatar);
      dragObject.shiftX = dragObject.downX - coords.left;
      dragObject.shiftY = dragObject.downY - coords.top;
      console.log(document.body.scrollWidth);
      startDrag(e); // отобразить начало переноса
    }

    let coords = getCoords(dragObject.avatar);
    // отобразить перенос объекта при каждом движении мыши
    if ((e.pageX)&&(e.pageY)) {
      dragObject.avatar.style.left = e.pageX - dragObject.shiftX + 'px';
      dragObject.avatar.style.top = e.pageY - dragObject.shiftY + 'px';
    } else if (e.targetTouches) {
      dragObject.avatar.style.left = e.targetTouches[0].pageX - dragObject.shiftX + 'px';
      dragObject.avatar.style.top = e.targetTouches[0].pageY - dragObject.shiftY + 'px';
      e.preventDefault();
    }

    console.log(coords);
    if ((parseInt(dragObject.avatar.style.left)) > (document.body.clientWidth - coords.width))  {
      dragObject.avatar.style.left = document.body.clientWidth - coords.width + 'px';
    } else if (parseInt(dragObject.avatar.style.left) < 0) {
      dragObject.avatar.style.left = 0 + 'px';
    }

    return false;
  };

  let findDroppable = (event) => {
    // спрячем переносимый элемент
    dragObject.avatar.hidden = true;
    let elem,
        touch,
        coordX,
        coordY,
        points;

    if ((event.clientX)&&(event.clientY)) {
      elem = document.elementFromPoint(event.clientX, event.clientY);
    } else if (event.changedTouches) {
      elem = document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
      event.preventDefault();
    }

    // показать переносимый элемент обратно
    dragObject.avatar.hidden = false;

    if (elem == null) {
      // такое возможно, если курсор мыши "вылетел" за границу окна
      return null;
    }

    return elem.closest('.basket-orange');
  };

  let finishDrag = (e) => {
    let dropElem = findDroppable(e);
    console.log(dropElem);
    if (!dropElem) {
      // self.onDragCancel(dragObject);

    } else {
    self.onDragEnd(dragObject, dropElem);
    }
  };

  let onMouseUp = (e) => {
    if (dragObject.avatar) { // если перенос идет
      finishDrag(e);
    }

    // перенос либо не начинался, либо завершился
    // в любом случае очистим "состояние переноса" dragObject
    dragObject = {};
  };

  document.addEventListener("mousemove", onMouseMove);
  document.addEventListener("touchstart", onMouseDown, true);
  document.addEventListener("touchmove", onMouseMove, true);

  document.addEventListener("mouseup", onMouseUp);
  document.addEventListener("touchend", onMouseUp, true);
  document.addEventListener("touchcancel", onMouseUp, true);
  document.addEventListener("mousedown", onMouseDown);

  this.onDragEnd = function(dragObject, dropElem) {};
  this.onDragCancel = function(dragObject) {};

};

let counters = parseIntMod(document.querySelector('.countFigure').innerHTML);
console.log( counters );

DragManager.onDragCancel = function(dragObject) {
  dragObject.avatar.rollback();
};

DragManager.onDragEnd = function(dragObject, dropElem) {
  dragObject.elem.style.display = 'none';
  dropElem.classList.add('computer-smile');
  setTimeout(function() {
    dropElem.classList.remove('computer-smile');
  }, 200);
};

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function parseIntMod(n) {
  var result = "";
  for (var i = 0; i < n.length; i++) {
    if ( isNumber(n[i]) == false ) continue;

    result += n[i];
  }

  return +result;
}
<|endoftext|>


<commit_before>(function(sox, $) {
  'use strict';

  sox.dialog = {
    init: function(options) {
      if (!$('.top-bar').length) return;
      sox.debug('initializing SOX dialog');

      const version = options.version;
      const features = options.features;
      const settings = options.settings;
      const lastVersionInstalled = options.lastVersionInstalled;
      const html = GM_getResourceText('dialog');
      const $soxSettingsDialog = $(html);
      const $soxSettingsDialogFeatures = $soxSettingsDialog.find('#sox-settings-dialog-features');
      const $soxSettingsDialogVersion = $soxSettingsDialog.find('#sox-settings-dialog-version');
      const $soxSettingsSave = $soxSettingsDialog.find('#sox-settings-dialog-save');
      const $soxSettingsReset = $soxSettingsDialog.find('#sox-settings-dialog-reset');
      const $soxSettingsDebugging = $soxSettingsDialog.find('#sox-settings-dialog-debugging');
      const $soxSettingsNewAccessTokenButton = $soxSettingsDialog.find('#sox-settings-dialog-access-token');
      const $soxSettingsToggle = $soxSettingsDialog.find('#sox-settings-dialog-check-toggle');
      const $soxSettingsClose = $soxSettingsDialog.find('#sox-settings-dialog-close');
      const $searchBox = $soxSettingsDialog.find('#search');
      const $importSettingsButton = $soxSettingsDialog.find('#sox-settings-import');
      const $exportSettingsButton = $soxSettingsDialog.find('#sox-settings-export');
      const $featurePackButtons = $soxSettingsDialog.find('.sox-settings-dialog-feature-pack');

      // Array of HTML strings that will be displayed as `li` items if the user has installed a new version.
      const changes = [
        'Fix bugs in various features',
        'Add feature to copy markdown for comments',
        'Add feature to add scrolling to room list in usercards in chat',
        'Only run SOX on HTTPS',
        'Deprecate "add timeline button" feature (now natively implemented!)',
      ];

      function addCategory(name) {
        const $div = $('
', {
          'class': 'header category',
          'id': 'header-for-' + name,
        });

        const $h3 = $('
', {
          text: name.toLowerCase(),
        });

        const $content = $('
', {
          id: name,
          class: 'modal-content features',
        });
        $div.append($h3);

        if (!$soxSettingsDialogFeatures.find('div#header-for-' + name).length) {
          $soxSettingsDialogFeatures.append($div);
          $div.after($content);
        }
      }

      function addFeature(category, name, description, featureSettings, extendedDescription, metaLink, featurePacks, usesApi) {
        const blockFeatureSelection = usesApi && !sox.settings.accessToken;

        const $div = $('
', {
          'class': 'sox-feature ' + (featurePacks.length ? featurePacks.join(' ') : '') + (blockFeatureSelection ? ' disabled-feature' : ''),
          'title': blockFeatureSelection ? 'You must get an access token to enable this feature (click the key button at the bottom of the SOX dialog)' : '',
        });

        const $info = sox.sprites.getSvg('info').hover(function() {
          if (extendedDescription && !$(this).parent().find('.sox-feature-info').length) {
            $(this).parent().append($('
', {
              'class': 'sox-feature-info',
              'html': extendedDescription + (metaLink ? ' [meta]' : ''),
            }));
          }
        });

        const $label = $('');
        const $input = $('<input/>', {
          id: name,
          class: 's-checkbox',
          type: 'checkbox',
        }).prop('disabled', blockFeatureSelection);

        $div.on('mouseleave', function() {
          $(this).find('.sox-feature-info').remove();
        }).append($label).append(extendedDescription ? $info : '');
        $label.append($input);
        $input.after(description);
        $soxSettingsDialogFeatures.find('#' + category).append($div);

        if (featureSettings) {
          const $settingsDiv = $('
', {
            id: 'feature-settings-' + name,
            class: 'sox-feature-settings',
            style: 'display: none; margin-top: 5px;',
          });

          const $settingsToggle = sox.sprites.getSvg('wrench', 'Edit this feature\'s settings').click(e => {
            e.preventDefault(); //don't uncheck the checkbox

            const $settingsPanel = $('#feature-settings-' + name);

            if ($settingsPanel.is(':visible')) {
              $settingsPanel.fadeOut();
            } else {
              $settingsPanel.fadeIn();
            }
          });

          const optionalSettings = GM_getValue('SOX-' + name + '-settings', -1);

          for (let i = 0; i < featureSettings.length; i++) {
            const currentSetting = featureSettings[i];
            $settingsDiv
              .append(sox.helpers.newElement(currentSetting.type, { //use newElement helper so the type can be things like 'checkbox' or 'radio'
                id: currentSetting.id,
                'class': currentSetting.type === 'textarea' ? 'featureSetting s-input' : 'featureSetting s-checkbox',
                'style': 'margin-right: 5px',
                'checked': (currentSetting.type === 'checkbox' ? JSON.parse(optionalSettings)[currentSetting.id] : false),
                value: (optionalSettings === -1 ? '' : JSON.parse(optionalSettings)[currentSetting.id]),
              }))
              .append(currentSetting.desc)
              .append('
');
          }

          const $saveFeatureSettings = $('', {
            id: 'saveSettings-' + name,
            class: 'action s-btn s-btn__secondary s-btn__sm',
            text: 'Save Settings',
            click: function(e) {
              e.preventDefault(); //don't uncheck the checkbox
              const settingsToSave = {};
              $('.sox-feature.disabled-feature input[type="checkbox"]').prop('checked', false); //uncheck any features that somehow were checked (they shouldn't be able to through the UI) but should be disabled (user doesn't have access token)
              $(this).parent().find('.featureSetting').each(function() {
                settingsToSave[$(this).attr('id')] = ($(this).is(':checkbox') ? $(this).is(':checked') : $(this).val());
              });
              GM_setValue('SOX-' + name + '-settings', JSON.stringify(settingsToSave));
              sox.settings.writeToConsole(true);
              alert('Saved!');
            },
          });

          $settingsDiv.append($saveFeatureSettings);

          const $feature = $soxSettingsDialogFeatures.find('input#' + name).parent();
          $feature.append($settingsToggle);

          if ($div.has('.sox-sprite-info').length) {
            $info.after($settingsDiv);
          } else {
            $feature.append($settingsDiv);
          }
        }
      }

      // display sox version number in the dialog
      if (version != 'unknown' && version !== null) {
        $soxSettingsDialogVersion.text(' v' + (version ? version.toLowerCase() : ''));
      } else {
        $soxSettingsDialogVersion.text('');
      }

      if (version !== lastVersionInstalled) {
        GM_setValue('SOX-lastVersionInstalled', version);
        const $newVersionDetailsContainer = $('
', {
          'class': 'sox-new-version-details',
        });

        const $newVersionHeader = $('
', {
          'class': 'header category',
          'html': '
new in this version
',
        });

        const $changes = $('
');

        for (let i = 0; i < changes.length; i++) {
          $changes.append($('
', {
            'html': changes[i], //this array is defined near the top of the file
            'class': 'sox-new-version-item',
          }));
        }

        const $newVersionInfoContainer = $('
', {
          'class': 'modal-content',
          'html': $changes,
        });

        $soxSettingsDialogFeatures.append($newVersionDetailsContainer.append($newVersionHeader).append($newVersionInfoContainer));
      }

      if (sox.info.debugging) $soxSettingsDebugging.text('Disable debugging');

      // wire up event handlers
      $soxSettingsClose.on('click', () => {
        $soxSettingsDialog.hide();
      });

      $soxSettingsReset.on('click', () => {
        if (confirm('Are you sure you want to reset SOX?')) {
          sox.settings.reset();
          location.reload(); // reload page to reflect changed settings
        }
      });

      $soxSettingsDebugging.on('click', () => {
        const currentState = sox.info.debugging;
        if (typeof currentState === 'undefined') {
          GM_setValue('SOX-debug', true);
          $soxSettingsDebugging.text('Disable debugging');
        } else {
          GM_setValue('SOX-debug', !currentState);
          $soxSettingsDebugging.text(currentState ? 'Enable debugging' : 'Disable debugging');
        }
        location.reload();
      });

      $soxSettingsNewAccessTokenButton.on('click', () => {
        window.open('https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/');
        sox.loginfo('To get a new access token, please go to the following URL', 'https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/');
      });

      $soxSettingsToggle.on('click', function() {
        const $icon = $(this).find('i');

        const checked = $icon.hasClass('fas');

        if (checked) {
          $icon.removeClass('fas').addClass('far');
        } else {
          $icon.removeClass('far').addClass('fas');
        }

        $soxSettingsDialogFeatures.find('input').prop('checked', !checked);
      });

      $soxSettingsSave.on('click', () => {
        const settings = [];
        $soxSettingsDialogFeatures.find('input[type=checkbox]:checked').not('.featureSetting').each(function() { //NOT the per-feature featureSetting checkboxes, because they are saved in THEIR OWN setting object!
          const x = $(this).closest('.modal-content').attr('id') + '-' + $(this).attr('id');
          settings.push(x); //Add the function's ID (also the checkbox's ID) to the array
        });

        sox.settings.save(settings);
        location.reload(); // reload page to reflect changed settings
      });

      $importSettingsButton.on('click', () => {
        const settingsToImport = window.prompt('Please paste the settings exactly as they were given to you');
        if (!settingsToImport) return;
        sox.settings.save(settingsToImport);
        location.reload();
      });

      $exportSettingsButton.on('click', () => {
        window.prompt('Your settings are below. Press Ctrl/Cmd + C to copy.', JSON.stringify(sox.settings.load()));
      });

      $searchBox.on('keyup keydown', function() { //search box
        if ($(this).val() !== '') {
          const searchQuery = $(this).val();
          $('.sox-new-version-details').hide();
          $('#sox-settings-dialog .sox-feature').each(function() {
            if ($(this).find('label').text().toLowerCase().indexOf(searchQuery) == -1) {
              $(this).hide();
            } else {
              $(this).show();
            }
          });
        } else {
          $('.category, .features, #sox-settings-dialog .sox-feature, .sox-new-version-details').fadeIn();
        }
      });

      $featurePackButtons.click(function() {
        $('#sox-settings-dialog .sox-feature').removeClass('feature-fade-out');
        if ($(this).is('.clear-feature-pack-selection')) return;
        $('#sox-settings-dialog .sox-feature').not('.' + $(this).attr('data-feature-pack-id')).addClass('feature-fade-out');
      });

      // create sox settings button
      const $soxSettingsButton = $('', {
        id: 'soxSettingsButton',
        class: 'sox-settings-button -link',
        title: 'Change SOX settings',
        href: '#',
        click: function(e) {
          e.preventDefault();
          $('#sox-settings-dialog').toggle();
          if ($soxSettingsDialog.is(':visible')) {
            $(this).addClass('topbar-icon-on');
            $soxSettingsDialog.find('#search').focus();
          } else {
            $(this).removeClass('topbar-icon-on');
          }
        },
      });

      // Very basic 'dark theme' support. See https://github.com/soscripted/sox/issues/406
      // Not sure what the best way to detect dark mode is; the following just checks to
      // see if 's text color is #ccc (grey/rgb(204,204,204)). Might need changing
      // in future
      if ($('body').css('color') === 'rgb(204, 204, 204)') {
        sox.debug('Dark mode detected, tweaking SOX CSS');
        $soxSettingsDialog.addClass('dark-mode');
      }

      const $icon = sox.sprites.getSvg('settings', 'Change your SOX settings', {
        fill: $('.top-bar .-secondary .-link').css('color'),
        width: '25px',
        height: '25px',
      });

      //close dialog if clicked outside it
      $(document).click(e => { //close dialog if clicked outside it
        const $target = $(e.target);
        const isToggle = $target.is('#soxSettingsButton, #sox-settings-dialog');
        const isChild = $target.parents('#soxSettingsButton, #sox-settings-dialog').is('#soxSettingsButton, #sox-settings-dialog');

        if (!isToggle && !isChild) {
          $soxSettingsDialog.hide();
          $soxSettingsButton.removeClass('topbar-icon-on');
        }
      });

      //close dialog if one of the links on the topbar is clicked
      $('.topbar-icon, .-link').not('.sox-settings-button').click(() => {
        $soxSettingsDialog.hide();
        $soxSettingsButton.removeClass('topbar-icon-on');
      });

      // load features into dialog
      sox.debug('injecting features into dialog');
      for (const category in features.categories) {
        addCategory(category);
        for (const feature in features.categories[category]) {
          const currentFeature = features.categories[category][feature];
          addFeature(
            category,
            currentFeature.name,
            currentFeature.desc,
            (currentFeature.settings ? currentFeature.settings : false), //add the settings panel for this feautre if indicated in the JSON
            (currentFeature.extended_description ? currentFeature.extended_description : false), //add the extra description on hover if the feature has the extended description
            (currentFeature.meta ? currentFeature.meta : false), //add the meta link to the extra description on hover
            (currentFeature.feature_packs ? currentFeature.feature_packs : []),
            (currentFeature.usesApi ? currentFeature.usesApi : false)
          );
        }
      }

      if (settings) {
        for (let i = 0; i < settings.length; ++i) {
          $soxSettingsDialogFeatures.find('#' + settings[i].split('-')[1]).prop('checked', true);
        }
      } else { // no settings found, mark all inputs as checked and display settings dialog
        //note: the .not() is to make sure any disabled features (user doesn't have access token) aren't selected by default
        $soxSettingsDialogFeatures.find('input').not('.sox-feature.disabled-feature input').prop('checked', true);
        $soxSettingsButton.addClass('topbar-icon-on');
        $soxSettingsDialog.show();
      }

      // add dialog to corral and sox button to topbar
      $soxSettingsButton.append($icon);
      // The following check is because SO doesn't have inbox, achievements help centre and site switcher items
      if ($('.inbox-button-item').length) {
        $('.inbox-button-item').before($('
').addClass('-item').append($soxSettingsButton));
      } else {
        $('.js-searchbar-trigger').after($('
').addClass('-item').append($soxSettingsButton));
      }

      $soxSettingsDialog.css({
        'top': $('.top-bar').height(),
        'right': $('.-container').outerWidth() - $('#soxSettingsButton').parent().position().left - $('#soxSettingsButton').outerWidth(),
      });

      //only add dialog if button was added successfully
      if ($('#soxSettingsButton').length) $('.js-topbar-dialog-corral').append($soxSettingsDialog);
    },
  };
})(window.sox = window.sox || {}, jQuery);
<commit_msg>Search shouldn't be case sensitive, simplify 4-line if conditions to one-line ones<commit_after>(function(sox, $) {
  'use strict';

  sox.dialog = {
    init: function(options) {
      if (!$('.top-bar').length) return;
      sox.debug('initializing SOX dialog');

      const version = options.version;
      const features = options.features;
      const settings = options.settings;
      const lastVersionInstalled = options.lastVersionInstalled;
      const html = GM_getResourceText('dialog');
      const $soxSettingsDialog = $(html);
      const $soxSettingsDialogFeatures = $soxSettingsDialog.find('#sox-settings-dialog-features');
      const $soxSettingsDialogVersion = $soxSettingsDialog.find('#sox-settings-dialog-version');
      const $soxSettingsSave = $soxSettingsDialog.find('#sox-settings-dialog-save');
      const $soxSettingsReset = $soxSettingsDialog.find('#sox-settings-dialog-reset');
      const $soxSettingsDebugging = $soxSettingsDialog.find('#sox-settings-dialog-debugging');
      const $soxSettingsNewAccessTokenButton = $soxSettingsDialog.find('#sox-settings-dialog-access-token');
      const $soxSettingsToggle = $soxSettingsDialog.find('#sox-settings-dialog-check-toggle');
      const $soxSettingsClose = $soxSettingsDialog.find('#sox-settings-dialog-close');
      const $searchBox = $soxSettingsDialog.find('#search');
      const $importSettingsButton = $soxSettingsDialog.find('#sox-settings-import');
      const $exportSettingsButton = $soxSettingsDialog.find('#sox-settings-export');
      const $featurePackButtons = $soxSettingsDialog.find('.sox-settings-dialog-feature-pack');

      // Array of HTML strings that will be displayed as `li` items if the user has installed a new version.
      const changes = [
        'Fix bugs in various features',
        'Add feature to copy markdown for comments',
        'Add feature to add scrolling to room list in usercards in chat',
        'Only run SOX on HTTPS',
        'Deprecate "add timeline button" feature (now natively implemented!)',
      ];

      function addCategory(name) {
        const $div = $('
', {
          'class': 'header category',
          'id': 'header-for-' + name,
        });

        const $h3 = $('
', {
          text: name.toLowerCase(),
        });

        const $content = $('
', {
          id: name,
          class: 'modal-content features',
        });
        $div.append($h3);

        if (!$soxSettingsDialogFeatures.find('div#header-for-' + name).length) {
          $soxSettingsDialogFeatures.append($div);
          $div.after($content);
        }
      }

      function addFeature(category, name, description, featureSettings, extendedDescription, metaLink, featurePacks, usesApi) {
        const blockFeatureSelection = usesApi && !sox.settings.accessToken;

        const $div = $('
', {
          'class': 'sox-feature ' + (featurePacks.length ? featurePacks.join(' ') : '') + (blockFeatureSelection ? ' disabled-feature' : ''),
          'title': blockFeatureSelection ? 'You must get an access token to enable this feature (click the key button at the bottom of the SOX dialog)' : '',
        });

        const $info = sox.sprites.getSvg('info').hover(function() {
          if (extendedDescription && !$(this).parent().find('.sox-feature-info').length) {
            $(this).parent().append($('
', {
              'class': 'sox-feature-info',
              'html': extendedDescription + (metaLink ? ' [meta]' : ''),
            }));
          }
        });

        const $label = $('');
        const $input = $('<input/>', {
          id: name,
          class: 's-checkbox',
          type: 'checkbox',
        }).prop('disabled', blockFeatureSelection);

        $div.on('mouseleave', function() {
          $(this).find('.sox-feature-info').remove();
        }).append($label).append(extendedDescription ? $info : '');
        $label.append($input);
        $input.after(description);
        $soxSettingsDialogFeatures.find('#' + category).append($div);

        if (featureSettings) {
          const $settingsDiv = $('
', {
            id: 'feature-settings-' + name,
            class: 'sox-feature-settings',
            style: 'display: none; margin-top: 5px;',
          });

          const $settingsToggle = sox.sprites.getSvg('wrench', 'Edit this feature\'s settings').click(e => {
            e.preventDefault(); //don't uncheck the checkbox

            const $settingsPanel = $('#feature-settings-' + name);
            $settingsPanel.is(':visible') ? $settingsPanel.fadeOut() : $settingsPanel.fadeIn();
          });

          const optionalSettings = GM_getValue('SOX-' + name + '-settings', -1);

          for (let i = 0; i < featureSettings.length; i++) {
            const currentSetting = featureSettings[i];
            $settingsDiv
              .append(sox.helpers.newElement(currentSetting.type, { //use newElement helper so the type can be things like 'checkbox' or 'radio'
                id: currentSetting.id,
                'class': currentSetting.type === 'textarea' ? 'featureSetting s-input' : 'featureSetting s-checkbox',
                'style': 'margin-right: 5px',
                'checked': (currentSetting.type === 'checkbox' ? JSON.parse(optionalSettings)[currentSetting.id] : false),
                value: (optionalSettings === -1 ? '' : JSON.parse(optionalSettings)[currentSetting.id]),
              }))
              .append(currentSetting.desc)
              .append('
');
          }

          const $saveFeatureSettings = $('', {
            id: 'saveSettings-' + name,
            class: 'action s-btn s-btn__secondary s-btn__sm',
            text: 'Save Settings',
            click: function(e) {
              e.preventDefault(); //don't uncheck the checkbox
              const settingsToSave = {};
              $('.sox-feature.disabled-feature input[type="checkbox"]').prop('checked', false); //uncheck any features that somehow were checked (they shouldn't be able to through the UI) but should be disabled (user doesn't have access token)
              $(this).parent().find('.featureSetting').each(function() {
                settingsToSave[$(this).attr('id')] = ($(this).is(':checkbox') ? $(this).is(':checked') : $(this).val());
              });
              GM_setValue('SOX-' + name + '-settings', JSON.stringify(settingsToSave));
              sox.settings.writeToConsole(true);
              alert('Saved!');
            },
          });

          $settingsDiv.append($saveFeatureSettings);

          const $feature = $soxSettingsDialogFeatures.find('input#' + name).parent();
          $feature.append($settingsToggle);
          $div.has('.sox-sprite-info').length ? $info.after($settingsDiv) : $feature.append($settingsDiv);
        }
      }

      // display sox version number in the dialog
      version != 'unknown' && version !== null ? $soxSettingsDialogVersion.text(' v' + (version ? version.toLowerCase() : '')) : $soxSettingsDialogVersion.text('');

      if (version !== lastVersionInstalled) {
        GM_setValue('SOX-lastVersionInstalled', version);
        const $newVersionDetailsContainer = $('
', {
          'class': 'sox-new-version-details',
        });

        const $newVersionHeader = $('
', {
          'class': 'header category',
          'html': '
new in this version
',
        });

        const $changes = $('
');

        for (let i = 0; i < changes.length; i++) {
          $changes.append($('
', {
            'html': changes[i], //this array is defined near the top of the file
            'class': 'sox-new-version-item',
          }));
        }

        const $newVersionInfoContainer = $('
', {
          'class': 'modal-content',
          'html': $changes,
        });

        $soxSettingsDialogFeatures.append($newVersionDetailsContainer.append($newVersionHeader).append($newVersionInfoContainer));
      }

      if (sox.info.debugging) $soxSettingsDebugging.text('Disable debugging');

      // wire up event handlers
      $soxSettingsClose.on('click', () => {
        $soxSettingsDialog.hide();
      });

      $soxSettingsReset.on('click', () => {
        if (confirm('Are you sure you want to reset SOX?')) {
          sox.settings.reset();
          location.reload(); // reload page to reflect changed settings
        }
      });

      $soxSettingsDebugging.on('click', () => {
        const currentState = sox.info.debugging;
        if (typeof currentState === 'undefined') {
          GM_setValue('SOX-debug', true);
          $soxSettingsDebugging.text('Disable debugging');
        } else {
          GM_setValue('SOX-debug', !currentState);
          $soxSettingsDebugging.text(currentState ? 'Enable debugging' : 'Disable debugging');
        }
        location.reload();
      });

      $soxSettingsNewAccessTokenButton.on('click', () => {
        window.open('https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/');
        sox.loginfo('To get a new access token, please go to the following URL', 'https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/');
      });

      $soxSettingsToggle.on('click', function() {
        const $icon = $(this).find('i');

        const checked = $icon.hasClass('fas');
        checked ? $icon.removeClass('fas').addClass('far') : $icon.removeClass('far').addClass('fas');

        $soxSettingsDialogFeatures.find('input').prop('checked', !checked);
      });

      $soxSettingsSave.on('click', () => {
        const settings = [];
        $soxSettingsDialogFeatures.find('input[type=checkbox]:checked').not('.featureSetting').each(function() { //NOT the per-feature featureSetting checkboxes, because they are saved in THEIR OWN setting object!
          const x = $(this).closest('.modal-content').attr('id') + '-' + $(this).attr('id');
          settings.push(x); //Add the function's ID (also the checkbox's ID) to the array
        });

        sox.settings.save(settings);
        location.reload(); // reload page to reflect changed settings
      });

      $importSettingsButton.on('click', () => {
        const settingsToImport = window.prompt('Please paste the settings exactly as they were given to you');
        if (!settingsToImport) return;
        sox.settings.save(settingsToImport);
        location.reload();
      });

      $exportSettingsButton.on('click', () => {
        window.prompt('Your settings are below. Press Ctrl/Cmd + C to copy.', JSON.stringify(sox.settings.load()));
      });

      $searchBox.on('keyup keydown', function() { //search box
        if ($(this).val() !== '') {
          const searchQuery = $(this).val();
          $('.sox-new-version-details').hide();
          $('#sox-settings-dialog .sox-feature').each(function() {
            $(this).find('label').text().match(new RegExp(searchQuery, 'i')) ? $(this).show() : $(this).hide();
          });
        } else {
          $('.category, .features, #sox-settings-dialog .sox-feature, .sox-new-version-details').fadeIn();
        }
      });

      $featurePackButtons.click(function() {
        $('#sox-settings-dialog .sox-feature').removeClass('feature-fade-out');
        if ($(this).is('.clear-feature-pack-selection')) return;
        $('#sox-settings-dialog .sox-feature').not('.' + $(this).attr('data-feature-pack-id')).addClass('feature-fade-out');
      });

      // create sox settings button
      const $soxSettingsButton = $('', {
        id: 'soxSettingsButton',
        class: 'sox-settings-button -link',
        title: 'Change SOX settings',
        href: '#',
        click: function(e) {
          e.preventDefault();
          $('#sox-settings-dialog').toggle();
          if ($soxSettingsDialog.is(':visible')) {
            $(this).addClass('topbar-icon-on');
            $soxSettingsDialog.find('#search').focus();
          } else {
            $(this).removeClass('topbar-icon-on');
          }
        },
      });

      // Very basic 'dark theme' support. See https://github.com/soscripted/sox/issues/406
      // Not sure what the best way to detect dark mode is; the following just checks to
      // see if 's text color is #ccc (grey/rgb(204,204,204)). Might need changing
      // in future
      if ($('body').css('color') === 'rgb(204, 204, 204)') {
        sox.debug('Dark mode detected, tweaking SOX CSS');
        $soxSettingsDialog.addClass('dark-mode');
      }

      const $icon = sox.sprites.getSvg('settings', 'Change your SOX settings', {
        fill: $('.top-bar .-secondary .-link').css('color'),
        width: '25px',
        height: '25px',
      });

      //close dialog if clicked outside it
      $(document).click(e => { //close dialog if clicked outside it
        const $target = $(e.target);
        const isToggle = $target.is('#soxSettingsButton, #sox-settings-dialog');
        const isChild = $target.parents('#soxSettingsButton, #sox-settings-dialog').is('#soxSettingsButton, #sox-settings-dialog');

        if (!isToggle && !isChild) {
          $soxSettingsDialog.hide();
          $soxSettingsButton.removeClass('topbar-icon-on');
        }
      });

      //close dialog if one of the links on the topbar is clicked
      $('.topbar-icon, .-link').not('.sox-settings-button').click(() => {
        $soxSettingsDialog.hide();
        $soxSettingsButton.removeClass('topbar-icon-on');
      });

      // load features into dialog
      sox.debug('injecting features into dialog');
      for (const category in features.categories) {
        addCategory(category);
        for (const feature in features.categories[category]) {
          const currentFeature = features.categories[category][feature];
          addFeature(
            category,
            currentFeature.name,
            currentFeature.desc,
            (currentFeature.settings ? currentFeature.settings : false), //add the settings panel for this feautre if indicated in the JSON
            (currentFeature.extended_description ? currentFeature.extended_description : false), //add the extra description on hover if the feature has the extended description
            (currentFeature.meta ? currentFeature.meta : false), //add the meta link to the extra description on hover
            (currentFeature.feature_packs ? currentFeature.feature_packs : []),
            (currentFeature.usesApi ? currentFeature.usesApi : false)
          );
        }
      }

      if (settings) {
        for (let i = 0; i < settings.length; ++i) {
          $soxSettingsDialogFeatures.find('#' + settings[i].split('-')[1]).prop('checked', true);
        }
      } else { // no settings found, mark all inputs as checked and display settings dialog
        //note: the .not() is to make sure any disabled features (user doesn't have access token) aren't selected by default
        $soxSettingsDialogFeatures.find('input').not('.sox-feature.disabled-feature input').prop('checked', true);
        $soxSettingsButton.addClass('topbar-icon-on');
        $soxSettingsDialog.show();
      }

      // add dialog to corral and sox button to topbar
      $soxSettingsButton.append($icon);
      // The following check is because SO doesn't have inbox, achievements help centre and site switcher items
      if ($('.inbox-button-item').length) {
        $('.inbox-button-item').before($('
').addClass('-item').append($soxSettingsButton));
      } else {
        $('.js-searchbar-trigger').after($('
').addClass('-item').append($soxSettingsButton));
      }

      $soxSettingsDialog.css({
        'top': $('.top-bar').height(),
        'right': $('.-container').outerWidth() - $('#soxSettingsButton').parent().position().left - $('#soxSettingsButton').outerWidth(),
      });

      //only add dialog if button was added successfully
      if ($('#soxSettingsButton').length) $('.js-topbar-dialog-corral').append($soxSettingsDialog);
    },
  };
})(window.sox = window.sox || {}, jQuery);
<|endoftext|>