<commit_before>const Discord = require('discord.js');
const utils = require('./utils');
const actions = require('./botActions');
const log = require('./logger').getLogger();
const config = require('./configManager').getConfigManager();

class Bot {

  constructor(commands, token, guildSettings, guildLevels) {
    this.commands = commands.commands;
    this.prefix = commands.prefix;
    this.token = token;
    this.guildSettings = guildSettings;
    this.guildLevels = guildLevels;
    this.configureBot();
    this.resetBot();
  }

// sets all the handlers for bot actions
  configureBot() {
    this.bot = new Discord.Client();
    this.bot.on('ready', () => {
      log.info('Mari bot ready for combat!');
    });

    this.bot.on('message', (msg) => {
      this.handleMessage(msg);
    });

    this.bot.on('guildMemberAdd', (member) => {
      let guildSettings = this.guildSettings[member.guild.name];
      if (guildSettings && guildSettings.welcomeMessage && guildSettings.welcomeChannel) {
        actions.welcomeMember(member, guildSettings);
      }
    });

    this.bot.on('voiceStateUpdate', (newMember, oldMember) => {
      this.newPhoneWhoDis(newMember, oldMember);
    });

    this.bot.on('messageReactionAdd', (reaction) => {
      this.handleReactionAdded(reaction);
    });

    this.bot.on('messageReactionRemove', (reaction) => {
      this.handleReactionRemoved(reaction);
    });

    this.bot.on('error', (e) => {
      log.error('ERROR bot crashed!: ');
      for (let prop of e) {
        log.error(prop);
      }
      try {
        this.resetBot();
      } catch (e) {
        log.error('Could not reset the bot: ' + e);
        process.exit(1);
      }
    });

    this.bot.on('warn', (warning) => {
      log.warn('warning: ' + warning);
    });

    this.bot.on('disconnect', (closeEvent) => {
      log.warn(`Websocket connection failed with error code ${closeEvent.code}! attempting to restart bot`);
      log.warn(closeEvent.reason);
      this.resetBot();
    });

    this.bot.on('debug', (info) => {
      // ignore heartbeats
      if (info.toLowerCase().includes('heartbeat')) {
        return;
      }
      log.info(`debug: ${info}`);
    });
  }

  handleReactionAdded(reaction) {
    // this means the bot has already added this reaction
    if (reaction.me) {
      return;
    }
    if (this.guildSettings[reaction.message.channel.guild.name].react) {
      reaction.message.react(reaction.emoji).then(() => {
        log.info('Reacted with ' + reaction.emoji);
      }).catch((e) => {
        log.error('Failed to react to message: ' + e);
      });
    }
  }

  handleReactionRemoved(reaction) {
    // don't remove until the bot is the only one left who's reacted
    if (reaction.users.length > 1) {
      return;
    }
    if (this.guildSettings[reaction.message.channel.guild.name].react) {
      if (reaction.users.get(this.bot.user.id)) {
        reaction.remove(this.bot.user).then(() => {
          log.info('Removed reaction ' + reaction.emoji);
        }).catch((e) => {
          log.error('Failed to remove reaction: ' + e);
        });
      }
    }
  }

  // NEW PHONE WHO DIS
  // play new phone audio clip when a new user comes into the same channel as the bot
  newPhoneWhoDis(oldMember, newMember) {
    if (this.bot.voiceConnections.size === 0) {
      return;
    }
    if (oldMember && newMember) {
      if (oldMember.mute !== newMember.mute || oldMember.deaf !== newMember.deaf) {
        return;
      }
    }
    if (newMember && newMember.user.voiceChannel) {
      const voiceConnection = actions.getChannelVoice(newMember.voiceChannel.id, this.bot.voiceConnections);
      if (voiceConnection) {
        actions.playAudioCommand(this.bot.voiceConnections, this.commands['newphone'], newMember.user.voiceChannel.id, voiceConnection);
      }
    }
  }

  // handling of normal commands
  // check if this channel allows the bot and if this user can use the bot in this server.
  // Then, if the message contains a command the bot can understand, handle it.
  // then pass along to the handler function
  handleMessage(msg) {
    // don't respond to your own messages
    if (msg.author.username === 'mari-bot') {
      return;
    }

    // storing memes for later use
    if (msg.channel && msg.channel.name && msg.channel.name.includes('memes')) {
      let words = msg.content.split(' ');
      for (let i = 0; i < words.length; i++) {
        if (utils.isURL(words[i])) {
          if (this.commands.meme.urls.indexOf(words[i]) === -1) {
            this.commands.meme.urls.push(words[i]);
            this.commandsUpdated = true;
            log.info('Added a new meme to my collection: \n' + words[i]);
          } else {
            log.info('Avoided duplicate meme: ' + words[i]);
          }
        }
      }
    }

    // load data for current guild setup and user levels
    // no guild means message is PM, so guild restrictions are not applicable
    let currentGuildSettings = msg.channel.guild ? this.guildSettings[msg.channel.guild.name] : null;
    let currentGuildLevels = msg.channel.guild ? this.guildLevels[msg.channel.guild.name] : null;

    // check if we should level up a user
    if (currentGuildSettings && currentGuildLevels) {
      actions.levelUpUser(currentGuildLevels, currentGuildSettings, msg.author, msg.channel);
    }

    // ignore if message doesn't start with the prefix
    if (!msg.content.startsWith(this.prefix)) {
      return;
    }

    // check if this is a channel that the bot should read
    // if no registered settings assume no restrictions
    if (currentGuildSettings) {
      if (!this.botCanPostToChannel(currentGuildSettings.channels, msg.channel)) { // make sure this channel is ok to use
        msg.author.send('Sorry, you can\'t use mari-bot from ' + msg.channel.name + ' in ' + msg.channel.guild.name);
        return;
      }
      if (!this.userAllowedToUseBot(currentGuildSettings.roles, msg.member.roles)) { // make sure user is allowed to use bot
        msg.author.send('Sorry, you don\'t have permission to use mari-bot in ' + msg.channel.guild.name);
        return;
      }
    }
    // commands can't have spaces, remove anything beyond the first space
    let [importantBit] = msg.content.split(' ');
    // cut out the prefix
    importantBit = importantBit.toLowerCase().slice(1);
    log.info('Received: ' + importantBit);
    for (let command in this.commands) {
      if (!this.commands.hasOwnProperty(command)) {
        continue;
      }
      if (importantBit === command) {
        this.handleCommand(this.commands[command], msg, currentGuildLevels, currentGuildSettings);
      }
    }
  }

  userAllowedToUseBot(allowedRoles, userRoles) {
    // if no options, assume all are allowed
    if (!allowedRoles) {
      return true;
    }
    for (let role of allowedRoles) {
      if (userRoles.filter((userRole) => userRole.name.toLowerCase() === role.toLowerCase()).size) {
        return true;
      }
    }
    return false;
  }

  botCanPostToChannel(allowedChannels, channel) {
    // if no options, assume all are allowed
    if (!allowedChannels) {
      return true;
    }
    return !!allowedChannels.filter((channelName) => channel.name === channelName).length;
  }

// Reset the bot (or start it if it's not already running)
// if channel is given, notify that channel when reset is complete
  resetBot(channel) {
    if (this.bot && this.bot.readyTimestamp) {
      this.bot.destroy().then(() => {
        this.bot.login(this.token).then(() => {
          log.info('Reset complete!');
        });
      }).catch((reason) => {
        log.info('Failed to logout: ' + reason);
      });
    } else {
      this.bot.login(this.token).then(() => {
        if (channel) {
          channel.send('Reset complete!');
        }
      });
    }
  }

// breakout command types into their handler functions
  handleCommand(command, msg, guildLevels, guildSettings) {
    let type = command.type.toLowerCase();
    switch (type) {
      case 'audio':
        actions.handleAudioCommand(command, msg);
        break;
      case 'stop':
        actions.stopTalkingInGuild(msg.guild, this.bot.voiceConnections);
        break;
      case 'text':
        if (command.response) {
          actions.sendMessage(command.response, msg.channel);
        } else {
          let beginning = command.beginning ? command.beginning : '';
          let response = command.responses[Math.floor(Math.random() * command.responses.length)];
          let ending = command.ending ? command.ending : '';
          actions.sendMessage(beginning + response + ending, msg.channel);
        }
        break;
      case 'move':
        actions.joinChannel(this.bot.guilds, msg);
        break;
      case 'leave':
        const connection = actions.getVoiceInGuild(this.bot.voiceConnections, msg.guild);
        if (connection) {
          connection.disconnect();
        }
        break;
      case 'go':
        const channelName = msg.content.substring(4);
        log.info('Moving to: ' + channelName);
        actions.joinChannel(this.bot.guilds, null, channelName);
        break;
      case 'meme':
        const urls = command.urls;
        let url = urls[Math.floor(Math.random() * urls.length)];
        actions.sendMessage(url, msg.channel);
        break;
      case 'help':
        actions.sendHelpMessage(msg, this.commands);
        break;
      case 'level':
        const userName = msg.content.substring(7);
        const level = actions.getLevelOfUser(guildLevels, guildSettings, msg.channel.guild.members, userName);
        if (level) {
          actions.sendMessage(`${userName} is level ${level}`, msg.channel);
        } else {
          actions.sendMessage(`${userName} is not a user in this discord server`, msg.channel);
        }
        break;
      case 'reset':
        config.readCommands().then((commands) => {
          this.setConfigAndReset(commands, msg.channel);
        });
        break;
      default:
        actions.sendMessage('Something\'s fucked. Yell at Taylor to fix it.', msg.channel);
        break;
    }
  }

  sendSubMessage(streamer) {
    let msg = (streamer.message ? streamer.message : streamer.name + ' is now live on twitch! https://www.twitch.tv/' + streamer.name);
    for (let server of streamer.servers) {
      actions.sendMessage(msg, this.bot.guilds.get(server.id).channels.get(server.channel));
    }
  }

  setConfigAndReset(data, channel, memes) {
    this.prefix = data.prefix;
    let tempMemes = this.commands.meme;
    this.commands = data.commands;
    if (memes) {
      this.commands.meme = memes;
    } else {
      this.commands.meme = tempMemes;
    }
    // start your engines!
    this.resetBot(channel);
  }
}

module.exports = Bot;<commit_msg>fixed reactions in PM's<commit_after>const Discord = require('discord.js');
const utils = require('./utils');
const actions = require('./botActions');
const log = require('./logger').getLogger();
const config = require('./configManager').getConfigManager();

class Bot {

  constructor(commands, token, guildSettings, guildLevels) {
    this.commands = commands.commands;
    this.prefix = commands.prefix;
    this.token = token;
    this.guildSettings = guildSettings;
    this.guildLevels = guildLevels;
    this.configureBot();
    this.resetBot();
  }

// sets all the handlers for bot actions
  configureBot() {
    this.bot = new Discord.Client();
    this.bot.on('ready', () => {
      log.info('Mari bot ready for combat!');
    });

    this.bot.on('message', (msg) => {
      this.handleMessage(msg);
    });

    this.bot.on('guildMemberAdd', (member) => {
      let guildSettings = this.guildSettings[member.guild.name];
      if (guildSettings && guildSettings.welcomeMessage && guildSettings.welcomeChannel) {
        actions.welcomeMember(member, guildSettings);
      }
    });

    this.bot.on('voiceStateUpdate', (newMember, oldMember) => {
      this.newPhoneWhoDis(newMember, oldMember);
    });

    this.bot.on('messageReactionAdd', (reaction) => {
      this.handleReactionAdded(reaction);
    });

    this.bot.on('messageReactionRemove', (reaction) => {
      this.handleReactionRemoved(reaction);
    });

    this.bot.on('error', (e) => {
      log.error('ERROR bot crashed!: ');
      for (let prop of e) {
        log.error(prop);
      }
      try {
        this.resetBot();
      } catch (e) {
        log.error('Could not reset the bot: ' + e);
        process.exit(1);
      }
    });

    this.bot.on('warn', (warning) => {
      log.warn('warning: ' + warning);
    });

    this.bot.on('disconnect', (closeEvent) => {
      log.warn(`Websocket connection failed with error code ${closeEvent.code}! attempting to restart bot`);
      log.warn(closeEvent.reason);
      this.resetBot();
    });

    this.bot.on('debug', (info) => {
      // ignore heartbeats
      if (info.toLowerCase().includes('heartbeat')) {
        return;
      }
      log.info(`debug: ${info}`);
    });
  }

  handleReactionAdded(reaction) {
    // this means the bot has already added this reaction
    if (reaction.me) {
      return;
    }
    let { channel } = reaction.message;
    if (!channel.guild || this.guildSettings[channel.guild.name].react) {
      reaction.message.react(reaction.emoji).then(() => {
        log.info('Reacted with ' + reaction.emoji);
      }).catch((e) => {
        log.error('Failed to react to message: ' + e);
      });
    }
  }

  handleReactionRemoved(reaction) {
    // don't remove until the bot is the only one left who's reacted
    if (reaction.users.length > 1) {
      return;
    }
    let { channel } = reaction.message;
    if (!channel.guild || this.guildSettings[channel.guild.name].react) {
      if (reaction.users.get(this.bot.user.id)) {
        reaction.remove(this.bot.user).then(() => {
          log.info('Removed reaction ' + reaction.emoji);
        }).catch((e) => {
          log.error('Failed to remove reaction: ' + e);
        });
      }
    }
  }

  // NEW PHONE WHO DIS
  // play new phone audio clip when a new user comes into the same channel as the bot
  newPhoneWhoDis(oldMember, newMember) {
    if (this.bot.voiceConnections.size === 0) {
      return;
    }
    if (oldMember && newMember) {
      if (oldMember.mute !== newMember.mute || oldMember.deaf !== newMember.deaf) {
        return;
      }
    }
    if (newMember && newMember.user.voiceChannel) {
      const voiceConnection = actions.getChannelVoice(newMember.voiceChannel.id, this.bot.voiceConnections);
      if (voiceConnection) {
        actions.playAudioCommand(this.bot.voiceConnections, this.commands['newphone'], newMember.user.voiceChannel.id, voiceConnection);
      }
    }
  }

  // handling of normal commands
  // check if this channel allows the bot and if this user can use the bot in this server.
  // Then, if the message contains a command the bot can understand, handle it.
  // then pass along to the handler function
  handleMessage(msg) {
    // don't respond to your own messages
    if (msg.author.username === 'mari-bot') {
      return;
    }

    // storing memes for later use
    if (msg.channel && msg.channel.name && msg.channel.name.includes('memes')) {
      let words = msg.content.split(' ');
      for (let i = 0; i < words.length; i++) {
        if (utils.isURL(words[i])) {
          if (this.commands.meme.urls.indexOf(words[i]) === -1) {
            this.commands.meme.urls.push(words[i]);
            this.commandsUpdated = true;
            log.info('Added a new meme to my collection: \n' + words[i]);
          } else {
            log.info('Avoided duplicate meme: ' + words[i]);
          }
        }
      }
    }

    // load data for current guild setup and user levels
    // no guild means message is PM, so guild restrictions are not applicable
    let currentGuildSettings = msg.channel.guild ? this.guildSettings[msg.channel.guild.name] : null;
    let currentGuildLevels = msg.channel.guild ? this.guildLevels[msg.channel.guild.name] : null;

    // check if we should level up a user
    if (currentGuildSettings && currentGuildLevels) {
      actions.levelUpUser(currentGuildLevels, currentGuildSettings, msg.author, msg.channel);
    }

    // ignore if message doesn't start with the prefix
    if (!msg.content.startsWith(this.prefix)) {
      return;
    }

    // check if this is a channel that the bot should read
    // if no registered settings assume no restrictions
    if (currentGuildSettings) {
      if (!this.botCanPostToChannel(currentGuildSettings.channels, msg.channel)) { // make sure this channel is ok to use
        msg.author.send('Sorry, you can\'t use mari-bot from ' + msg.channel.name + ' in ' + msg.channel.guild.name);
        return;
      }
      if (!this.userAllowedToUseBot(currentGuildSettings.roles, msg.member.roles)) { // make sure user is allowed to use bot
        msg.author.send('Sorry, you don\'t have permission to use mari-bot in ' + msg.channel.guild.name);
        return;
      }
    }
    // commands can't have spaces, remove anything beyond the first space
    let [importantBit] = msg.content.split(' ');
    // cut out the prefix
    importantBit = importantBit.toLowerCase().slice(1);
    log.info('Received: ' + importantBit);
    for (let command in this.commands) {
      if (!this.commands.hasOwnProperty(command)) {
        continue;
      }
      if (importantBit === command) {
        this.handleCommand(this.commands[command], msg, currentGuildLevels, currentGuildSettings);
      }
    }
  }

  userAllowedToUseBot(allowedRoles, userRoles) {
    // if no options, assume all are allowed
    if (!allowedRoles) {
      return true;
    }
    for (let role of allowedRoles) {
      if (userRoles.filter((userRole) => userRole.name.toLowerCase() === role.toLowerCase()).size) {
        return true;
      }
    }
    return false;
  }

  botCanPostToChannel(allowedChannels, channel) {
    // if no options, assume all are allowed
    if (!allowedChannels) {
      return true;
    }
    return !!allowedChannels.filter((channelName) => channel.name === channelName).length;
  }

// Reset the bot (or start it if it's not already running)
// if channel is given, notify that channel when reset is complete
  resetBot(channel) {
    if (this.bot && this.bot.readyTimestamp) {
      this.bot.destroy().then(() => {
        this.bot.login(this.token).then(() => {
          log.info('Reset complete!');
        });
      }).catch((reason) => {
        log.info('Failed to logout: ' + reason);
      });
    } else {
      this.bot.login(this.token).then(() => {
        if (channel) {
          channel.send('Reset complete!');
        }
      });
    }
  }

// breakout command types into their handler functions
  handleCommand(command, msg, guildLevels, guildSettings) {
    let type = command.type.toLowerCase();
    switch (type) {
      case 'audio':
        actions.handleAudioCommand(command, msg);
        break;
      case 'stop':
        actions.stopTalkingInGuild(msg.guild, this.bot.voiceConnections);
        break;
      case 'text':
        if (command.response) {
          actions.sendMessage(command.response, msg.channel);
        } else {
          let beginning = command.beginning ? command.beginning : '';
          let response = command.responses[Math.floor(Math.random() * command.responses.length)];
          let ending = command.ending ? command.ending : '';
          actions.sendMessage(beginning + response + ending, msg.channel);
        }
        break;
      case 'move':
        actions.joinChannel(this.bot.guilds, msg);
        break;
      case 'leave':
        const connection = actions.getVoiceInGuild(this.bot.voiceConnections, msg.guild);
        if (connection) {
          connection.disconnect();
        }
        break;
      case 'go':
        const channelName = msg.content.substring(4);
        log.info('Moving to: ' + channelName);
        actions.joinChannel(this.bot.guilds, null, channelName);
        break;
      case 'meme':
        const urls = command.urls;
        let url = urls[Math.floor(Math.random() * urls.length)];
        actions.sendMessage(url, msg.channel);
        break;
      case 'help':
        actions.sendHelpMessage(msg, this.commands);
        break;
      case 'level':
        const userName = msg.content.substring(7);
        const level = actions.getLevelOfUser(guildLevels, guildSettings, msg.channel.guild.members, userName);
        if (level) {
          actions.sendMessage(`${userName} is level ${level}`, msg.channel);
        } else {
          actions.sendMessage(`${userName} is not a user in this discord server`, msg.channel);
        }
        break;
      case 'reset':
        config.readCommands().then((commands) => {
          this.setConfigAndReset(commands, msg.channel);
        });
        break;
      default:
        actions.sendMessage('Something\'s fucked. Yell at Taylor to fix it.', msg.channel);
        break;
    }
  }

  sendSubMessage(streamer) {
    let msg = (streamer.message ? streamer.message : streamer.name + ' is now live on twitch! https://www.twitch.tv/' + streamer.name);
    for (let server of streamer.servers) {
      actions.sendMessage(msg, this.bot.guilds.get(server.id).channels.get(server.channel));
    }
  }

  setConfigAndReset(data, channel, memes) {
    this.prefix = data.prefix;
    let tempMemes = this.commands.meme;
    this.commands = data.commands;
    if (memes) {
      this.commands.meme = memes;
    } else {
      this.commands.meme = tempMemes;
    }
    // start your engines!
    this.resetBot(channel);
  }
}

module.exports = Bot;<|endoftext|>


<commit_before>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 */

var ajaxTimeout = {config name="ajaxTimeout"};

if (ajaxTimeout >= 6) {
    Ext.Ajax.timeout= ajaxTimeout * 1000;

    Ext.override(Ext.form.Basic,
        { timeout: ajaxTimeout }
    );
    Ext.override(Ext.data.proxy.Server,
        { timeout: Ext.Ajax.timeout }
    );
    Ext.override(Ext.data.Connection,
        { timeout: Ext.Ajax.timeout }
    );
}
<commit_msg>SW-17911 - fix javascript error on loading backend if reading of config fails<commit_after>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 */

var ajaxTimeout = {if {config name="ajaxTimeout"}}{config name="ajaxTimeout"}{else}30{/if};

if (ajaxTimeout >= 6) {
    Ext.Ajax.timeout= ajaxTimeout * 1000;

    Ext.override(Ext.form.Basic,
        { timeout: ajaxTimeout }
    );
    Ext.override(Ext.data.proxy.Server,
        { timeout: Ext.Ajax.timeout }
    );
    Ext.override(Ext.data.Connection,
        { timeout: Ext.Ajax.timeout }
    );
}
<|endoftext|>


<commit_before>"use strict";

import { intersection } from "../../../src/iterable/intersection";

describe("intersection()", function () {
    it("should yield the intersection of two sorted iterators when first element of 'this' is higher than the first element of the argument", function () {
        [...[1,2,3,4,5]::intersection([2,3,4,6], function (b) {
            return this - b;
        })].should.deep.equal([2,3,4]);
    });

    it("should yield the intersection of two iterators when the first element of 'this' is lower than the first element of the argument", function () {
        [...[3,4,5,6,7]::intersection([2,3,4,6], function (b) {
            return this - b;
        })].should.deep.equal([3,4,6]);
    });
});
<commit_msg>fix typo<commit_after>"use strict";

import { intersection } from "../../../src/iterable/intersection";

describe("intersection()", function () {
    it("should yield the intersection of two sorted iterators when first element of 'this' is lower than the first element of the argument", function () {
        [...[1,2,3,4,5]::intersection([2,3,4,6], function (b) {
            return this - b;
        })].should.deep.equal([2,3,4]);
    });

    it("should yield the intersection of two iterators when the first element of 'this' is higher than the first element of the argument", function () {
        [...[3,4,5,6,7]::intersection([2,3,4,6], function (b) {
            return this - b;
        })].should.deep.equal([3,4,6]);
    });
});
<|endoftext|>


<commit_before>//		CoblerJS 0.2.0
//		(c) 2011-2016 Adam Smallcomb
//		Licensed under the MIT license.
//		For all details and documentation:
//		https://github.com/Cloverstone/Cobler

function Cobler(options) {
  var topics = {};
	this.options = options
	this.options.active = this.options.active || 'widget_active';
	this.options.itemContainer = this.options.itemContainer || 'itemContainer';
	this.options.itemTarget = this.options.itemTarget || 'cobler-li-content';

  options.removed = false;
	//simple event bus with the topics object bound
  this.subscribe = function(topic, listener) {
    if(!topics[topic]) topics[topic] = [];
    topics[topic].push(listener);
  }.bind({topics: topics})
  this.publish = function(topic, data) {
    if(!topics[topic] || topics[topic].length < 1) return;
    topics[topic].forEach(function(listener) {
      listener(data || {});
    });
  }.bind({topics: topics})

  //initialize collections array and then create a collection for each target
	var collections = [];
	for(var i=0; i<options.targets.length; i++){
		addCollection.call(this, options.targets[i], options.items[i]);
	}

	function collection(target, items, cob){
		var sortable;
		function init() {
			target.addEventListener('click', eventManager.bind(this));
			if(!cob.options.disabled) {
				target.addEventListener('click', instanceManager.bind(this));
				target.className += ' cobler_container';
				sortable = Sortable.create(target, {
					forceFallback: !!cob.options.fallback,
					group: cob.options.group || 'cb',
					animation: 50,
					onSort: function (/**Event*/evt) {
						if(cob.options.remove) {
								cob.options.removed = items.splice(parseInt(evt.item.dataset.start, 10), 1)[0];
								cob.options.remove = false;
						}else if(evt.from !== evt.to && typeof evt.item.dataset.type === 'undefined'){
							cob.options.remove = true;
						}
			    },
					onAdd: addOnDrop.bind(this),
					onUpdate: function (evt) {
						var item = items.splice(parseInt(evt.item.dataset.start, 10), 1)[0];
						items.splice(getNodeIndex(evt.item), 0 , item);
						evt.item.removeAttribute('data-start');
						cob.publish('change', item);
						cob.publish('reorder', item);
					},
					onStart: function (evt) {
		        evt.item.dataset.start = getNodeIndex(evt.item);  // element index within parent
		    	}
				});
			}
			loadItems.call(this, items);
		}
		function reset(items) {
			target.innerHTML = '';
			items = items || [];
		}
		function addOnDrop(evt){
			var A = evt.item;
			//handle if dragged over target and put back in original
			if(A.parentNode === target){
				var newItem;
			 	if(typeof A.dataset.type !== 'undefined') {
					newItem = new Cobler.types[A.dataset.type](this);
				}else{
					var temp = cob.options.removed.get();
					newItem = new Cobler.types[temp.widgetType](this);
					newItem.set(temp);
					evt.newIndex = getNodeIndex(evt.item);
				}
				var renderedItem = renderItem.call(this.owner,newItem);
			 	var a = A.parentNode.replaceChild(renderedItem, A);
				items.splice(evt.newIndex, 0 , newItem);
				if(typeof newItem.initialize !== 'undefined'){
					newItem.initialize(renderedItem)
				}

				if(typeof A.dataset.type !== 'undefined') {
			 		activate(renderedItem);
			 	}else{
			 		cob.options.removed = false;
			 	}
			}
			this.owner.publish('moved', newItem)
		}
		function eventManager(e){
			if(typeof e.target.dataset.event !== 'undefined'){
				var referenceNode = e.target.parentElement;
				while(referenceNode !== null && !referenceNode.classList.contains('slice') && !referenceNode.classList.contains('widget')){
					referenceNode = referenceNode.parentElement;
				}

				cob.publish(e.target.dataset.event, items[getNodeIndex(referenceNode)])
			}
		}
		function instanceManager(e) {
			var referenceNode = e.target.parentElement;
			while(referenceNode !== null && !referenceNode.classList.contains('slice') && !referenceNode.classList.contains('widget')){
				referenceNode = referenceNode.parentElement;
			}

			var classList = e.target.className.split(' ');
			if(classList.indexOf('remove-item') >= 0){
				if(confirm('Are you sure you want to delete this widget?')){
					var olditem = items.splice(getNodeIndex(referenceNode), 1);
					target.removeChild(referenceNode);
				 	cob.publish('remove', olditem);
				 	cob.publish('change', olditem);
			 	}
			}else if(classList.indexOf('duplicate-item') >= 0){
				deactivate();
				var index = getNodeIndex(referenceNode);
				addItem.call(this, items[index].get(), index+1);
			}else if(classList.indexOf('edit-item') >= 0){
				activate(referenceNode);
			}else if(e.target.tagName === 'LI' && target.className.indexOf('cobler_select') != -1) {
				deactivate();
				activate(e.target);
			}
		}
		function activate(targetEL) {
			targetEL.className += ' ' + cob.options.active;
			active = getNodeIndex(targetEL);
			cob.publish('activate', items[active]);
			items[active].edit();
			cob.publish('activated', items[active]);
		}
		function update(data, item) {
			var item = item || items[active];
			item.set(data);
			var temp = renderItem.call(cob,item);
			temp.className += ' ' + cob.options.active;
			var modEL = elementOf(item);
		 	var a = modEL.parentNode.replaceChild(temp, modEL);
		 	if(typeof item.initialize !== 'undefined'){
				item.initialize(temp)
			}
		 	cob.publish('change', item);
		}

		function deactivate() {
			active = null;
			var elems = target.getElementsByClassName(cob.options.active);
			[].forEach.call(elems, function(el) {
			    el.className = el.className.replace(cob.options.active, '');
			});
		}
		function loadItems(obj) {
			deactivate();
			reset(obj);
			items = [];
			for(var i in obj) {
				addItem.call(this, obj[i], false, true);
			}
		}
		function addItem(widgetType, index, silent) {
			if(typeof widgetType === 'undefined' || typeof Cobler.types[widgetType.widgetType || widgetType] === 'undefined') {
				return false;
			}
			index = index || items.length;
			var newItem = new Cobler.types[widgetType.widgetType || widgetType](this)
			if(typeof widgetType !== 'string'){
				newItem.set(widgetType);
			}
			items.splice(index, 0, newItem);
			var renderedItem = renderItem.call(this.owner, newItem);

			target.insertBefore(renderedItem, target.childNodes[index]);

			// target.insertBefore(renderedItem, target.querySelectorAll(':scope > LI')[index]);

			if(typeof newItem.initialize !== 'undefined'){
				newItem.initialize(renderedItem)
			}
			if(!silent){
				activate(renderedItem);
				cob.publish('change', newItem)
			}
		}
		function toJSON(opts) {
			var json = [];
			for(var i in items){
				json.push(items[i].toJSON(opts));
			}
			if(opts.object)return {target: target.dataset.id, items: json};
			return json;
		}
		function toHTML() {
			var temp = '';
			for(var i in items){
				temp += Cobler.types[items[i].widgetType].render(items[i]);
			}
			return temp;
		}
		function destroy(){
			reset();
			if(typeof sortable !== 'undefined') { sortable.destroy(); }
			target.removeEventListener('click', instanceManager);
			target.removeEventListener('click', eventManager);
		}
		function indexOf(item){
			return items.indexOf(item);
		}
		function elementOf(item){
				return target.children[items.indexOf(item)];
			}
		return {
			addItem: addItem,
			toJSON: toJSON,
			toHTML: toHTML,
			deactivate: deactivate,
			clear: reset,
			load: loadItems,
			update: update.bind(this),
			destroy: destroy,
			owner: cob,
			init: init,
			indexOf: indexOf,
			elementOf: elementOf
		}
	}

	function renderItem(item){
		var EL;
		if(options.disabled){
			EL = document.createElement('DIV');
		} else {
			EL = document.createElement('LI');
		}
		EL.className = 'slice';
		EL.innerHTML = templates[item.template || this.options.itemContainer].render(item.get(), templates);
		EL.getElementsByClassName(item.target || this.options.itemTarget)[0].innerHTML += item.render();
		return EL;
	}
	function getNodeIndex(node) {
	  var index = 0;
	  while (node = node.previousSibling) {
	    if (node.nodeType != 3 || !/^\s*$/.test(node.data)) {
	      index++;
	    }
	  }
	  return index;
	}
	function addCollection(target, item){
		var newCol = new collection(target, item, this);
		newCol.init();
		collections.push(newCol);
	}
	function addSource(element){
		Sortable.create(element, {
			group: {name: 'cb', pull: 'clone', put: false},
			sort: false
		});
	}
	function applyToEach(func){
		return function(opts){
			var temp = [];
			for(var i in collections) {
				temp.push(collections[i][func].call(null, opts));
			}
			this.publish(func, temp);
			return temp;
		}.bind(this)
	}

	return {
		collections: collections,
		addCollection: addCollection.bind(this),
		addSource: addSource,
		toJSON: applyToEach.call(this, 'toJSON'),
		toHTML: applyToEach.call(this, 'toHTML'),
		clear: applyToEach.call(this, 'clear'),
		deactivate: applyToEach.call(this, 'deactivate'),
		destroy: applyToEach.call(this, 'destroy'),
		on: this.subscribe//,
		//trigger: this.publish.bind(this)
	};
}

Cobler.types = {};

berryEditor = function(container){
	return function(){
		var formConfig = $.extend(true, {}, {
			// renderer: 'tabs',
			attributes: this.get(),
			fields: this.fields,
			autoDestroy: true
		}, this.formOptions || {});

		var opts = container.owner.options;
		var events = 'save';
		if(typeof opts.formTarget !== 'undefined' && opts.formTarget.length){
			formConfig.actions = false;
			events = 'change';
		}
		var myBerry = new Berry(formConfig, this.formTarget || $(container.elementOf(this)).find('.panel-body'));
		myBerry.on(events, function(){
		 	container.update(myBerry.toJSON(), this);
		 	container.deactivate();
		 	myBerry.trigger('saved');
		}, this);
		myBerry.on('cancel',function(){
		 	container.update(this.get(), this)
		 	container.deactivate();
		}, this)
		return myBerry;
	}
}
<commit_msg>fix bug on creation<commit_after>//		CoblerJS 0.2.0
//		(c) 2011-2016 Adam Smallcomb
//		Licensed under the MIT license.
//		For all details and documentation:
//		https://github.com/Cloverstone/Cobler

function Cobler(options) {
  var topics = {};
	this.options = options
	this.options.active = this.options.active || 'widget_active';
	this.options.itemContainer = this.options.itemContainer || 'itemContainer';
	this.options.itemTarget = this.options.itemTarget || 'cobler-li-content';

  options.removed = false;
	//simple event bus with the topics object bound
  this.subscribe = function(topic, listener) {
    if(!topics[topic]) topics[topic] = [];
    topics[topic].push(listener);
  }.bind({topics: topics})
  this.publish = function(topic, data) {
    if(!topics[topic] || topics[topic].length < 1) return;
    topics[topic].forEach(function(listener) {
      listener(data || {});
    });
  }.bind({topics: topics})

  //initialize collections array and then create a collection for each target
	var collections = [];
	for(var i=0; i<options.targets.length; i++){
		addCollection.call(this, options.targets[i], options.items[i]);
	}

	function collection(target, items, cob){
		var sortable;
		function init() {
			target.addEventListener('click', eventManager.bind(this));
			if(!cob.options.disabled) {
				target.addEventListener('click', instanceManager.bind(this));
				target.className += ' cobler_container';
				sortable = Sortable.create(target, {
					forceFallback: !!cob.options.fallback,
					group: cob.options.group || 'cb',
					animation: 50,
					onSort: function (/**Event*/evt) {
						if(cob.options.remove) {
								cob.options.removed = items.splice(parseInt(evt.item.dataset.start, 10), 1)[0];
								cob.options.remove = false;
						}else if(evt.from !== evt.to && typeof evt.item.dataset.type === 'undefined'){
							cob.options.remove = true;
						}
			    },
					onAdd: addOnDrop.bind(this),
					onUpdate: function (evt) {
						var item = items.splice(parseInt(evt.item.dataset.start, 10), 1)[0];
						items.splice(getNodeIndex(evt.item), 0 , item);
						evt.item.removeAttribute('data-start');
						cob.publish('change', item);
						cob.publish('reorder', item);
					},
					onStart: function (evt) {
		        evt.item.dataset.start = getNodeIndex(evt.item);  // element index within parent
		    	}
				});
			}
			loadItems.call(this, items);
		}
		function reset(items) {
			target.innerHTML = '';
			items = items || [];
		}
		function addOnDrop(evt){
			var A = evt.item;
			//handle if dragged over target and put back in original
			if(A.parentNode === target){
				var newItem;
			 	if(typeof A.dataset.type !== 'undefined') {
					newItem = new Cobler.types[A.dataset.type](this);
				}else{
					// var temp = cob.options.removed.get();
					var temp = cob.options.removed.toJSON({editor:true});
					newItem = new Cobler.types[temp.widgetType](this);
					newItem.set(temp);
					evt.newIndex = getNodeIndex(evt.item);
				}
				var renderedItem = renderItem.call(this.owner,newItem);
			 	var a = A.parentNode.replaceChild(renderedItem, A);
				items.splice(evt.newIndex, 0 , newItem);
				if(typeof newItem.initialize !== 'undefined'){
					newItem.initialize(renderedItem)
				}

				if(typeof A.dataset.type !== 'undefined') {
			 		activate(renderedItem);
			 	}else{
			 		cob.options.removed = false;
			 	}
			}
			this.owner.publish('moved', newItem)
		}
		function eventManager(e){
			if(typeof e.target.dataset.event !== 'undefined'){
				var referenceNode = e.target.parentElement;
				while(referenceNode !== null && !referenceNode.classList.contains('slice') && !referenceNode.classList.contains('widget')){
					referenceNode = referenceNode.parentElement;
				}

				cob.publish(e.target.dataset.event, items[getNodeIndex(referenceNode)])
			}
		}
		function instanceManager(e) {
			var referenceNode = e.target.parentElement;
			while(referenceNode !== null && !referenceNode.classList.contains('slice') && !referenceNode.classList.contains('widget')){
				referenceNode = referenceNode.parentElement;
			}

			var classList = e.target.className.split(' ');
			if(classList.indexOf('remove-item') >= 0){
				if(confirm('Are you sure you want to delete this widget?')){
					var olditem = items.splice(getNodeIndex(referenceNode), 1);
					target.removeChild(referenceNode);
				 	cob.publish('remove', olditem);
				 	cob.publish('change', olditem);
			 	}
			}else if(classList.indexOf('duplicate-item') >= 0){
				deactivate();
				var index = getNodeIndex(referenceNode);
				addItem.call(this, items[index].get(), index+1);
			}else if(classList.indexOf('edit-item') >= 0){
				activate(referenceNode);
			}else if(e.target.tagName === 'LI' && target.className.indexOf('cobler_select') != -1) {
				deactivate();
				activate(e.target);
			}
		}
		function activate(targetEL) {
			targetEL.className += ' ' + cob.options.active;
			active = getNodeIndex(targetEL);
			cob.publish('activate', items[active]);
			items[active].edit();
			cob.publish('activated', items[active]);
		}
		function update(data, item) {
			var item = item || items[active];
			item.set(data);
			var temp = renderItem.call(cob,item);
			temp.className += ' ' + cob.options.active;
			var modEL = elementOf(item);
		 	var a = modEL.parentNode.replaceChild(temp, modEL);
		 	if(typeof item.initialize !== 'undefined'){
				item.initialize(temp)
			}
		 	cob.publish('change', item);
		}

		function deactivate() {
			active = null;
			var elems = target.getElementsByClassName(cob.options.active);
			[].forEach.call(elems, function(el) {
			    el.className = el.className.replace(cob.options.active, '');
			});
		}
		function loadItems(obj) {
			deactivate();
			reset(obj);
			items = [];
			for(var i in obj) {
				addItem.call(this, obj[i], false, true);
			}
		}
		function addItem(widgetType, index, silent) {
			if(typeof widgetType === 'undefined' || typeof Cobler.types[widgetType.widgetType || widgetType] === 'undefined') {
				return false;
			}
			index = index || items.length;
			var newItem = new Cobler.types[widgetType.widgetType || widgetType](this)
			if(typeof widgetType !== 'string'){
				newItem.set(widgetType);
			}
			items.splice(index, 0, newItem);
			var renderedItem = renderItem.call(this.owner, newItem);

			target.insertBefore(renderedItem, target.childNodes[index]);

			// target.insertBefore(renderedItem, target.querySelectorAll(':scope > LI')[index]);

			if(typeof newItem.initialize !== 'undefined'){
				newItem.initialize(renderedItem)
			}
			if(!silent){
				activate(renderedItem);
				cob.publish('change', newItem)
			}
		}
		function toJSON(opts) {
			var json = [];
			for(var i in items){
				json.push(items[i].toJSON(opts));
			}
			if(opts.object)return {target: target.dataset.id, items: json};
			return json;
		}
		function toHTML() {
			var temp = '';
			for(var i in items){
				temp += Cobler.types[items[i].widgetType].render(items[i]);
			}
			return temp;
		}
		function destroy(){
			reset();
			if(typeof sortable !== 'undefined') { sortable.destroy(); }
			target.removeEventListener('click', instanceManager);
			target.removeEventListener('click', eventManager);
		}
		function indexOf(item){
			return items.indexOf(item);
		}
		function elementOf(item){
				return target.children[items.indexOf(item)];
			}
		return {
			addItem: addItem,
			toJSON: toJSON,
			toHTML: toHTML,
			deactivate: deactivate,
			clear: reset,
			load: loadItems,
			update: update.bind(this),
			destroy: destroy,
			owner: cob,
			init: init,
			indexOf: indexOf,
			elementOf: elementOf
		}
	}

	function renderItem(item){
		var EL;
		if(options.disabled){
			EL = document.createElement('DIV');
		} else {
			EL = document.createElement('LI');
		}
		EL.className = 'slice';
		EL.innerHTML = templates[item.template || this.options.itemContainer].render(item.get(), templates);
		EL.getElementsByClassName(item.target || this.options.itemTarget)[0].innerHTML += item.render();
		return EL;
	}
	function getNodeIndex(node) {
	  var index = 0;
	  while (node = node.previousSibling) {
	    if (node.nodeType != 3 || !/^\s*$/.test(node.data)) {
	      index++;
	    }
	  }
	  return index;
	}
	function addCollection(target, item){
		var newCol = new collection(target, item, this);
		newCol.init();
		collections.push(newCol);
	}
	function addSource(element){
		Sortable.create(element, {
			group: {name: 'cb', pull: 'clone', put: false},
			sort: false
		});
	}
	function applyToEach(func){
		return function(opts){
			var temp = [];
			for(var i in collections) {
				temp.push(collections[i][func].call(null, opts));
			}
			this.publish(func, temp);
			return temp;
		}.bind(this)
	}

	return {
		collections: collections,
		addCollection: addCollection.bind(this),
		addSource: addSource,
		toJSON: applyToEach.call(this, 'toJSON'),
		toHTML: applyToEach.call(this, 'toHTML'),
		clear: applyToEach.call(this, 'clear'),
		deactivate: applyToEach.call(this, 'deactivate'),
		destroy: applyToEach.call(this, 'destroy'),
		on: this.subscribe//,
		//trigger: this.publish.bind(this)
	};
}

Cobler.types = {};

berryEditor = function(container){
	return function(){
		var formConfig = $.extend(true, {}, {
			// renderer: 'tabs',
			attributes: this.get(),
			fields: this.fields,
			autoDestroy: true
		}, this.formOptions || {});

		var opts = container.owner.options;
		var events = 'save';
		if(typeof opts.formTarget !== 'undefined' && opts.formTarget.length){
			formConfig.actions = false;
			events = 'change';
		}
		var myBerry = new Berry(formConfig, this.formTarget || $(container.elementOf(this)).find('.panel-body'));
		myBerry.on(events, function(){
		 	container.update(myBerry.toJSON(), this);
		 	container.deactivate();
		 	myBerry.trigger('saved');
		}, this);
		myBerry.on('cancel',function(){
		 	container.update(this.get(), this)
		 	container.deactivate();
		}, this)
		return myBerry;
	}
}
<|endoftext|>


<commit_before>'use strict';

describe('Services: requestAnimation & cancelAnimation', function () {
  var windowMock,
      timeoutMockObject;

  beforeEach(function() {
    var timeoutCancel;
    timeoutMockObject = {};
    timeoutMockObject.timeout = {};
    timeoutMockObject.timeout.cancel = jasmine.createSpy('timeoutCancelMock');
    timeoutCancel = timeoutMockObject.timeout.cancel;
    timeoutMockObject.timeout = jasmine.createSpy('timeoutMock');
    timeoutMockObject.timeout.cancel = timeoutCancel;

    windowMock = {
      requestAnimationFrame: function () {
        return 'requestAnimationFrame';
      },
      cancelAnimationFrame: function () {
        return 'cancelAnimationFrame';
      },
      webkitRequestAnimationFrame: function () {
        return 'webkitRequestAnimationFrame';
      },
      webkitCancelAnimationFrame: function () {
        return 'webkitCancelAnimationFrame';
      },
      webkitCancelRequestAnimationFrame: function () {
        return 'webkitCancelRequestAnimationFrame';
      },
      mozRequestAnimationFrame: function () {
        return 'mozRequestAnimationFrame';
      },
      mozCancelAnimationFrame: function () {
        return 'mozCancelAnimationFrame';
      },
      navigator: {
        userAgent: ''
      }
    };

    module('snapscroll');

    module(function ($provide) {
      $provide.value('$window', windowMock);
      $provide.value('$timeout', timeoutMockObject.timeout);
    });
  });

  describe('on modern browsers', function () {
    beforeEach(function () {
    });

    it('return the unprefixed functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('requestAnimationFrame');
      expect(cancelAnimation()).toBe('cancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old webkit browsers', function () {
    beforeEach(function () {
      windowMock.requestAnimationFrame = undefined;
      windowMock.cancelAnimationFrame = undefined;
    });

    it('return the legacy webkit functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('webkitRequestAnimationFrame');
      expect(cancelAnimation()).toBe('webkitCancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old webkit browsers, cancelAnimation', function () {
    beforeEach(function () {
      windowMock.cancelAnimationFrame = undefined;
      windowMock.mozCancelAnimationFrame = undefined;
      windowMock.webkitCancelAnimationFrame = undefined;
    });

    it('may also return webkitCancelRequestAnimationFrame', inject(function (cancelAnimation) {
      expect(cancelAnimation()).toBe('webkitCancelRequestAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old mozilla browsers', function () {
    beforeEach(function () {
      windowMock.requestAnimationFrame = undefined;
      windowMock.cancelAnimationFrame = undefined;
      windowMock.webkitRequestAnimationFrame = undefined;
      windowMock.webkitCancelAnimationFrame = undefined;
      windowMock.webkitCancelRequestAnimationFrame = undefined;
    });

    it('return the legacy mozilla functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('mozRequestAnimationFrame');
      expect(cancelAnimation()).toBe('mozCancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old browsers', function () {
    beforeEach(function () {
      windowMock.requestAnimationFrame = undefined;
      windowMock.cancelAnimationFrame = undefined;
      windowMock.webkitRequestAnimationFrame = undefined;
      windowMock.webkitCancelAnimationFrame = undefined;
      windowMock.webkitCancelRequestAnimationFrame = undefined;
      windowMock.mozRequestAnimationFrame = undefined;
      windowMock.mozCancelAnimationFrame = undefined;
    });

    it('return a timeout promise and cancel function respectively', inject(function (requestAnimation, cancelAnimation) {
      requestAnimation();
      expect(timeoutMockObject.timeout).toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
      cancelAnimation();
      expect(timeoutMockObject.timeout.cancel).toHaveBeenCalled();
    }));
  });

  describe('on iOS 6', function () {
    beforeEach(function () {
      windowMock.navigator.userAgent = 'iPhone OS 6';
    });

    it('return a timeout promise and cancel function respectively', inject(function (requestAnimation, cancelAnimation) {
      requestAnimation();
      expect(timeoutMockObject.timeout).toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
      cancelAnimation();
      expect(timeoutMockObject.timeout.cancel).toHaveBeenCalled();
    }));
  });
});<commit_msg>as attribute: added correctness test for iOS 7<commit_after>'use strict';

describe('Services: requestAnimation & cancelAnimation', function () {
  var windowMock,
      timeoutMockObject;

  beforeEach(function() {
    var timeoutCancel;
    timeoutMockObject = {};
    timeoutMockObject.timeout = {};
    timeoutMockObject.timeout.cancel = jasmine.createSpy('timeoutCancelMock');
    timeoutCancel = timeoutMockObject.timeout.cancel;
    timeoutMockObject.timeout = jasmine.createSpy('timeoutMock');
    timeoutMockObject.timeout.cancel = timeoutCancel;

    windowMock = {
      requestAnimationFrame: function () {
        return 'requestAnimationFrame';
      },
      cancelAnimationFrame: function () {
        return 'cancelAnimationFrame';
      },
      webkitRequestAnimationFrame: function () {
        return 'webkitRequestAnimationFrame';
      },
      webkitCancelAnimationFrame: function () {
        return 'webkitCancelAnimationFrame';
      },
      webkitCancelRequestAnimationFrame: function () {
        return 'webkitCancelRequestAnimationFrame';
      },
      mozRequestAnimationFrame: function () {
        return 'mozRequestAnimationFrame';
      },
      mozCancelAnimationFrame: function () {
        return 'mozCancelAnimationFrame';
      },
      navigator: {
        userAgent: ''
      }
    };

    module('snapscroll');

    module(function ($provide) {
      $provide.value('$window', windowMock);
      $provide.value('$timeout', timeoutMockObject.timeout);
    });
  });

  describe('on modern browsers', function () {
    beforeEach(function () {
    });

    it('return the unprefixed functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('requestAnimationFrame');
      expect(cancelAnimation()).toBe('cancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old webkit browsers', function () {
    beforeEach(function () {
      windowMock.requestAnimationFrame = undefined;
      windowMock.cancelAnimationFrame = undefined;
    });

    it('return the legacy webkit functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('webkitRequestAnimationFrame');
      expect(cancelAnimation()).toBe('webkitCancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old webkit browsers, cancelAnimation', function () {
    beforeEach(function () {
      windowMock.cancelAnimationFrame = undefined;
      windowMock.mozCancelAnimationFrame = undefined;
      windowMock.webkitCancelAnimationFrame = undefined;
    });

    it('may also return webkitCancelRequestAnimationFrame', inject(function (cancelAnimation) {
      expect(cancelAnimation()).toBe('webkitCancelRequestAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old mozilla browsers', function () {
    beforeEach(function () {
      windowMock.requestAnimationFrame = undefined;
      windowMock.cancelAnimationFrame = undefined;
      windowMock.webkitRequestAnimationFrame = undefined;
      windowMock.webkitCancelAnimationFrame = undefined;
      windowMock.webkitCancelRequestAnimationFrame = undefined;
    });

    it('return the legacy mozilla functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('mozRequestAnimationFrame');
      expect(cancelAnimation()).toBe('mozCancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });

  describe('on old browsers', function () {
    beforeEach(function () {
      windowMock.requestAnimationFrame = undefined;
      windowMock.cancelAnimationFrame = undefined;
      windowMock.webkitRequestAnimationFrame = undefined;
      windowMock.webkitCancelAnimationFrame = undefined;
      windowMock.webkitCancelRequestAnimationFrame = undefined;
      windowMock.mozRequestAnimationFrame = undefined;
      windowMock.mozCancelAnimationFrame = undefined;
    });

    it('return a timeout promise and cancel function respectively', inject(function (requestAnimation, cancelAnimation) {
      requestAnimation();
      expect(timeoutMockObject.timeout).toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
      cancelAnimation();
      expect(timeoutMockObject.timeout.cancel).toHaveBeenCalled();
    }));
  });

  describe('on iOS 6', function () {
    beforeEach(function () {
      windowMock.navigator.userAgent = 'iPhone OS 6';
    });

    it('return a timeout promise and cancel function respectively', inject(function (requestAnimation, cancelAnimation) {
      requestAnimation();
      expect(timeoutMockObject.timeout).toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
      cancelAnimation();
      expect(timeoutMockObject.timeout.cancel).toHaveBeenCalled();
    }));
  });

  describe('on iOS 7', function () {
    beforeEach(function () {
      windowMock.navigator.userAgent = 'iPhone OS 7';
    });

    it('return the unprefixed functions', inject(function (requestAnimation, cancelAnimation) {
      expect(requestAnimation()).toBe('requestAnimationFrame');
      expect(cancelAnimation()).toBe('cancelAnimationFrame');
      expect(timeoutMockObject.timeout).not.toHaveBeenCalled();
      expect(timeoutMockObject.timeout.cancel).not.toHaveBeenCalled();
    }));
  });
});<|endoftext|>


<commit_before>Game.Map = {
  init: function(grid, options) {
    this.grid = grid;
    this.options = options || {};
    this.color = options.color || 0xaaaaff;
    this.entities = {};
    this.items = {};
    this.targets = [];
    this.crates = Object.create(Game.Crates.Group).init();
    this.scheduler = new ROT.Scheduler.Simple();
    this.engine = new ROT.Engine(this.scheduler);
    return this;
  },
  find: function(qualifyFunction) {
    var candidates = this.grid.filterCells(qualifyFunction);
    var length = candidates.length;
    return candidates[Math.floor(ROT.RNG.getUniform() * (length))];
  },
  randomEmpty: function(x, y, w, h) {
    x = x || 0;
    y = y || 0;
    w = w || this.grid.width;
    h = h || this.grid.height;
    var map = this;
    var emptyCell = this.find(function(cell) {
      return cell.dug &&
      !cell.impassable &&
      cell.x >= x && cell.x < x + w &&
      cell.y >= y && cell.y < y + h &&
      map.unoccupiedAt(cell.x, cell.y);
    });
    return emptyCell;
  },
  randomDug: function() {
    return this.find(function(cell) {
      return cell.dug && !cell.impassable;
    });
  },
  randomUndug: function() {
    return this.find(function(cell) {
      return !cell.dug && !cell.impassable;
    });
  },
  randomPristine: function() {
    var map = this;
    return this.find(function(cell) {
      return (!cell.dug && !map.itemAt(cell.x, cell.y) && !cell.impassable);
    });
  },
  randomStable: function() {
    var map = this;
    return this.find(function(cell) {
      return !cell.dug &&
        cell.south &&
        !cell.south.dug &&
        cell.y < map.grid.height - 5 &&
        !cell.impassable &&
        map.unoccupiedAt(cell.x, cell.y);
    });
  },
  addEntity: function(entity) {
    entity.map = this;
    this.updateEntityPosition(entity);
    if (entity.isPlayer) {
      this.player = entity;
    }
    if (entity.crateType !== undefined) {
      this.crates.add(entity);
    } else {
      this.scheduler.add(entity, true);
    }
  },
  removeEntity: function(entity) {
    var key = entity.x + ',' + entity.y;
    if (this.entities[key] == entity) {
      delete this.entities[key];
    }
    if (entity.crateType !== undefined) {
      this.crates.remove(entity);
    } else {
      this.scheduler.remove(entity);
    }
  },
  addItem: function(x, y, item) {
    item.map = this;
    item.x = x;
    item.y = y;
    var key = x + ',' + y;
    if (!this.items[key]) { // no item here, put it down
      this.items[key] = item;
    } else { // oh boy...
      var grid = this.grid;
      var itemOverflowMap = Object.create(grid).init(grid.width, grid.height);
      var here = itemOverflowMap.getCell(x, y);
      here.searched = true;
      var frontier = [here];
      while (frontier.length > 0) {
        current = frontier.shift();
        current.neighbors().some( function(neighbor) {
          if (neighbor.searched === undefined &&
              !item.map.grid.getCell(neighbor.x, neighbor.y).impassable &&
              !item.map.entityAt(neighbor.x, neighbor.y)) {
            key = neighbor.x + ',' + neighbor.y;
            if (!item.map.items[key]) {
              item.x = neighbor.x;
              item.y = neighbor.y;
              item.map.items[key] = item;
              frontier = [];
              return true;
            } else {
              neighbor.searched = true;
              frontier.push(neighbor);
            }
          }
        }, this);
      }
    }
  },
  removeItem: function(item) {
    var key = item.x + ',' + item.y;
    if (this.items[key] == item) {
      var name = item.name;
      delete this.items[key];
      return name;
    }
    return null;
  },
  updateEntityPosition: function(entity, oldX, oldY) {
    if (typeof oldX === 'number') {
        var oldKey = oldX + ',' + oldY;
        if (this.entities[oldKey] == entity) {
            delete this.entities[oldKey];
        }
    }
    if (entity.x < 0 || entity.x >= this.grid.width ||
        entity.x < 0 || entity.y >= this.grid.height) {
        throw new Error("Entity's position is out of bounds.");
    }
    var key = entity.x + ',' + entity.y;
    if (this.entities[key]) {
      throw new Error('Tried to add an entity at an occupied position.');
    }
    entity.slidingX = entity.x;
    entity.slidingY = entity.y;
    this.entities[key] = entity;
  },
  itemAt: function(x, y){
    return this.items[x + ',' + y];
  },
  entityAt: function(x, y){
    return this.entities[x + ',' + y];
  },
  unoccupiedAt: function(x, y) {
    return !!(this.entities[x + ',' + y] === undefined);
  }
};

Game.Map.Generators = {};

<commit_msg>Better exception message<commit_after>Game.Map = {
  init: function(grid, options) {
    this.grid = grid;
    this.options = options || {};
    this.color = options.color || 0xaaaaff;
    this.entities = {};
    this.items = {};
    this.targets = [];
    this.crates = Object.create(Game.Crates.Group).init();
    this.scheduler = new ROT.Scheduler.Simple();
    this.engine = new ROT.Engine(this.scheduler);
    return this;
  },
  find: function(qualifyFunction) {
    var candidates = this.grid.filterCells(qualifyFunction);
    var length = candidates.length;
    return candidates[Math.floor(ROT.RNG.getUniform() * (length))];
  },
  randomEmpty: function(x, y, w, h) {
    x = x || 0;
    y = y || 0;
    w = w || this.grid.width;
    h = h || this.grid.height;
    var map = this;
    var emptyCell = this.find(function(cell) {
      return cell.dug &&
      !cell.impassable &&
      cell.x >= x && cell.x < x + w &&
      cell.y >= y && cell.y < y + h &&
      map.unoccupiedAt(cell.x, cell.y);
    });
    return emptyCell;
  },
  randomDug: function() {
    return this.find(function(cell) {
      return cell.dug && !cell.impassable;
    });
  },
  randomUndug: function() {
    return this.find(function(cell) {
      return !cell.dug && !cell.impassable;
    });
  },
  randomPristine: function() {
    var map = this;
    return this.find(function(cell) {
      return (!cell.dug && !map.itemAt(cell.x, cell.y) && !cell.impassable);
    });
  },
  randomStable: function() {
    var map = this;
    return this.find(function(cell) {
      return !cell.dug &&
        cell.south &&
        !cell.south.dug &&
        cell.y < map.grid.height - 5 &&
        !cell.impassable &&
        map.unoccupiedAt(cell.x, cell.y);
    });
  },
  addEntity: function(entity) {
    entity.map = this;
    this.updateEntityPosition(entity);
    if (entity.isPlayer) {
      this.player = entity;
    }
    if (entity.crateType !== undefined) {
      this.crates.add(entity);
    } else {
      this.scheduler.add(entity, true);
    }
  },
  removeEntity: function(entity) {
    var key = entity.x + ',' + entity.y;
    if (this.entities[key] == entity) {
      delete this.entities[key];
    }
    if (entity.crateType !== undefined) {
      this.crates.remove(entity);
    } else {
      this.scheduler.remove(entity);
    }
  },
  addItem: function(x, y, item) {
    item.map = this;
    item.x = x;
    item.y = y;
    var key = x + ',' + y;
    if (!this.items[key]) { // no item here, put it down
      this.items[key] = item;
    } else { // oh boy...
      var grid = this.grid;
      var itemOverflowMap = Object.create(grid).init(grid.width, grid.height);
      var here = itemOverflowMap.getCell(x, y);
      here.searched = true;
      var frontier = [here];
      while (frontier.length > 0) {
        current = frontier.shift();
        current.neighbors().some( function(neighbor) {
          if (neighbor.searched === undefined &&
              !item.map.grid.getCell(neighbor.x, neighbor.y).impassable &&
              !item.map.entityAt(neighbor.x, neighbor.y)) {
            key = neighbor.x + ',' + neighbor.y;
            if (!item.map.items[key]) {
              item.x = neighbor.x;
              item.y = neighbor.y;
              item.map.items[key] = item;
              frontier = [];
              return true;
            } else {
              neighbor.searched = true;
              frontier.push(neighbor);
            }
          }
        }, this);
      }
    }
  },
  removeItem: function(item) {
    var key = item.x + ',' + item.y;
    if (this.items[key] == item) {
      var name = item.name;
      delete this.items[key];
      return name;
    }
    return null;
  },
  updateEntityPosition: function(entity, oldX, oldY) {
    if (typeof oldX === 'number') {
        var oldKey = oldX + ',' + oldY;
        if (this.entities[oldKey] == entity) {
            delete this.entities[oldKey];
        }
    }
    if (entity.x < 0 || entity.x >= this.grid.width ||
        entity.x < 0 || entity.y >= this.grid.height) {
        throw new Error("Entity's position is out of bounds.");
    }
    var key = entity.x + ',' + entity.y;
    if (this.entities[key]) {
      var errorMessage = 'Tried to add ' + entity.tile + ' at ' + key + ', but ' + this.entities[key] + ' was already there.';
      throw new Error(errorMessage);
    }
    entity.slidingX = entity.x;
    entity.slidingY = entity.y;
    this.entities[key] = entity;
  },
  itemAt: function(x, y){
    return this.items[x + ',' + y];
  },
  entityAt: function(x, y){
    return this.entities[x + ',' + y];
  },
  unoccupiedAt: function(x, y) {
    return !!(this.entities[x + ',' + y] === undefined);
  }
};

Game.Map.Generators = {};

<|endoftext|>


<commit_before>var assert = require("assert");

var test = require("../test")(module);
var documentMatchers = require("../../lib/styles/document-matchers");
var documents = require("../../lib/documents");
var Paragraph = documents.Paragraph;

test("paragraph with no options matches any paragraph", function() {
    var matcher = documentMatchers.paragraph();
    assert.ok(matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
});

test("paragraph style ID only matches paragraphs with that style ID", function() {
    var matcher = documentMatchers.paragraph({styleId: "Heading1"});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
    assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
});

test("paragraph style name only matches paragraphs with that style name", function() {
    var matcher = documentMatchers.paragraph({styleName: documentMatchers.equalTo("Heading 1")});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
    assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
});

test("ordered-list(index) matches an ordered list with specified level index", function() {
    var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 1}});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
    assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 0, isOrdered: true}})));
    assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
});

test("unordered-list(index) matches an unordered list with specified level index", function() {
    var matcher = documentMatchers.paragraph({list: {isOrdered: false, levelIndex: 1}});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
    assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
});

test("matchers for lists with index 0 do not match elements that are not lists", function() {
    var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 0}});
    assert.ok(!matcher.matches(new Paragraph()));
});

function paragraphWithStyle(styleId, styleName) {
    return new Paragraph([], {styleId: styleId, styleName: styleName});
}

test("equalTo matcher is case insensitive", function() {
    var matcher = documentMatchers.equalTo("Heading 1");
    assert.ok(matcher.operator(matcher.operand, "heaDING 1"));
    assert.ok(!matcher.operator(matcher.operand, "heaDING 2"));
});

test("startsWith matches strings with prefix", function() {
    var matcher = documentMatchers.startsWith("Heading");
    assert.ok(matcher.operator(matcher.operand, "Heading 1"));
    assert.ok(!matcher.operator(matcher.operand, "Custom Heading"));
    assert.ok(!matcher.operator(matcher.operand, "Head"));
    assert.ok(!matcher.operator(matcher.operand, "Header 2"));
});

test("startsWith matcher is case insensitive", function() {
    var matcher = documentMatchers.startsWith("Heading");
    assert.ok(matcher.operator(matcher.operand, "heaDING"));
});
<commit_msg>Add exact match to startsWith test case<commit_after>var assert = require("assert");

var test = require("../test")(module);
var documentMatchers = require("../../lib/styles/document-matchers");
var documents = require("../../lib/documents");
var Paragraph = documents.Paragraph;

test("paragraph with no options matches any paragraph", function() {
    var matcher = documentMatchers.paragraph();
    assert.ok(matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
});

test("paragraph style ID only matches paragraphs with that style ID", function() {
    var matcher = documentMatchers.paragraph({styleId: "Heading1"});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
    assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
});

test("paragraph style name only matches paragraphs with that style name", function() {
    var matcher = documentMatchers.paragraph({styleName: documentMatchers.equalTo("Heading 1")});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
    assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
});

test("ordered-list(index) matches an ordered list with specified level index", function() {
    var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 1}});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
    assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 0, isOrdered: true}})));
    assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
});

test("unordered-list(index) matches an unordered list with specified level index", function() {
    var matcher = documentMatchers.paragraph({list: {isOrdered: false, levelIndex: 1}});
    assert.ok(!matcher.matches(new Paragraph()));
    assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
    assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
});

test("matchers for lists with index 0 do not match elements that are not lists", function() {
    var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 0}});
    assert.ok(!matcher.matches(new Paragraph()));
});

function paragraphWithStyle(styleId, styleName) {
    return new Paragraph([], {styleId: styleId, styleName: styleName});
}

test("equalTo matcher is case insensitive", function() {
    var matcher = documentMatchers.equalTo("Heading 1");
    assert.ok(matcher.operator(matcher.operand, "heaDING 1"));
    assert.ok(!matcher.operator(matcher.operand, "heaDING 2"));
});

test("startsWith matches strings with prefix", function() {
    var matcher = documentMatchers.startsWith("Heading");
    assert.ok(matcher.operator(matcher.operand, "Heading"));
    assert.ok(matcher.operator(matcher.operand, "Heading 1"));
    assert.ok(!matcher.operator(matcher.operand, "Custom Heading"));
    assert.ok(!matcher.operator(matcher.operand, "Head"));
    assert.ok(!matcher.operator(matcher.operand, "Header 2"));
});

test("startsWith matcher is case insensitive", function() {
    var matcher = documentMatchers.startsWith("Heading");
    assert.ok(matcher.operator(matcher.operand, "heaDING"));
});
<|endoftext|>


<commit_before>/* @flow */

const _ = require('lodash')

const {
  assignId,
  assignPlatformIncompatibilities,
  id,
  markSide
} = require('../../../../core/metadata')
const timestamp = require('../../../../core/timestamp')

const dbBuilders = require('../db')

/*::
import type fs from 'fs-extra'
import type {
  Metadata,
  MetadataRemoteInfo,
  MetadataSidesInfo,
  SideName
} from '../../../../core/metadata'
import type Pouch from '../../../../core/pouch'
*/

module.exports = class BaseMetadataBuilder {
  /*::
  pouch: ?Pouch
  doc: Metadata
  old: ?Metadata
  */

  constructor (pouch /*: ?Pouch */, old /*: ?Metadata */) {
    this.pouch = pouch
    if (old) {
      this.old = old
      this.doc = _.cloneDeep(old)
      this.doc.tags.push('changed-tag')
    } else {
      this.doc = {
        _id: id('foo'),
        docType: 'folder', // To make flow happy (overridden by subclasses)
        path: 'foo',
        remote: {
          _id: dbBuilders.id(),
          _rev: dbBuilders.rev()
        },
        tags: [],
        sides: {},
        updated_at: timestamp.stringify(timestamp.current())
      }
    }
  }

  rev (rev /*: string */) /*: this */ {
    this.doc._rev = rev
    return this
  }

  noRev () /*: this */ {
    delete this.doc._rev
    return this
  }

  incompatible () /*: this */ {
    const { platform } = process

    if (platform === 'win32' || platform === 'darwin') {
      // Colon is currently considered forbidden on both platforms by the app
      // (although it probably shouldn't on macOS).
      return this.path('in:compatible')
    } else {
      throw new Error(`Cannot build incompatible doc on ${platform}`)
    }
  }

  ino (ino /*: number */) /*: this */ {
    this.doc.ino = ino
    return this
  }

  stats ({ino, mtime, ctime} /*: fs.Stats */) /*: this */ {
    return this.ino(ino).updatedAt(timestamp.maxDate(mtime, ctime))
  }

  path (path /*: string */) /*: this */ {
    this.doc.path = path
    assignId(this.doc)
    return this
  }

  overwrite (existingDoc /*: Metadata */) /*: this */ {
    this.doc.overwrite = existingDoc
    return this
  }

  trashed () /*: this */ {
    this.doc.trashed = true
    return this
  }

  updatedAt (date /*: Date */) /*: this */ {
    this.doc.updated_at = timestamp.fromDate(date).toISOString()
    return this
  }

  newerThan (doc /*: Metadata */) /*: this */ {
    this.doc.updated_at = new Date(timestamp.fromDate(doc.updated_at) + 2000)
    return this
  }

  olderThan (doc /*: Metadata */) /*: this */ {
    this.doc.updated_at = new Date(timestamp.fromDate(doc.updated_at) - 2000)
    return this
  }

  remoteId (_id /*: string */) /*: this */ {
    this.doc.remote = {
      _id,
      _rev: dbBuilders.rev()
    }
    return this
  }

  upToDate () /*: this */ {
    this.doc.sides = {local: 2, remote: 2}
    return this
  }

  notUpToDate () /*: this */ {
    this.doc.sides = {remote: 1}
    return this
  }

  changedSide (side /*: SideName */) /*: this */ {
    markSide(side, this.doc, this.old)
    return this
  }

  sides (sides /*: MetadataSidesInfo */) /*: this */ {
    this.doc.sides = sides
    return this
  }

  build () /*: Metadata */ {
    // Don't detect incompatibilities according to syncPath for test data, to
    // prevent environment related failures.
    assignPlatformIncompatibilities(this.doc, '')

    return _.cloneDeep(this.doc)
  }

  async create () /*: Promise<Metadata> */ {
    const doc = this.build()
    if (this.pouch == null) {
      throw new Error('Cannot create dir metadata without Pouch')
    }
    const { rev } = await this.pouch.put(doc)
    doc._rev = rev
    return doc
  }
}
<commit_msg>test/support/builders/metadata: Fix #newerThan() & #olderThan()<commit_after>/* @flow */

const _ = require('lodash')

const {
  assignId,
  assignPlatformIncompatibilities,
  id,
  markSide
} = require('../../../../core/metadata')
const timestamp = require('../../../../core/timestamp')

const dbBuilders = require('../db')

/*::
import type fs from 'fs-extra'
import type {
  Metadata,
  MetadataRemoteInfo,
  MetadataSidesInfo,
  SideName
} from '../../../../core/metadata'
import type Pouch from '../../../../core/pouch'
*/

module.exports = class BaseMetadataBuilder {
  /*::
  pouch: ?Pouch
  doc: Metadata
  old: ?Metadata
  */

  constructor (pouch /*: ?Pouch */, old /*: ?Metadata */) {
    this.pouch = pouch
    if (old) {
      this.old = old
      this.doc = _.cloneDeep(old)
      this.doc.tags.push('changed-tag')
    } else {
      this.doc = {
        _id: id('foo'),
        docType: 'folder', // To make flow happy (overridden by subclasses)
        path: 'foo',
        remote: {
          _id: dbBuilders.id(),
          _rev: dbBuilders.rev()
        },
        tags: [],
        sides: {},
        updated_at: timestamp.stringify(timestamp.current())
      }
    }
  }

  rev (rev /*: string */) /*: this */ {
    this.doc._rev = rev
    return this
  }

  noRev () /*: this */ {
    delete this.doc._rev
    return this
  }

  incompatible () /*: this */ {
    const { platform } = process

    if (platform === 'win32' || platform === 'darwin') {
      // Colon is currently considered forbidden on both platforms by the app
      // (although it probably shouldn't on macOS).
      return this.path('in:compatible')
    } else {
      throw new Error(`Cannot build incompatible doc on ${platform}`)
    }
  }

  ino (ino /*: number */) /*: this */ {
    this.doc.ino = ino
    return this
  }

  stats ({ino, mtime, ctime} /*: fs.Stats */) /*: this */ {
    return this.ino(ino).updatedAt(timestamp.maxDate(mtime, ctime))
  }

  path (path /*: string */) /*: this */ {
    this.doc.path = path
    assignId(this.doc)
    return this
  }

  overwrite (existingDoc /*: Metadata */) /*: this */ {
    this.doc.overwrite = existingDoc
    return this
  }

  trashed () /*: this */ {
    this.doc.trashed = true
    return this
  }

  updatedAt (date /*: Date */) /*: this */ {
    this.doc.updated_at = timestamp.fromDate(date).toISOString()
    return this
  }

  newerThan (doc /*: Metadata */) /*: this */ {
    this.doc.updated_at = new Date(timestamp.fromDate(doc.updated_at).getTime() + 2000)
    return this
  }

  olderThan (doc /*: Metadata */) /*: this */ {
    this.doc.updated_at = new Date(timestamp.fromDate(doc.updated_at).getTime() - 2000)
    return this
  }

  remoteId (_id /*: string */) /*: this */ {
    this.doc.remote = {
      _id,
      _rev: dbBuilders.rev()
    }
    return this
  }

  upToDate () /*: this */ {
    this.doc.sides = {local: 2, remote: 2}
    return this
  }

  notUpToDate () /*: this */ {
    this.doc.sides = {remote: 1}
    return this
  }

  changedSide (side /*: SideName */) /*: this */ {
    markSide(side, this.doc, this.old)
    return this
  }

  sides (sides /*: MetadataSidesInfo */) /*: this */ {
    this.doc.sides = sides
    return this
  }

  build () /*: Metadata */ {
    // Don't detect incompatibilities according to syncPath for test data, to
    // prevent environment related failures.
    assignPlatformIncompatibilities(this.doc, '')

    return _.cloneDeep(this.doc)
  }

  async create () /*: Promise<Metadata> */ {
    const doc = this.build()
    if (this.pouch == null) {
      throw new Error('Cannot create dir metadata without Pouch')
    }
    const { rev } = await this.pouch.put(doc)
    doc._rev = rev
    return doc
  }
}
<|endoftext|>


<commit_before>function listenallimg(){
    for (var img of document.querySelectorAll('img')) {
        if (img.id != "avatar") img.onclick = viewimg;
    }
}

function viewimg(){
    var doc = document.documentElement;
    var sleft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
    var stop = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);

    var bg = document.createElement("div");

    bg.style.background = "none repeat scroll 0% 0% rgba(0, 0, 0 , 0.5)";
    bg.style.position = "absolute";
    bg.style.left = sleft.toString() + "px";
    bg.style.top = stop.toString() + "px";
    bg.style.width = "100%";
    bg.style.height = "100%";
    bg.style.zIndex = "999";
    bg.onclick = function(){document.body.removeChild(this);};

    var imgele = document.createElement("img");
    var img = new Image();
    var disp = document.createElement("div");

    disp.style.width = "100%";
    disp.style.height = "100%";
    disp.style.textAlign = "center";
    bg.appendChild(disp);
    document.body.appendChild(bg);

    imgele.src = this.src;
    imgele.style.maxHeight = disp.clientHeight.toString() + "px";
    imgele.style.maxWidth = disp.clientWidth.toString() + "px";

    disp.appendChild(imgele);
}
<commit_msg>fix issue #3<commit_after>function listenallimg(){
    for (var img of Array.from(document.querySelectorAll('img'))) {
        if (img.id != "avatar") img.onclick = viewimg;
    }
}

function viewimg(){
    var doc = document.documentElement;
    var sleft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
    var stop = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);

    var bg = document.createElement("div");

    bg.style.background = "none repeat scroll 0% 0% rgba(0, 0, 0 , 0.5)";
    bg.style.position = "absolute";
    bg.style.left = sleft.toString() + "px";
    bg.style.top = stop.toString() + "px";
    bg.style.width = "100%";
    bg.style.height = "100%";
    bg.style.zIndex = "999";
    bg.onclick = function(){document.body.removeChild(this);};

    var imgele = document.createElement("img");
    var img = new Image();
    var disp = document.createElement("div");

    disp.style.width = "100%";
    disp.style.height = "100%";
    disp.style.textAlign = "center";
    bg.appendChild(disp);
    document.body.appendChild(bg);

    imgele.src = this.src;
    imgele.style.maxHeight = disp.clientHeight.toString() + "px";
    imgele.style.maxWidth = disp.clientWidth.toString() + "px";

    disp.appendChild(imgele);
}
<|endoftext|>


<commit_before>$(document).ready(function() {

 var tags_fns = new Bloodhound({
    datumTokenizer: function(d) {
      var test = Bloodhound.tokenizers.whitespace(d);
          $.each(test,function(k,v){
              var i = 0;
              while( (i+1) < v.length ){
                  test.push(v.substr(i,v.length));
                  i++;
              }
          })
          return test;
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    prefetch: {
          url:'data/en/index.json',
          ttl: 86400000*7,
          cache: true,
          transform: function(d){return d.tags.concat(d.functions, d.categories);}
        }
  });
  $('#lookup-box').typeahead({
      hint: true,
      highlight: true,
      minLength: 1
  },
  {
  		name: 'tags-fns',
  		source: tags_fns,
      limit: 10
  });
  $('.tt-hint').addClass('form-control');
  $('#search').submit(submitSearch);
  $('#lookup-box').on('typeahead:selected', submitSearch);
  $('#lookup-box').focus();

  $('.example-btn').click(function() {
      var name = $(this).attr('data-name');
      var index = $(this).attr('data-index');
      $('#example-modal-content').html('<iframe width="100%" height="450" border="0" src="/try/' + name + '/' + index + '">');
      $('.example-modal').modal();
  });

  if ($('.prettyprint').length != 0 && typeof(prettyPrint) == "function") {
      prettyPrint();
  }

});
//search submit
function submitSearch() {
  document.location = '/' + $('#lookup-box').val().toLowerCase();
  return false;
}
//google analytics
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-82573-18']);
_gaq.push(['_trackPageview']);
(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
<commit_msg>Added warning when running examples over https<commit_after>$(document).ready(function() {

 var tags_fns = new Bloodhound({
    datumTokenizer: function(d) {
      var test = Bloodhound.tokenizers.whitespace(d);
          $.each(test,function(k,v){
              var i = 0;
              while( (i+1) < v.length ){
                  test.push(v.substr(i,v.length));
                  i++;
              }
          })
          return test;
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    prefetch: {
          url:'data/en/index.json',
          ttl: 86400000*7,
          cache: true,
          transform: function(d){return d.tags.concat(d.functions, d.categories);}
        }
  });
  $('#lookup-box').typeahead({
      hint: true,
      highlight: true,
      minLength: 1
  },
  {
  		name: 'tags-fns',
  		source: tags_fns,
      limit: 10
  });
  $('.tt-hint').addClass('form-control');
  $('#search').submit(submitSearch);
  $('#lookup-box').on('typeahead:selected', submitSearch);
  $('#lookup-box').focus();

  $('.example-btn').click(function() {
      var name = $(this).attr('data-name');
      var index = $(this).attr('data-index');
      $('#example-modal-content').html('<iframe width="100%" height="450" border="0" src="/try/' + name + '/' + index + '">');
      $('.example-modal').modal();
      if (document.location.protocol == "https:") {
        alert("FYI Running Examples over HTTPS may not work on some browsers because trycf.com does not also run over HTTPS. Browsers with strong mixed content controls will block the cross domain execution.")
      }
  });

  if ($('.prettyprint').length != 0 && typeof(prettyPrint) == "function") {
      prettyPrint();
  }

});
//search submit
function submitSearch() {
  document.location = '/' + $('#lookup-box').val().toLowerCase();
  return false;
}
//google analytics
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-82573-18']);
_gaq.push(['_trackPageview']);
(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
<|endoftext|>