<commit_before>const AuthView = require('./AuthView')
const Browser = require('./new/Browser')
const ErrorView = require('./Error')

/**
 * Class to easily generate generic views for plugins
 *
 * This class expects the plugin using to have the following attributes
 *
 * stateId {String} object key of which the plugin state is stored
 *
 * This class also expects the plugin instance using it to have the following
 * accessor methods.
 * Each method takes the item whose property is to be accessed
 * as a param
 *
 * isFolder
 *    @return {Boolean} for if the item is a folder or not
 * getItemData
 *    @return {Object} that is format ready for uppy upload/download
 * getItemIcon
 *    @return {Object} html instance of the item's icon
 * getItemSubList
 *    @return {Array} sub-items in the item. e.g a folder may contain sub-items
 * getItemName
 *    @return {String} display friendly name of the item
 * getMimeType
 *    @return {String} mime type of the item
 * getItemId
 *    @return {String} unique id of the item
 * getItemRequestPath
 *    @return {String} unique request path of the item when making calls to uppy server
 * getItemModifiedDate
 *    @return {object} or {String} date of when last the item was modified
 */
module.exports = class View {
  /**
   * @param {object} instance of the plugin
   */
  constructor (plugin) {
    this.plugin = plugin
    this.Provider = plugin[plugin.id]

    // Logic
    this.addFile = this.addFile.bind(this)
    this.filterItems = this.filterItems.bind(this)
    this.filterQuery = this.filterQuery.bind(this)
    this.getFolder = this.getFolder.bind(this)
    this.getNextFolder = this.getNextFolder.bind(this)
    this.handleRowClick = this.handleRowClick.bind(this)
    this.logout = this.logout.bind(this)
    this.handleAuth = this.handleAuth.bind(this)
    this.handleDemoAuth = this.handleDemoAuth.bind(this)
    this.sortByTitle = this.sortByTitle.bind(this)
    this.sortByDate = this.sortByDate.bind(this)
    this.isActiveRow = this.isActiveRow.bind(this)

    // Visual
    this.render = this.render.bind(this)
  }

  /**
   * Little shorthand to update the state with the plugin's state
   */
  updateState (newState) {
    let stateId = this.plugin.stateId
    const {state} = this.plugin.core

    this.plugin.core.setState({[stateId]: Object.assign({}, state[stateId], newState)})
  }

  /**
   * Based on folder ID, fetch a new folder and update it to state
   * @param  {String} id Folder id
   * @return {Promise}   Folders/files in folder
   */
  getFolder (id) {
    return this.Provider.list(id)
      .then((res) => {
        let folders = []
        let files = []
        let updatedDirectories

        const state = this.plugin.core.getState()[this.plugin.stateId]
        const index = state.directories.findIndex((dir) => id === dir.id)

        if (index !== -1) {
          updatedDirectories = state.directories.slice(0, index + 1)
        } else {
          updatedDirectories = state.directories.concat([{id, title: this.plugin.getItemName(res)}])
        }

        this.plugin.getItemSubList(res).forEach((item) => {
          if (this.plugin.isFolder(item)) {
            folders.push(item)
          } else {
            files.push(item)
          }
        })

        let data = {folders, files, directories: updatedDirectories}
        this.updateState(data)

        return data
      })
      .catch((err) => {
        return err
      })
  }

  /**
   * Fetches new folder
   * @param  {Object} Folder
   * @param  {String} title Folder title
   */
  getNextFolder (folder) {
    let id = this.plugin.getItemRequestPath(folder)
    this.getFolder(id)
  }

  addFile (file) {
    const tagFile = {
      source: this.plugin.id,
      data: this.plugin.getItemData(file),
      name: this.plugin.getItemName(file),
      type: this.plugin.getMimeType(file),
      isRemote: true,
      body: {
        fileId: this.plugin.getItemId(file)
      },
      remote: {
        host: this.plugin.opts.host,
        url: `${this.plugin.opts.host}/${this.Provider.id}/get/${this.plugin.getItemRequestPath(file)}`,
        body: {
          fileId: this.plugin.getItemId(file)
        }
      }
    }
    console.log('adding file')
    this.plugin.core.emitter.emit('core:file-add', tagFile)
  }

  /**
   * Removes session token on client side.
   */
  logout () {
    this.Provider.logout(location.href)
      .then((res) => res.json())
      .then((res) => {
        if (res.ok) {
          const newState = {
            authenticated: false,
            files: [],
            folders: [],
            directories: []
          }
          this.updateState(newState)
        }
      })
  }

  /**
   * Used to set active file/folder.
   * @param  {Object} file   Active file/folder
   */
  handleRowClick (file) {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    const newState = Object.assign({}, state, {
      activeRow: this.plugin.getItemId(file)
    })

    this.updateState(newState)
  }

  filterQuery (e) {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    this.updateState(Object.assign({}, state, {
      filterInput: e.target.value
    }))
  }

  filterItems (items) {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    return items.filter((folder) => {
      return this.plugin.getItemName(folder).toLowerCase().indexOf(state.filterInput.toLowerCase()) !== -1
    })
  }

  sortByTitle () {
    const state = Object.assign({}, this.plugin.core.getState()[this.plugin.stateId])
    const {files, folders, sorting} = state

    let sortedFiles = files.sort((fileA, fileB) => {
      if (sorting === 'titleDescending') {
        return this.plugin.getItemName(fileB).localeCompare(this.plugin.getItemName(fileA))
      }
      return this.plugin.getItemName(fileA).localeCompare(this.plugin.getItemName(fileB))
    })

    let sortedFolders = folders.sort((folderA, folderB) => {
      if (sorting === 'titleDescending') {
        return this.plugin.getItemName(folderB).localeCompare(this.plugin.getItemName(folderA))
      }
      return this.plugin.getItemName(folderA).localeCompare(this.plugin.getItemName(folderB))
    })

    this.updateState(Object.assign({}, state, {
      files: sortedFiles,
      folders: sortedFolders,
      sorting: (sorting === 'titleDescending') ? 'titleAscending' : 'titleDescending'
    }))
  }

  sortByDate () {
    const state = Object.assign({}, this.plugin.core.getState()[this.plugin.stateId])
    const {files, folders, sorting} = state

    let sortedFiles = files.sort((fileA, fileB) => {
      let a = new Date(this.plugin.getItemModifiedDate(fileA))
      let b = new Date(this.plugin.getItemModifiedDate(fileB))

      if (sorting === 'dateDescending') {
        return a > b ? -1 : a < b ? 1 : 0
      }
      return a > b ? 1 : a < b ? -1 : 0
    })

    let sortedFolders = folders.sort((folderA, folderB) => {
      let a = new Date(this.plugin.getItemModifiedDate(folderA))
      let b = new Date(this.plugin.getItemModifiedDate(folderB))

      if (sorting === 'dateDescending') {
        return a > b ? -1 : a < b ? 1 : 0
      }

      return a > b ? 1 : a < b ? -1 : 0
    })

    this.updateState(Object.assign({}, state, {
      files: sortedFiles,
      folders: sortedFolders,
      sorting: (sorting === 'dateDescending') ? 'dateAscending' : 'dateDescending'
    }))
  }

  isActiveRow (file) {
    return this.plugin.core.getState()[this.plugin.stateId].activeRow === this.plugin.getItemId(file)
  }

  handleDemoAuth () {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    this.updateState({}, state, {
      authenticated: true
    })
  }

  handleAuth () {
    const urlId = Math.floor(Math.random() * 999999) + 1
    const redirect = `${location.href}${location.search ? '&' : '?'}id=${urlId}`

    const authState = btoa(JSON.stringify({ redirect }))
    const link = `${this.plugin.opts.host}/connect/${this.Provider.authProvider}?state=${authState}`

    const authWindow = window.open(link, '_blank')
    const checkAuth = () => {
      let authWindowUrl

      try {
        authWindowUrl = authWindow.location.href
      } catch (e) {
        if (e instanceof DOMException || e instanceof TypeError) {
          return setTimeout(checkAuth, 100)
        } else throw e
      }

      // split url because chrome adds '#' to redirects
      if (authWindowUrl.split('#')[0] === redirect) {
        authWindow.close()
        this.Provider.auth().then(this.plugin.onAuth)
      } else {
        setTimeout(checkAuth, 100)
      }
    }

    checkAuth()
  }

  render (state) {
    const { authenticated, error } = state[this.plugin.stateId]

    if (error) {
      return ErrorView({ error: error })
    }

    if (!authenticated) {
      return AuthView({
        pluginName: this.plugin.title,
        demo: this.plugin.opts.demo,
        handleAuth: this.handleAuth,
        handleDemoAuth: this.handleDemoAuth
      })
    }

    const browserProps = Object.assign({}, state[this.plugin.stateId], {
      getNextFolder: this.getNextFolder,
      getFolder: this.getFolder,
      addFile: this.addFile,
      filterItems: this.filterItems,
      filterQuery: this.filterQuery,
      handleRowClick: this.handleRowClick,
      sortByTitle: this.sortByTitle,
      sortByDate: this.sortByDate,
      logout: this.logout,
      demo: this.plugin.opts.demo,
      isActiveRow: this.isActiveRow,
      getItemName: this.plugin.getItemName,
      getItemIcon: this.plugin.getItemIcon
    })

    return Browser(browserProps)
  }
}
<commit_msg>refactor: non arrow functions for const<commit_after>const AuthView = require('./AuthView')
const Browser = require('./new/Browser')
const ErrorView = require('./Error')

/**
 * Class to easily generate generic views for plugins
 *
 * This class expects the plugin using to have the following attributes
 *
 * stateId {String} object key of which the plugin state is stored
 *
 * This class also expects the plugin instance using it to have the following
 * accessor methods.
 * Each method takes the item whose property is to be accessed
 * as a param
 *
 * isFolder
 *    @return {Boolean} for if the item is a folder or not
 * getItemData
 *    @return {Object} that is format ready for uppy upload/download
 * getItemIcon
 *    @return {Object} html instance of the item's icon
 * getItemSubList
 *    @return {Array} sub-items in the item. e.g a folder may contain sub-items
 * getItemName
 *    @return {String} display friendly name of the item
 * getMimeType
 *    @return {String} mime type of the item
 * getItemId
 *    @return {String} unique id of the item
 * getItemRequestPath
 *    @return {String} unique request path of the item when making calls to uppy server
 * getItemModifiedDate
 *    @return {object} or {String} date of when last the item was modified
 */
module.exports = class View {
  /**
   * @param {object} instance of the plugin
   */
  constructor (plugin) {
    this.plugin = plugin
    this.Provider = plugin[plugin.id]

    // Logic
    this.addFile = this.addFile.bind(this)
    this.filterItems = this.filterItems.bind(this)
    this.filterQuery = this.filterQuery.bind(this)
    this.getFolder = this.getFolder.bind(this)
    this.getNextFolder = this.getNextFolder.bind(this)
    this.handleRowClick = this.handleRowClick.bind(this)
    this.logout = this.logout.bind(this)
    this.handleAuth = this.handleAuth.bind(this)
    this.handleDemoAuth = this.handleDemoAuth.bind(this)
    this.sortByTitle = this.sortByTitle.bind(this)
    this.sortByDate = this.sortByDate.bind(this)
    this.isActiveRow = this.isActiveRow.bind(this)

    // Visual
    this.render = this.render.bind(this)
  }

  /**
   * Little shorthand to update the state with the plugin's state
   */
  updateState (newState) {
    let stateId = this.plugin.stateId
    const {state} = this.plugin.core

    this.plugin.core.setState({[stateId]: Object.assign({}, state[stateId], newState)})
  }

  /**
   * Based on folder ID, fetch a new folder and update it to state
   * @param  {String} id Folder id
   * @return {Promise}   Folders/files in folder
   */
  getFolder (id) {
    return this.Provider.list(id)
      .then((res) => {
        let folders = []
        let files = []
        let updatedDirectories

        const state = this.plugin.core.getState()[this.plugin.stateId]
        const index = state.directories.findIndex((dir) => id === dir.id)

        if (index !== -1) {
          updatedDirectories = state.directories.slice(0, index + 1)
        } else {
          updatedDirectories = state.directories.concat([{id, title: this.plugin.getItemName(res)}])
        }

        this.plugin.getItemSubList(res).forEach((item) => {
          if (this.plugin.isFolder(item)) {
            folders.push(item)
          } else {
            files.push(item)
          }
        })

        let data = {folders, files, directories: updatedDirectories}
        this.updateState(data)

        return data
      })
      .catch((err) => {
        return err
      })
  }

  /**
   * Fetches new folder
   * @param  {Object} Folder
   * @param  {String} title Folder title
   */
  getNextFolder (folder) {
    let id = this.plugin.getItemRequestPath(folder)
    this.getFolder(id)
  }

  addFile (file) {
    const tagFile = {
      source: this.plugin.id,
      data: this.plugin.getItemData(file),
      name: this.plugin.getItemName(file),
      type: this.plugin.getMimeType(file),
      isRemote: true,
      body: {
        fileId: this.plugin.getItemId(file)
      },
      remote: {
        host: this.plugin.opts.host,
        url: `${this.plugin.opts.host}/${this.Provider.id}/get/${this.plugin.getItemRequestPath(file)}`,
        body: {
          fileId: this.plugin.getItemId(file)
        }
      }
    }
    console.log('adding file')
    this.plugin.core.emitter.emit('core:file-add', tagFile)
  }

  /**
   * Removes session token on client side.
   */
  logout () {
    this.Provider.logout(location.href)
      .then((res) => res.json())
      .then((res) => {
        if (res.ok) {
          const newState = {
            authenticated: false,
            files: [],
            folders: [],
            directories: []
          }
          this.updateState(newState)
        }
      })
  }

  /**
   * Used to set active file/folder.
   * @param  {Object} file   Active file/folder
   */
  handleRowClick (file) {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    const newState = Object.assign({}, state, {
      activeRow: this.plugin.getItemId(file)
    })

    this.updateState(newState)
  }

  filterQuery (e) {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    this.updateState(Object.assign({}, state, {
      filterInput: e.target.value
    }))
  }

  filterItems (items) {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    return items.filter((folder) => {
      return this.plugin.getItemName(folder).toLowerCase().indexOf(state.filterInput.toLowerCase()) !== -1
    })
  }

  sortByTitle () {
    const state = Object.assign({}, this.plugin.core.getState()[this.plugin.stateId])
    const {files, folders, sorting} = state

    let sortedFiles = files.sort((fileA, fileB) => {
      if (sorting === 'titleDescending') {
        return this.plugin.getItemName(fileB).localeCompare(this.plugin.getItemName(fileA))
      }
      return this.plugin.getItemName(fileA).localeCompare(this.plugin.getItemName(fileB))
    })

    let sortedFolders = folders.sort((folderA, folderB) => {
      if (sorting === 'titleDescending') {
        return this.plugin.getItemName(folderB).localeCompare(this.plugin.getItemName(folderA))
      }
      return this.plugin.getItemName(folderA).localeCompare(this.plugin.getItemName(folderB))
    })

    this.updateState(Object.assign({}, state, {
      files: sortedFiles,
      folders: sortedFolders,
      sorting: (sorting === 'titleDescending') ? 'titleAscending' : 'titleDescending'
    }))
  }

  sortByDate () {
    const state = Object.assign({}, this.plugin.core.getState()[this.plugin.stateId])
    const {files, folders, sorting} = state

    let sortedFiles = files.sort((fileA, fileB) => {
      let a = new Date(this.plugin.getItemModifiedDate(fileA))
      let b = new Date(this.plugin.getItemModifiedDate(fileB))

      if (sorting === 'dateDescending') {
        return a > b ? -1 : a < b ? 1 : 0
      }
      return a > b ? 1 : a < b ? -1 : 0
    })

    let sortedFolders = folders.sort((folderA, folderB) => {
      let a = new Date(this.plugin.getItemModifiedDate(folderA))
      let b = new Date(this.plugin.getItemModifiedDate(folderB))

      if (sorting === 'dateDescending') {
        return a > b ? -1 : a < b ? 1 : 0
      }

      return a > b ? 1 : a < b ? -1 : 0
    })

    this.updateState(Object.assign({}, state, {
      files: sortedFiles,
      folders: sortedFolders,
      sorting: (sorting === 'dateDescending') ? 'dateAscending' : 'dateDescending'
    }))
  }

  isActiveRow (file) {
    return this.plugin.core.getState()[this.plugin.stateId].activeRow === this.plugin.getItemId(file)
  }

  handleDemoAuth () {
    const state = this.plugin.core.getState()[this.plugin.stateId]
    this.updateState({}, state, {
      authenticated: true
    })
  }

  handleAuth () {
    const urlId = Math.floor(Math.random() * 999999) + 1
    const redirect = `${location.href}${location.search ? '&' : '?'}id=${urlId}`

    const authState = btoa(JSON.stringify({ redirect }))
    const link = `${this.plugin.opts.host}/connect/${this.Provider.authProvider}?state=${authState}`

    const authWindow = window.open(link, '_blank')
    const checkAuth = function () {
      let authWindowUrl

      try {
        authWindowUrl = authWindow.location.href
      } catch (e) {
        if (e instanceof DOMException || e instanceof TypeError) {
          return setTimeout(checkAuth, 100)
        } else throw e
      }

      // split url because chrome adds '#' to redirects
      if (authWindowUrl.split('#')[0] === redirect) {
        authWindow.close()
        this.Provider.auth().then(this.plugin.onAuth)
      } else {
        setTimeout(checkAuth, 100)
      }
    }

    checkAuth()
  }

  render (state) {
    const { authenticated, error } = state[this.plugin.stateId]

    if (error) {
      return ErrorView({ error: error })
    }

    if (!authenticated) {
      return AuthView({
        pluginName: this.plugin.title,
        demo: this.plugin.opts.demo,
        handleAuth: this.handleAuth,
        handleDemoAuth: this.handleDemoAuth
      })
    }

    const browserProps = Object.assign({}, state[this.plugin.stateId], {
      getNextFolder: this.getNextFolder,
      getFolder: this.getFolder,
      addFile: this.addFile,
      filterItems: this.filterItems,
      filterQuery: this.filterQuery,
      handleRowClick: this.handleRowClick,
      sortByTitle: this.sortByTitle,
      sortByDate: this.sortByDate,
      logout: this.logout,
      demo: this.plugin.opts.demo,
      isActiveRow: this.isActiveRow,
      getItemName: this.plugin.getItemName,
      getItemIcon: this.plugin.getItemIcon
    })

    return Browser(browserProps)
  }
}
<|endoftext|>


<commit_before>import {FilterComponent} from "../../src/filter-component";
import {mkEvent} from '../test-utils';

describe("Filter Component", function() {

    describe("types", function() {
        it("should filter out events with other types", function() {
            const filter = new FilterComponent({ types: ['m.room.message'] });
            const event = mkEvent({
                type: 'm.room.member',
                content: { },
                room: 'roomId',
                event: true,
            });

            const checkResult = filter.check(event);

            expect(checkResult).toBe(false);
        });

        it("should validate events with the same type", function() {
            const filter = new FilterComponent({ types: ['m.room.message'] });
            const event = mkEvent({
                type: 'm.room.message',
                content: { },
                room: 'roomId',
                event: true,
            });

            const checkResult = filter.check(event);

            expect(checkResult).toBe(true);
        });

    });

});
<commit_msg>More lint fixes<commit_after>import {FilterComponent} from "../../src/filter-component";
import {mkEvent} from '../test-utils';

describe("Filter Component", function() {
    describe("types", function() {
        it("should filter out events with other types", function() {
            const filter = new FilterComponent({ types: ['m.room.message'] });
            const event = mkEvent({
                type: 'm.room.member',
                content: { },
                room: 'roomId',
                event: true,
            });

            const checkResult = filter.check(event);

            expect(checkResult).toBe(false);
        });

        it("should validate events with the same type", function() {
            const filter = new FilterComponent({ types: ['m.room.message'] });
            const event = mkEvent({
                type: 'm.room.message',
                content: { },
                room: 'roomId',
                event: true,
            });

            const checkResult = filter.check(event);

            expect(checkResult).toBe(true);
        });
    });
});
<|endoftext|>


<commit_before>var pokerConnection = require('../../lib/poker-connection');

describe('poker-connection', function() {
    it('should be initialized', function() {
        var currentUsers = [1,2,3];
        var carddisplay = [8,13,20];
        var connectionHandler = pokerConnection.getNewHandler();

        connectionHandler.init(currentUsers, carddisplay);

        expect(connectionHandler.pokerData).toEqual({
            "users": currentUsers,
            "carddisplay": carddisplay
        });
    });

    it('should set a connection', function() {
        var connectionMock = {
            on: function(type, callback) {}
        };
        spyOn(connectionMock, 'on');

        var connectionHandler = pokerConnection.getNewHandler();
        connectionHandler.init(null, null);
        connectionHandler.setConnection(connectionMock);

        expect(connectionMock.on).toHaveBeenCalledWith('message', jasmine.any(Function));
        expect(connectionMock.on).toHaveBeenCalledWith('close', jasmine.any(Function));
    });

    it('should remove all connection listeners when connection is closed', function() {
        var connectionMock = {
            on: function() {},
            removeAllListeners: function() {}
        };
        spyOn(connectionMock, 'removeAllListeners');

        var connectionHandler = pokerConnection.getNewHandler();
        connectionHandler.init(null, null);
        connectionHandler.setConnection(connectionMock);

        connectionHandler.onclose();
        expect(connectionMock.removeAllListeners).toHaveBeenCalled();
    });

    it('should remove the user and all listeners when connection is closed', function() {

    });
});<commit_msg>spec for user removal<commit_after>var pokerConnection = require('../../lib/poker-connection');

// TODO: remove asap. This is ugly
broadcastUsers = function() {};
broadcastCards = function() {};

describe('poker-connection', function() {
    it('should be initialized', function() {
        var currentUsers = [1,2,3];
        var carddisplay = [8,13,20];
        var connectionHandler = pokerConnection.getNewHandler();

        connectionHandler.init(currentUsers, carddisplay);

        expect(connectionHandler.pokerData).toEqual({
            "users": currentUsers,
            "carddisplay": carddisplay
        });
    });

    it('should set a connection', function() {
        var connectionMock = {
            on: function(type, callback) {}
        };
        spyOn(connectionMock, 'on');

        var connectionHandler = pokerConnection.getNewHandler();
        connectionHandler.init(null, null);
        connectionHandler.setConnection(connectionMock);

        expect(connectionMock.on).toHaveBeenCalledWith('message', jasmine.any(Function));
        expect(connectionMock.on).toHaveBeenCalledWith('close', jasmine.any(Function));
    });

    it('should remove all connection listeners when connection is closed', function() {
        var connectionMock = {
            on: function() {},
            removeAllListeners: function() {}
        };
        spyOn(connectionMock, 'removeAllListeners');

        var connectionHandler = pokerConnection.getNewHandler();
        connectionHandler.init(null, null);
        connectionHandler.setConnection(connectionMock);

        connectionHandler.onclose();
        expect(connectionMock.removeAllListeners).toHaveBeenCalled();
    });

    it('should remove the user and all listeners when connection is closed', function() {
        var connectionMock = {
            on: function() {},
            removeAllListeners: function() {}
        };
        spyOn(connectionMock, 'on');

        var usersMock = {
            remove: function() {}
        };
        spyOn(usersMock, 'remove');

        var carddisplayMock = {
            removeCard: function() {}
        };
        spyOn(carddisplayMock, 'removeCard');

        var userIdMock = 'foobar';

        var connectionHandler = pokerConnection.getNewHandler();
        connectionHandler.init(usersMock, carddisplayMock);
        connectionHandler.setConnection(connectionMock);
        connectionHandler.user = {
            id: userIdMock
        };

        connectionHandler.onclose();

        expect(usersMock.remove).toHaveBeenCalledWith(userIdMock);
        expect(carddisplayMock.removeCard).toHaveBeenCalledWith(userIdMock);
        expect(connectionMock.on).toHaveBeenCalledWith('message', jasmine.any(Function));
        expect(connectionMock.on).toHaveBeenCalledWith('close', jasmine.any(Function));
    });
});<|endoftext|>


<commit_before>/* German translation for the jQuery Timepicker Addon */
/* Written by Marvin */
(function($) {
	$.timepicker.regional['de'] = {
		timeOnlyTitle: 'Zeit Wählen',
		timeText: 'Zeit',
		hourText: 'Stunde',
		minuteText: 'Minute',
		secondText: 'Sekunde',
		millisecText: 'Millisekunde',
		microsecText: 'Mikrosekunde',
		timezoneText: 'Zeitzone',
		currentText: 'Jetzt',
		closeText: 'Fertig',
		timeFormat: 'HH:mm',
		amNames: ['vorm.', 'AM', 'A'],
		pmNames: ['nachm.', 'PM', 'P'],
		isRTL: false
	};
	$.timepicker.setDefaults($.timepicker.regional['de']);
})(jQuery);
<commit_msg>Fix typo in German translation<commit_after>/* German translation for the jQuery Timepicker Addon */
/* Written by Marvin */
(function($) {
	$.timepicker.regional['de'] = {
		timeOnlyTitle: 'Zeit wählen',
		timeText: 'Zeit',
		hourText: 'Stunde',
		minuteText: 'Minute',
		secondText: 'Sekunde',
		millisecText: 'Millisekunde',
		microsecText: 'Mikrosekunde',
		timezoneText: 'Zeitzone',
		currentText: 'Jetzt',
		closeText: 'Fertig',
		timeFormat: 'HH:mm',
		amNames: ['vorm.', 'AM', 'A'],
		pmNames: ['nachm.', 'PM', 'P'],
		isRTL: false
	};
	$.timepicker.setDefaults($.timepicker.regional['de']);
})(jQuery);
<|endoftext|>


<commit_before>import CodeMirror from 'codemirror';
import 'codemirror/addon/hint/javascript-hint';

import Snippet from './Snippet';

const jsHint = CodeMirror.hint.javascript;
CodeMirror.hint.javascript = (instance, options) => {
  const cursor = instance.getCursor();
  const token = instance.getTokenAt(cursor);
  const from = { line: cursor.line, ch: token.start };
  const to = { line: cursor.line, ch: cursor.ch };

  if (endOfCompletion.test(token.string)) {
    return { list: [], from, to };
  }

  options = Object.assign({}, options, jsOptions);

  const result = jsHint(instance, options) || { list: [], from, to };

  const snippets = Object.keys(jsSnippets)
    .filter((key) => key.indexOf(token.string) === 0)
    .map((key) => jsSnippets[key]);

  result.list = snippets.concat(result.list);

  if (token.type === 'string') {
    const left = instance.getLine(cursor.line)
      .substr(0, cursor.ch)
      .substr(token.start + 1);
    const moduleNames = options.files
      .filter(file => file.moduleName.indexOf(left) === 0)
      .map(file => ({
        text: file.moduleName,
        from: { line: from.line, ch: from.ch + 1 },
      }));
    result.list = moduleNames.concat(result.list);
  }

  return result;
};

const globalScope = (keys => {
  const merge = (p, c) => {
    if (typeof c === 'string') {
      p[c] = null;
      return p;
    } else if (c instanceof Array) {
      const key = c[0];
      const props = c.slice(1);
      p[key] = props.reduce(merge, Object.create(null));
    }
    return p;
  };
  return keys.reduce(merge, Object.create(null));
})([
  'require',
  'exports',
  ['module', 'exports'],
  ['console', 'log', 'info', 'warn', 'error', 'time', 'timeEnd'],
  ['env', 'DEBUG', 'VIEW']
]);

const jsOptions = {
  globalScope
};

const jsSnippets = {
  "(": new Snippet({
    text: "() => {};",
    displayText: '() => {}; [anonymous function]',
    pick: (from) => ({
      from: { line: from.line, ch: from.ch - 1 },
      to: { line: from.line, ch: from.ch + 1 },
    }),
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 6 },
      anchor: { line: from.line, ch: from.ch + 6 }
    }]
  }),
  "const": new Snippet({
    text: "const  = ;",
    displayText: '[const]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 6 },
      anchor: { line: from.line, ch: from.ch + 9 }
    }]
  }),
  "import": new Snippet({
    text: "import  from '';",
    displayText: '[import]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 7 },
      anchor: { line: from.line, ch: from.ch + 7 }
    }]
  }),
  "import*": new Snippet({
    text: "import * as  from '';",
    displayText: '[import *]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 12 },
      anchor: { line: from.line, ch: from.ch + 12 }
    }]
  }),
  "exportd": new Snippet({
    text: "export default ;",
    displayText: '[export default]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 15 },
      anchor: { line: from.line, ch: from.ch + 15 }
    }]
  }),
  "export": new Snippet({
    text: "export {  :  };",
    displayText: '[export { name: var }]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 9 },
      anchor: { line: from.line, ch: from.ch + 12 }
    }]
  }),
  "fetchblob": new Snippet({
    text: "fetch('')\n.then(response => response.blob())\n.then(blob => {\n\t\n});",
    displayText: 'fetch() [fetch:Blob]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 7 },
      anchor: { line: from.line, ch: from.ch + 7 }
    }],
    autoIndent: false,
  }),
  "fetchtext": new Snippet({
    text: "fetch('')\n.then(response => response.text())\n.then(text => {\n\t\n});",
    displayText: 'fetch() [fetch:Text]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 7 },
      anchor: { line: from.line, ch: from.ch + 7 }
    }],
    autoIndent: false,
  }),
  "f": new Snippet({
    text: "const  = () => {\n\t// \n};",
    displayText: '() => {}; [function]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 6 },
      anchor: { line: from.line, ch: from.ch + 6 }
    }]
  }),
  "fun": new Snippet({
    text: "function () {}",
    displayText: '[scoped anonymous function]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 13 },
      anchor: { line: from.line, ch: from.ch + 13 }
    }]
  }),
  "funcion": new Snippet({
    text: "function functionName() {\n\t// \n}",
    displayText: '[scoped function]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 9 },
      anchor: { line: from.line, ch: from.ch + 21 }
    }]
  }),
  "if": new Snippet({
    text: "if (true) {\n\t// \n}",
    displayText: '[if]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 4 },
      anchor: { line: from.line, ch: from.ch + 8 }
    }]
  }),
  "else": new Snippet({
    text: "else {\n\t// \n}",
    displayText: '[else]'
  }),
  "try": new Snippet({
    text: "try {} catch (e) {}",
    displayText: '[try-catch]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 5 },
      anchor: { line: from.line, ch: from.ch + 5 }
    }]
  }),
  "log": new Snippet({
    text: "console.log();",
    displayText: '[console.log]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 12 },
      anchor: { line: from.line, ch: from.ch + 12 }
    }]
  }),
  "error": new Snippet({
    text: "console.error();",
    displayText: '[console.error]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 14 },
      anchor: { line: from.line, ch: from.ch + 14 }
    }]
  }),
};

const endOfCompletion = /^(.*[\;\=\)\,]|\s*)$/;
<commit_msg>less completion<commit_after>import CodeMirror from 'codemirror';
import 'codemirror/addon/hint/javascript-hint';

import Snippet from './Snippet';

const jsHint = CodeMirror.hint.javascript;
CodeMirror.hint.javascript = (instance, options) => {
  const cursor = instance.getCursor();
  const token = instance.getTokenAt(cursor);
  const from = { line: cursor.line, ch: token.start };
  const to = { line: cursor.line, ch: cursor.ch };

  if (endOfCompletion.test(token.string)) {
    return { list: [], from, to };
  }

  if (token.type === null && token.string !== '(') {
    return { list: [], from, to };
  }

  options = Object.assign({}, options, jsOptions);

  const result = jsHint(instance, options) || { list: [], from, to };

  const snippets = Object.keys(jsSnippets)
    .filter((key) => key.indexOf(token.string) === 0)
    .map((key) => jsSnippets[key]);

  result.list = snippets.concat(result.list);

  if (token.type === 'string') {
    const left = instance.getLine(cursor.line)
      .substr(0, cursor.ch)
      .substr(token.start + 1);
    const moduleNames = options.files
      .filter(file => file.moduleName.indexOf(left) === 0)
      .map(file => ({
        text: file.moduleName,
        from: { line: from.line, ch: from.ch + 1 },
      }));
    result.list = moduleNames.concat(result.list);
  }

  return result;
};

const globalScope = (keys => {
  const merge = (p, c) => {
    if (typeof c === 'string') {
      p[c] = null;
      return p;
    } else if (c instanceof Array) {
      const key = c[0];
      const props = c.slice(1);
      p[key] = props.reduce(merge, Object.create(null));
    }
    return p;
  };
  return keys.reduce(merge, Object.create(null));
})([
  'require',
  'exports',
  ['module', 'exports'],
  ['console', 'log', 'info', 'warn', 'error', 'time', 'timeEnd'],
  ['env', 'DEBUG', 'VIEW']
]);

const jsOptions = {
  globalScope
};

const jsSnippets = {
  "(": new Snippet({
    text: "() => {};",
    displayText: '() => {}; [anonymous function]',
    pick: (from) => ({
      from: { line: from.line, ch: from.ch - 1 },
      to: { line: from.line, ch: from.ch + 1 },
    }),
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 6 },
      anchor: { line: from.line, ch: from.ch + 6 }
    }]
  }),
  "const": new Snippet({
    text: "const  = ;",
    displayText: '[const]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 6 },
      anchor: { line: from.line, ch: from.ch + 9 }
    }]
  }),
  "import": new Snippet({
    text: "import  from '';",
    displayText: '[import]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 7 },
      anchor: { line: from.line, ch: from.ch + 7 }
    }]
  }),
  "import*": new Snippet({
    text: "import * as  from '';",
    displayText: '[import *]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 12 },
      anchor: { line: from.line, ch: from.ch + 12 }
    }]
  }),
  "exportd": new Snippet({
    text: "export default ;",
    displayText: '[export default]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 15 },
      anchor: { line: from.line, ch: from.ch + 15 }
    }]
  }),
  "export": new Snippet({
    text: "export {  :  };",
    displayText: '[export { name: var }]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 9 },
      anchor: { line: from.line, ch: from.ch + 12 }
    }]
  }),
  "fetchblob": new Snippet({
    text: "fetch('')\n.then(response => response.blob())\n.then(blob => {\n\t\n});",
    displayText: 'fetch() [fetch:Blob]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 7 },
      anchor: { line: from.line, ch: from.ch + 7 }
    }],
    autoIndent: false,
  }),
  "fetchtext": new Snippet({
    text: "fetch('')\n.then(response => response.text())\n.then(text => {\n\t\n});",
    displayText: 'fetch() [fetch:Text]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 7 },
      anchor: { line: from.line, ch: from.ch + 7 }
    }],
    autoIndent: false,
  }),
  "f": new Snippet({
    text: "const  = () => {\n\t// \n};",
    displayText: '() => {}; [function]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 6 },
      anchor: { line: from.line, ch: from.ch + 6 }
    }]
  }),
  "fun": new Snippet({
    text: "function () {}",
    displayText: '[scoped anonymous function]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 13 },
      anchor: { line: from.line, ch: from.ch + 13 }
    }]
  }),
  "funcion": new Snippet({
    text: "function functionName() {\n\t// \n}",
    displayText: '[scoped function]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 9 },
      anchor: { line: from.line, ch: from.ch + 21 }
    }]
  }),
  "if": new Snippet({
    text: "if (true) {\n\t// \n}",
    displayText: '[if]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 4 },
      anchor: { line: from.line, ch: from.ch + 8 }
    }]
  }),
  "else": new Snippet({
    text: "else {\n\t// \n}",
    displayText: '[else]'
  }),
  "try": new Snippet({
    text: "try {} catch (e) {}",
    displayText: '[try-catch]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 5 },
      anchor: { line: from.line, ch: from.ch + 5 }
    }]
  }),
  "log": new Snippet({
    text: "console.log();",
    displayText: '[console.log]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 12 },
      anchor: { line: from.line, ch: from.ch + 12 }
    }]
  }),
  "error": new Snippet({
    text: "console.error();",
    displayText: '[console.error]',
    selections: (from) => [{
      head: { line: from.line, ch: from.ch + 14 },
      anchor: { line: from.line, ch: from.ch + 14 }
    }]
  }),
};

const endOfCompletion = /^(.*[\;\=\)\,]|\s*)$/;
<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, bwcError, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, go, walletService) {

  var isCordova = platformInfo.isCordova;
  var isWP = platformInfo.isWP;
  var isAndroid = platformInfo.isAndroid;
  var isChromeApp = platformInfo.isChromeApp;

  var errorPopup;

  var HISTORY_SHOW_LIMIT = 10;

  $scope.openSearchModal = function() {
    var fc = profileService.focusedClient;
    $scope.color = fc.backgroundColor;
    $scope.self = self;

    $ionicModal.fromTemplateUrl('views/modals/search.html', {
      scope: $scope,
      focusFirstInput: true
    }).then(function(modal) {
      $scope.searchModal = modal;
      $scope.searchModal.show();
    });
  };

  $scope.openTxModal = function(btx) {
    var self = this;

    $scope.btx = lodash.cloneDeep(btx);
    $scope.self = self;

    $ionicModal.fromTemplateUrl('views/modals/tx-details.html', {
      scope: $scope,
      hideDelay: 500
    }).then(function(modal) {
      $scope.txDetailsModal = modal;
      $scope.txDetailsModal.show();
    });
  };

  $scope.recreate = function() {
    walletService.recreate();
  };

  $scope.updateStatus = function(force) {
    $scope.updatingStatus = true;
    $scope.updateStatusError = false;
    $timeout(function() {
      walletService.getStatus(wallet, {
        force: !!force,
      }, function(err, status) {
        $scope.updatingStatus = false;
        if (err) {
          $scope.status = null;
          $scope.updateStatusError = true;
          return;
        }
        $scope.status = status;
      });
    })
  };

  $scope.updateTxHistory = function() {

    if ($scope.updatingTxHistory) return;

    $scope.updatingTxHistory = true;
    $scope.updateTxHistoryError = false;
    $scope.updatingTxHistoryProgress = null;

    var progressFn = function(txs) {
      $scope.updatingTxHistoryProgress = txs ? txs.length : 0;
      completeTxHistory = txs;
      $scope.showHistory();
      $scope.$digest();
    };

    $timeout(function() {
      walletService.getTxHistory(wallet, {
        progressFn: progressFn,
      }, function(err, txHistory) {
        $scope.updatingTxHistory = false;
        if (err) {
          $scope.txHistory = null;
          $scope.updateTxHistoryError = true;
          return;
        }
        completeTxHistory = txHistory;

        $scope.showHistory();
        $scope.$apply();
      });
    });
  };

  $scope.showHistory = function() {
    if ($scope.isSearching) {
      $scope.txHistorySearchResults = filteredTxHistory ? filteredTxHistory.slice(0, (currentTxHistoryPage + 1) * HISTORY_SHOW_LIMIT) : [];
      $scope.txHistoryShowMore = filteredTxHistory.length > $scope.txHistorySearchResults.length;
    } else {
      $scope.txHistory = completeTxHistory ? completeTxHistory.slice(0, (currentTxHistoryPage + 1) * HISTORY_SHOW_LIMIT) : [];
      $scope.txHistoryShowMore = completeTxHistory.length > $scope.txHistory.length;
    }
  };

  $scope.showMore = function() {
    currentTxHistoryPage++;
    $scope.showHistory();
    $scope.$broadcast('scroll.infiniteScrollComplete');
  };

  $scope.updateAll = function()  {
    $scope.updateStatus(false);
    $scope.updateTxHistory();
  }

  $scope.hideToggle = function() {
    console.log('[walletDetails.js.70:hideToogle:] TODO'); //TODO
  };

  var currentTxHistoryPage;
  var completeTxHistory;
  var wallet;

  $scope.init = function() {
    currentTxHistoryPage = 0;
    completeTxHistory = [];

    wallet = profileService.getWallet($stateParams.walletId);
    $scope.wallet = wallet;
    $scope.requiresMultipleSignatures = wallet.credentials.m > 1;
    $scope.newTx = false;

    $scope.updateAll();
  };

});
<commit_msg>Fix history<commit_after>'use strict';

angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, bwcError, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, go, walletService) {

  var isCordova = platformInfo.isCordova;
  var isWP = platformInfo.isWP;
  var isAndroid = platformInfo.isAndroid;
  var isChromeApp = platformInfo.isChromeApp;

  var errorPopup;

  var HISTORY_SHOW_LIMIT = 10;

  $scope.openSearchModal = function() {
    var fc = profileService.focusedClient;
    $scope.color = fc.backgroundColor;
    $scope.self = self;

    $ionicModal.fromTemplateUrl('views/modals/search.html', {
      scope: $scope,
      focusFirstInput: true
    }).then(function(modal) {
      $scope.searchModal = modal;
      $scope.searchModal.show();
    });
  };

  $scope.openTxModal = function(btx) {
    var self = this;

    $scope.btx = lodash.cloneDeep(btx);
    $scope.self = self;

    $ionicModal.fromTemplateUrl('views/modals/tx-details.html', {
      scope: $scope,
      hideDelay: 500
    }).then(function(modal) {
      $scope.txDetailsModal = modal;
      $scope.txDetailsModal.show();
    });
  };

  $scope.recreate = function() {
    walletService.recreate();
  };

  $scope.updateStatus = function(force) {
    $scope.updatingStatus = true;
    $scope.updateStatusError = false;
    $timeout(function() {
      walletService.getStatus(wallet, {
        force: !!force,
      }, function(err, status) {
        $scope.updatingStatus = false;
        if (err) {
          $scope.status = null;
          $scope.updateStatusError = true;
          return;
        }
        $scope.status = status;
      });
    })
  };

  $scope.updateTxHistory = function() {

    if ($scope.updatingTxHistory) return;

    $scope.updatingTxHistory = true;
    $scope.updateTxHistoryError = false;
    $scope.updatingTxHistoryProgress = null;

    var progressFn = function(txs) {
      $scope.updatingTxHistoryProgress = txs ? txs.length : 0;
      completeTxHistory = txs;
      $scope.showHistory();
      $scope.$digest();
    };

    $timeout(function() {
      walletService.getTxHistory(wallet, {
        progressFn: progressFn,
      }, function(err, txHistory) {
        $scope.updatingTxHistory = false;
        if (err) {
          $scope.txHistory = null;
          $scope.updateTxHistoryError = true;
          return;
        }
        completeTxHistory = txHistory;

        $scope.showHistory();
        $scope.$apply();
      });
    });
  };

  $scope.showHistory = function() {
    if ($scope.isSearching) {
      $scope.txHistorySearchResults = filteredTxHistory ? filteredTxHistory.slice(0, (currentTxHistoryPage + 1) * HISTORY_SHOW_LIMIT) : [];
      $scope.txHistoryShowMore = filteredTxHistory.length > $scope.txHistorySearchResults.length;
    } else if (completeTxHistory) {
      $scope.txHistory = completeTxHistory.slice(0, (currentTxHistoryPage + 1) * HISTORY_SHOW_LIMIT);
      $scope.txHistoryShowMore = completeTxHistory.length > $scope.txHistory.length;
    }
  };

  $scope.showMore = function() {
    currentTxHistoryPage++;
    $scope.showHistory();
    $scope.$broadcast('scroll.infiniteScrollComplete');
  };

  $scope.updateAll = function()  {
    $scope.updateStatus(false);
    $scope.updateTxHistory();
  }

  $scope.hideToggle = function() {
    console.log('[walletDetails.js.70:hideToogle:] TODO'); //TODO
  };

  var currentTxHistoryPage;
  var completeTxHistory;
  var wallet;

  $scope.init = function() {
    currentTxHistoryPage = 0;
    completeTxHistory = [];

    wallet = profileService.getWallet($stateParams.walletId);
    $scope.wallet = wallet;
    $scope.requiresMultipleSignatures = wallet.credentials.m > 1;
    $scope.newTx = false;

    $scope.updateAll();
  };

});
<|endoftext|>


<commit_before>const Q = require('q')
const deviceGeo = require('./get-location')
const querystring = require('../get-url-parameter')
const supportedCities = require('./supportedCities')
const browser = require('../browser')
const cookies = require('../cookies')

import * as postcodes from './postcodes'
import * as storage from '../storage'

const myLocationId = 'my-location'

const _useMyLocation = (deferred) => {
  const defaultResolution = () => {
    let cityId = myLocationId
    const saved = cookies.get(cookies.keys.location)
    if (saved !== undefined && saved.length > 0) {
      cityId = supportedCities.get(saved).id
    }
    deferred.resolve({
      id: cityId,
      findHelpId: myLocationId,
      isSelected: true,
      latitude: 0,
      longitude: 0,
      name: 'my location',
      geoLocationUnavailable: true
    })
  }
  deviceGeo.location()
    .then((userLocation) => {
      let cityId = 'my-location'
      const saved = cookies.get(cookies.keys.location)
      if (cookies.get(cookies.keys.location) !== undefined && saved.length > 0) {
        cityId = supportedCities.get(saved).id
      }
      postcodes.getByCoords(userLocation.coords, (postcode) => {
        storage.set(storage.keys.userLocationState, {
          'postcode': postcode,
          'longitude': userLocation.coords.longitude,
          'latitude': userLocation.coords.latitude
        })
        deferred.resolve({
          id: cityId,
          findHelpId: myLocationId,
          isSelected: true,
          latitude: userLocation.coords.latitude,
          longitude: userLocation.coords.longitude,
          name: 'my location',
          postcode: postcode
        })
      }, defaultResolution)
    }, () => {
      defaultResolution()
    })
}

const _useRequested = (deferred, locationInQueryString) => {
  const requestedCity = supportedCities.get(locationInQueryString)
  if (requestedCity !== undefined) {
    deferred.resolve(requestedCity)
  } else {
    alert('uh oh')
  }
}

const _useSaved = (deferred) => {
  const saved = cookies.get(cookies.keys.location)
  if (saved === 'elsewhere' && deviceGeo.isAvailable()) {
    _useMyLocation(deferred)
  } else if (saved !== undefined && saved.length > 0 && saved !== myLocationId) {
    deferred.resolve(supportedCities.get(saved))
  } else {
    alert('uh oh')
  }
}

const _determineLocationRetrievalMethod = () => {
  let method = _useSaved
  let id = ''

  const locationInQueryString = querystring.parameter('location')
  if (locationInQueryString === myLocationId && deviceGeo.isAvailable()) {
    method = _useMyLocation
  } else if (locationInQueryString !== 'undefined' && locationInQueryString.length > 0 && locationInQueryString !== myLocationId) {
    method = _useRequested
    id = locationInQueryString
  } else {
    const locationInPath = browser.location().pathname.split('/')[1]
    const cities = supportedCities.locations.map((l) => l.id)
    if (locationInPath !== 'undefined' && locationInPath.length > 0 && cities.indexOf(locationInPath) > -1) {
      method = _useRequested
      id = locationInPath

      setCurrent(id)
    }
  }

  return {
    method: method,
    id: id
  }
}

const getSelectedLocationId = () => {
  const saved = cookies.get(cookies.keys.location) || 'elsewhere'
  if (cookies.get(cookies.keys.location) !== undefined && saved.length > 0) {
    return supportedCities.get(saved).id
  }
}

const getCurrent = () => {
  const deferred = Q.defer()
  const getLocation = _determineLocationRetrievalMethod()
  getLocation.method(deferred, getLocation.id)
  return deferred.promise
}

const buildLocationResult = (userLocationState) => {
  return {
    'id': 'my-location',
    'findHelpId': 'my-location',
    'name': 'my selected postcode',
    'longitude': userLocationState.longitude,
    'latitude': userLocationState.latitude,
    'isPublic': true,
    'isSelectableInBody': false,
    'postcode': userLocationState.postcode
  }
}

const getPreviouslySetPostcode = () => {
  const deferred = Q.defer()
  const userLocationState = storage.get(storage.keys.userLocationState)
  if (userLocationState) {
    deferred.resolve(buildLocationResult(userLocationState))
  } else {
    const getLocation = _determineLocationRetrievalMethod()
    getLocation.method(deferred, getLocation.id)
  }

  return deferred.promise
}

const setPostcode = (postcode, onSuccessCallback, onErrorCallback) => {
  postcodes.getCoords(postcode, (coordsResult) => {
    storage.set(storage.keys.userLocationState, coordsResult)
    onSuccessCallback(buildLocationResult(coordsResult))
  }, (error) => {
    onErrorCallback(error)
  })
}

const setCurrent = (newCity) => {
  if (newCity.length > 0) {
    const selectedCity = supportedCities.locations.find(c => c.id === newCity)
    storage.set(storage.keys.userLocationState, {
      'postcode': selectedCity.postcode,
      'longitude': selectedCity.longitude,
      'latitude': selectedCity.latitude
    })
    document.cookie = `${cookies.keys.location}=${newCity};expires=Fri, 31 Dec 9999 23:59:59 GMT;path=/`
  }
}

/**
 * initialise location dropdown with selectorId inject a callback when location selector changes
 * @param {function} onChangeLocationCallback
 * @param {string} selectorId
 */
const onChange = (onChangeLocationCallback, selectorId = '.js-location-select') => {
  const locationSelector = document.querySelector(selectorId)
  locationSelector.addEventListener('change', () => {
    var selectedLocation = locationSelector.options[locationSelector.selectedIndex].value
    setCurrent(selectedLocation)
    onChangeLocationCallback(selectedLocation)
  })
}

const exportedObj = {
  getSelectedLocationId: getSelectedLocationId,
  getPreviouslySetPostcode: getPreviouslySetPostcode,
  setPostcode: setPostcode,
  getCurrent: getCurrent,
  setCurrent: setCurrent,
  handler: onChange
}

module.exports = exportedObj
<commit_msg>remove querystring location check<commit_after>const Q = require('q')
const deviceGeo = require('./get-location')
const querystring = require('../get-url-parameter')
const supportedCities = require('./supportedCities')
const browser = require('../browser')
const cookies = require('../cookies')

import * as postcodes from './postcodes'
import * as storage from '../storage'

const myLocationId = 'my-location'

const _useMyLocation = (deferred) => {
  const defaultResolution = () => {
    let cityId = myLocationId
    const saved = cookies.get(cookies.keys.location)
    if (saved !== undefined && saved.length > 0) {
      cityId = supportedCities.get(saved).id
    }
    deferred.resolve({
      id: cityId,
      findHelpId: myLocationId,
      isSelected: true,
      latitude: 0,
      longitude: 0,
      name: 'my location',
      geoLocationUnavailable: true
    })
  }
  deviceGeo.location()
    .then((userLocation) => {
      let cityId = 'my-location'
      const saved = cookies.get(cookies.keys.location)
      if (cookies.get(cookies.keys.location) !== undefined && saved.length > 0) {
        cityId = supportedCities.get(saved).id
      }
      postcodes.getByCoords(userLocation.coords, (postcode) => {
        storage.set(storage.keys.userLocationState, {
          'postcode': postcode,
          'longitude': userLocation.coords.longitude,
          'latitude': userLocation.coords.latitude
        })
        deferred.resolve({
          id: cityId,
          findHelpId: myLocationId,
          isSelected: true,
          latitude: userLocation.coords.latitude,
          longitude: userLocation.coords.longitude,
          name: 'my location',
          postcode: postcode
        })
      }, defaultResolution)
    }, () => {
      defaultResolution()
    })
}

const _useSaved = (deferred) => {
  const saved = cookies.get(cookies.keys.location)
  if (saved === 'elsewhere' && deviceGeo.isAvailable()) {
    _useMyLocation(deferred)
  } else if (saved !== undefined && saved.length > 0 && saved !== myLocationId) {
    deferred.resolve(supportedCities.get(saved))
  } else {
    alert('uh oh')
  }
}

const _determineLocationRetrievalMethod = () => {
  let method = _useSaved
  let id = ''

  const locationInPath = browser.location().pathname.split('/')[1]
  const cities = supportedCities.locations.map((l) => l.id)
  if (locationInPath !== 'undefined' && locationInPath.length > 0 && cities.indexOf(locationInPath) > -1) {
    method = _useRequested
    id = locationInPath

    setCurrent(id)
  }

  return {
    method: method,
    id: id
  }
}

const getSelectedLocationId = () => {
  const saved = cookies.get(cookies.keys.location) || 'elsewhere'
  if (cookies.get(cookies.keys.location) !== undefined && saved.length > 0) {
    return supportedCities.get(saved).id
  }
}

const getCurrent = () => {
  const deferred = Q.defer()
  const getLocation = _determineLocationRetrievalMethod()
  getLocation.method(deferred, getLocation.id)
  return deferred.promise
}

const buildLocationResult = (userLocationState) => {
  return {
    'id': 'my-location',
    'findHelpId': 'my-location',
    'name': 'my selected postcode',
    'longitude': userLocationState.longitude,
    'latitude': userLocationState.latitude,
    'isPublic': true,
    'isSelectableInBody': false,
    'postcode': userLocationState.postcode
  }
}

const getPreviouslySetPostcode = () => {
  const deferred = Q.defer()
  const userLocationState = storage.get(storage.keys.userLocationState)
  if (userLocationState) {
    deferred.resolve(buildLocationResult(userLocationState))
  } else {
    const getLocation = _determineLocationRetrievalMethod()
    getLocation.method(deferred, getLocation.id)
  }

  return deferred.promise
}

const setPostcode = (postcode, onSuccessCallback, onErrorCallback) => {
  postcodes.getCoords(postcode, (coordsResult) => {
    storage.set(storage.keys.userLocationState, coordsResult)
    onSuccessCallback(buildLocationResult(coordsResult))
  }, (error) => {
    onErrorCallback(error)
  })
}

const setCurrent = (newCity) => {
  if (newCity.length > 0) {
    const selectedCity = supportedCities.locations.find(c => c.id === newCity)
    storage.set(storage.keys.userLocationState, {
      'postcode': selectedCity.postcode,
      'longitude': selectedCity.longitude,
      'latitude': selectedCity.latitude
    })
    document.cookie = `${cookies.keys.location}=${newCity};expires=Fri, 31 Dec 9999 23:59:59 GMT;path=/`
  }
}

/**
 * initialise location dropdown with selectorId inject a callback when location selector changes
 * @param {function} onChangeLocationCallback
 * @param {string} selectorId
 */
const onChange = (onChangeLocationCallback, selectorId = '.js-location-select') => {
  const locationSelector = document.querySelector(selectorId)
  locationSelector.addEventListener('change', () => {
    var selectedLocation = locationSelector.options[locationSelector.selectedIndex].value
    setCurrent(selectedLocation)
    onChangeLocationCallback(selectedLocation)
  })
}

const exportedObj = {
  getSelectedLocationId: getSelectedLocationId,
  getPreviouslySetPostcode: getPreviouslySetPostcode,
  setPostcode: setPostcode,
  getCurrent: getCurrent,
  setCurrent: setCurrent,
  handler: onChange
}

module.exports = exportedObj
<|endoftext|>


<commit_before>'use strict';

define(['angular', 'model/TLCoin', 'model/TLWalletJSONKeys', 'model/TLBitcoinJSWrapper', 'model/TLWalletUtils', 'model/TLImportedAddress'],
    function(angular, TLCoin, TLWalletJSONKeys, TLBitcoinJSWrapper, TLWalletUtils, TLImportedAddress) {

        function TLImportedAddresses(appDelegate, importedAddresses, accountAddressType) {
            this.appDelegate = appDelegate;
            this.appWallet = appDelegate.appWallet;
            this.importedAddresses = [];
            this.archivedImportedAddresses = [];
            this.addressToIdxDict = {};
            this.addressToPositionInWalletArrayDict = {};
            this.accountAddressType = accountAddressType;
            for (var i = 0; i < importedAddresses.length; i++) {
                var importedAddressObject = importedAddresses[i];
                if (importedAddressObject.isArchived()) {
                    this.archivedImportedAddresses.push(importedAddressObject);
                } else {
                    var indexes = this.addressToIdxDict[importedAddressObject.getAddress()];
                    if (indexes == null) {
                        indexes = [];
                        this.addressToIdxDict[importedAddressObject.getAddress()] = indexes;
                    }
                    indexes.push(this.importedAddresses.length);
                    this.importedAddresses.push(importedAddressObject);
                }

                importedAddressObject.setPositionInWalletArray(i);
                this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()] = importedAddressObject;
            }
        }

        TLImportedAddresses.prototype.getAddressObjectAtIdx = function(idx) {
            return this.importedAddresses[idx];
        };

        TLImportedAddresses.prototype.getArchivedAddressObjectAtIdx = function(idx) {
            return this.archivedImportedAddresses[idx];
        };

        TLImportedAddresses.prototype.getIdxForAddressObject = function(addressObject) {
            return this.importedAddresses.indexOf(addressObject);
        };

        TLImportedAddresses.prototype.getIdxForArchivedAddressObject = function(addressObject) {
            return this.archivedImportedAddresses.indexOf(addressObject);
        };

        TLImportedAddresses.prototype.getCount = function() {
            return this.importedAddresses.length;
        };

        TLImportedAddresses.prototype.getArchivedCount = function() {
            return this.archivedImportedAddresses.length;
        };

        TLImportedAddresses.prototype.checkToGetAndSetAddressesData = function(fetchDataAgain, success, failure) {
            var addresses = new Set();
            for (var i = 0; i < this.importedAddresses; i++) {
                var importedAddressObject = this.importedAddresses[i];
                if (!importedAddressObject.hasFetchedAccountData() || fetchDataAgain) {
                    var address = importedAddressObject.getAddress();
                    addresses.add(address);
                }
            }
            if (addresses.length == 0) {
                success();
                return;
            }
            var self = this;
            this.appDelegate.blockExplorerAPI.getAddressesInfo(Array.from(addresses), function(jsonData) {
                //console.log("checkToGetAndSetAddressesData jsonData " + JSON.stringify(jsonData, null, 2));
                if (jsonData == null) {
                    success ? success() : null;
                    return;
                }
                var txArray = jsonData["txs"];
                if (txArray == null) {
                    success ? success() : null;
                    return;
                }
                var addressesArray = jsonData["addresses"];
                if (addressesArray == null) {
                    success ? success() : null;
                    return;
                }
                for (var i = 0; i < addressesArray.length; i++) {
                    var addressDict = addressesArray[i];
                    var address = addressDict["address"];

                    var indexes = self.addressToIdxDict[address];
                    for (var i = 0; i <indexes.length; i++) {
                        var importedAddressObject = self.importedAddresses[[indexes[i]]];
                        importedAddressObject.balance = new TLCoin(addressDict["final_balance"]);
                        importedAddressObject.processTxArray(txArray, false);
                        importedAddressObject.setHasFetchedAccountData(true, Math.floor(Date.now() / 1000));
                    }
                }

                self.appDelegate.postEvent('wallet', {'type': 'EVENT_FETCHED_ADDRESSES_DATA'});
                success ? success() : null;
            }, function(response) {
                failure ? failure() : null;
            });
        };

        TLImportedAddresses.prototype.addImportedPrivateKey = function(privateKey, encryptedPrivateKey) {
            var importedPrivateKeyDict = this.appWallet.addImportedPrivateKey(privateKey, encryptedPrivateKey);
            var importedAddressObject = new TLImportedAddress(this.appDelegate, importedPrivateKeyDict);
            this.importedAddresses.push(importedAddressObject);
            importedAddressObject.setPositionInWalletArray(this.importedAddresses.length - 1);
            this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()] = importedAddressObject;
            var address = TLBitcoinJSWrapper.getAddress(privateKey, this.appWallet.isTestnet());
            var indexes = this.addressToIdxDict[address];
            if (indexes == null) {
                indexes = [];
                this.addressToIdxDict[importedAddressObject.getAddress()] = indexes;
            }
            indexes.push(this.importedAddresses.length-1);
            this.setLabel(importedAddressObject.getDefaultAddressLabel(), this.importedAddresses.length-1);
            return importedAddressObject;
        };

        TLImportedAddresses.prototype.addImportedWatchAddress = function(address) {
            var importedDict = this.appWallet.addWatchOnlyAddress(address);
            var importedAddressObject = new TLImportedAddress(this.appDelegate, importedDict);
            this.importedAddresses.push(importedAddressObject);
            importedAddressObject.setPositionInWalletArray(this.importedAddresses.length - 1);
            this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()] = importedAddressObject;
            var indexes = this.addressToIdxDict[address];
            if (indexes == null) {
                indexes = [];
                this.addressToIdxDict[address] = indexes;
            }
            indexes.push(this.importedAddresses.length-1);
            this.setLabel(importedAddressObject.getDefaultAddressLabel(), this.importedAddresses.length-1);
            return importedAddressObject;
        };

        TLImportedAddresses.prototype.setLabel = function(label, positionInWalletArray) {
            var importedAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            importedAddressObject.setLabel(label);
            if (this.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED) {
                this.appWallet.setImportedPrivateKeyLabel(label, positionInWalletArray);
            } else if (self.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED_WATCH) {
                this.appWallet.setWatchOnlyAddressLabel(label, positionInWalletArray);
            }
            return true;
        };

        TLImportedAddresses.prototype.archiveAddress = function(positionInWalletArray) {
            this.setArchived(positionInWalletArray, true);
            var toMoveAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            var indexes = this.addressToIdxDict[toMoveAddressObject.getAddress()];
            if (indexes == null) {
                indexes = [];
                this.addressToIdxDict[toMoveAddressObject.getAddress()] = indexes;
            }
            var toMoveIndex = this.importedAddresses.indexOf(toMoveAddressObject);
            for (var key in this.addressToIdxDict) {
                var indexes = angular.copy(this.addressToIdxDict[key]);
                for (var i = 0; i < indexes.length; i++) {
                    var idx = indexes[i];
                    if (idx > toMoveIndex) {
                        var indexes = this.addressToIdxDict[key];
                        indexes.splice(indexes.indexOf(idx), 1);
                        indexes.push(idx-1);
                    }
                }
            }
            indexes.splice(this.importedAddresses.indexOf(toMoveIndex), 1);
            this.importedAddresses.splice(this.importedAddresses.indexOf(toMoveAddressObject), 1);
            for (var i = 0; i < this.archivedImportedAddresses.length; i++) {
                var importedAddressObject = this.archivedImportedAddresses[i];
                if (importedAddressObject.getPositionInWalletArray() > toMoveAddressObject.getPositionInWalletArray()) {
                    this.archivedImportedAddresses.splice(i, 0, toMoveAddressObject);
                    return;
                }
            }
            this.archivedImportedAddresses.push(toMoveAddressObject);
        };

        TLImportedAddresses.prototype.unarchiveAddress = function(positionInWalletArray) {
            this.setArchived(positionInWalletArray, false);
            var toMoveAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            this.archivedImportedAddresses.splice(this.archivedImportedAddresses.indexOf(toMoveAddressObject), 1);

            for (var i = 0; i < this.importedAddresses.length; i++) {
                var importedAddressObject = this.importedAddresses[i];
                if (importedAddressObject.getPositionInWalletArray() > toMoveAddressObject.getPositionInWalletArray()) {
                    this.importedAddresses.splice(i, 0, toMoveAddressObject);
                    var indexes = this.addressToIdxDict[toMoveAddressObject.getAddress()];
                    if (indexes == null) {
                        indexes = [i];
                        this.addressToIdxDict[toMoveAddressObject.getAddress()] = indexes;
                    }
                    for (var key in this.addressToIdxDict) {
                        var indexes = angular.copy(this.addressToIdxDict[key]);
                        for (var i = 0; i < indexes.length; i++) {
                            var idx = indexes[i];
                            if (idx > i) {
                                var indexes = this.addressToIdxDict[key];
                                indexes.splice(indexes.indexOf(idx), 1);
                                indexes.push(idx-1);
                            }
                        }
                    }
                    return;
                }
            }
            this.importedAddresses.push(toMoveAddressObject);
        };

        TLImportedAddresses.prototype.setArchived = function(positionInWalletArray, archive) {
            var importedAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            importedAddressObject.setArchived(archive);
            if (this.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED) {
                this.appWallet.setImportedPrivateKeyArchive(archive, positionInWalletArray);
            } else if (self.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED_WATCH) {
                this.appWallet.setWatchOnlyAddressArchive(archive, positionInWalletArray);
            }
            return true;
        };

        TLImportedAddresses.prototype.deleteAddress = function(idx) {
            var importedAddressObject = this.archivedImportedAddresses[idx];
            this.archivedImportedAddresses.splice(idx, 1);
            if (this.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED) {
                this.appWallet.deleteImportedPrivateKey(importedAddressObject.getPositionInWalletArray());
            } else if (self.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED_WATCH) {
                this.appWallet.deleteImportedWatchAddress(importedAddressObject.getPositionInWalletArray());
            }
            delete this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()];
            var tmpDict = angular.copy(this.addressToPositionInWalletArrayDict);
            for (var key in tmpDict) {
                var ia = this.addressToPositionInWalletArrayDict[key];
                if (ia.getPositionInWalletArray() > importedAddressObject.getPositionInWalletArray()) {
                    ia.setPositionInWalletArray(ia.getPositionInWalletArray()-1);
                    this.addressToPositionInWalletArrayDict[ia.getPositionInWalletArray()] = ia;
                }
            }
            if (importedAddressObject.getPositionInWalletArray() < this.addressToPositionInWalletArrayDict.length - 1) {
                delete this.addressToPositionInWalletArrayDict[this.addressToPositionInWalletArrayDict.length-1];
            }
            return true;
        };

        TLImportedAddresses.prototype.hasFetchedAddressesData = function() {
            for (var i = 0; i < this.importedAddresses.length; i++) {
                var importedAddressObject = this.importedAddresses[i];
                if (!importedAddressObject.hasFetchedAccountData()) {
                    return false
                }
            }
            return true;
        };

        return TLImportedAddresses;
    });
<commit_msg>Fix issue where adding imported addresses has PositionInWalletArray set incorrectly<commit_after>'use strict';

define(['angular', 'model/TLCoin', 'model/TLWalletJSONKeys', 'model/TLBitcoinJSWrapper', 'model/TLWalletUtils', 'model/TLImportedAddress'],
    function(angular, TLCoin, TLWalletJSONKeys, TLBitcoinJSWrapper, TLWalletUtils, TLImportedAddress) {

        function TLImportedAddresses(appDelegate, importedAddresses, accountAddressType) {
            this.appDelegate = appDelegate;
            this.appWallet = appDelegate.appWallet;
            this.importedAddresses = [];
            this.archivedImportedAddresses = [];
            this.addressToIdxDict = {};
            this.addressToPositionInWalletArrayDict = {};
            this.accountAddressType = accountAddressType;
            for (var i = 0; i < importedAddresses.length; i++) {
                var importedAddressObject = importedAddresses[i];
                if (importedAddressObject.isArchived()) {
                    this.archivedImportedAddresses.push(importedAddressObject);
                } else {
                    var indexes = this.addressToIdxDict[importedAddressObject.getAddress()];
                    if (indexes == null) {
                        indexes = [];
                        this.addressToIdxDict[importedAddressObject.getAddress()] = indexes;
                    }
                    indexes.push(this.importedAddresses.length);
                    this.importedAddresses.push(importedAddressObject);
                }

                importedAddressObject.setPositionInWalletArray(i);
                this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()] = importedAddressObject;
            }
        }

        TLImportedAddresses.prototype.getAddressObjectAtIdx = function(idx) {
            return this.importedAddresses[idx];
        };

        TLImportedAddresses.prototype.getArchivedAddressObjectAtIdx = function(idx) {
            return this.archivedImportedAddresses[idx];
        };

        TLImportedAddresses.prototype.getIdxForAddressObject = function(addressObject) {
            return this.importedAddresses.indexOf(addressObject);
        };

        TLImportedAddresses.prototype.getIdxForArchivedAddressObject = function(addressObject) {
            return this.archivedImportedAddresses.indexOf(addressObject);
        };

        TLImportedAddresses.prototype.getCount = function() {
            return this.importedAddresses.length;
        };

        TLImportedAddresses.prototype.getArchivedCount = function() {
            return this.archivedImportedAddresses.length;
        };

        TLImportedAddresses.prototype.checkToGetAndSetAddressesData = function(fetchDataAgain, success, failure) {
            var addresses = new Set();
            for (var i = 0; i < this.importedAddresses; i++) {
                var importedAddressObject = this.importedAddresses[i];
                if (!importedAddressObject.hasFetchedAccountData() || fetchDataAgain) {
                    var address = importedAddressObject.getAddress();
                    addresses.add(address);
                }
            }
            if (addresses.length == 0) {
                success();
                return;
            }
            var self = this;
            this.appDelegate.blockExplorerAPI.getAddressesInfo(Array.from(addresses), function(jsonData) {
                //console.log("checkToGetAndSetAddressesData jsonData " + JSON.stringify(jsonData, null, 2));
                if (jsonData == null) {
                    success ? success() : null;
                    return;
                }
                var txArray = jsonData["txs"];
                if (txArray == null) {
                    success ? success() : null;
                    return;
                }
                var addressesArray = jsonData["addresses"];
                if (addressesArray == null) {
                    success ? success() : null;
                    return;
                }
                for (var i = 0; i < addressesArray.length; i++) {
                    var addressDict = addressesArray[i];
                    var address = addressDict["address"];

                    var indexes = self.addressToIdxDict[address];
                    for (var i = 0; i <indexes.length; i++) {
                        var importedAddressObject = self.importedAddresses[[indexes[i]]];
                        importedAddressObject.balance = new TLCoin(addressDict["final_balance"]);
                        importedAddressObject.processTxArray(txArray, false);
                        importedAddressObject.setHasFetchedAccountData(true, Math.floor(Date.now() / 1000));
                    }
                }

                self.appDelegate.postEvent('wallet', {'type': 'EVENT_FETCHED_ADDRESSES_DATA'});
                success ? success() : null;
            }, function(response) {
                failure ? failure() : null;
            });
        };

        TLImportedAddresses.prototype.addImportedPrivateKey = function(privateKey, encryptedPrivateKey) {
            var importedPrivateKeyDict = this.appWallet.addImportedPrivateKey(privateKey, encryptedPrivateKey);
            var importedAddressObject = new TLImportedAddress(this.appDelegate, importedPrivateKeyDict);
            this.importedAddresses.push(importedAddressObject);
            importedAddressObject.setPositionInWalletArray(this.importedAddresses.length + this.archivedImportedAddresses.length - 1);
            this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()] = importedAddressObject;
            var address = TLBitcoinJSWrapper.getAddress(privateKey, this.appWallet.isTestnet());
            var indexes = this.addressToIdxDict[address];
            if (indexes == null) {
                indexes = [];
                this.addressToIdxDict[importedAddressObject.getAddress()] = indexes;
            }
            indexes.push(this.importedAddresses.length-1);
            this.setLabel(importedAddressObject.getDefaultAddressLabel(), importedAddressObject.getPositionInWalletArray());
            return importedAddressObject;
        };

        TLImportedAddresses.prototype.addImportedWatchAddress = function(address) {
            var importedDict = this.appWallet.addWatchOnlyAddress(address);
            var importedAddressObject = new TLImportedAddress(this.appDelegate, importedDict);
            this.importedAddresses.push(importedAddressObject);
            importedAddressObject.setPositionInWalletArray(this.importedAddresses.length + this.archivedImportedAddresses.length - 1);
            this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()] = importedAddressObject;
            var indexes = this.addressToIdxDict[address];
            if (indexes == null) {
                indexes = [];
                this.addressToIdxDict[address] = indexes;
            }
            indexes.push(this.importedAddresses.length-1);
            this.setLabel(importedAddressObject.getDefaultAddressLabel(), importedAddressObject.getPositionInWalletArray());
            return importedAddressObject;
        };

        TLImportedAddresses.prototype.setLabel = function(label, positionInWalletArray) {
            var importedAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            importedAddressObject.setLabel(label);
            if (this.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED) {
                this.appWallet.setImportedPrivateKeyLabel(label, positionInWalletArray);
            } else if (self.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED_WATCH) {
                this.appWallet.setWatchOnlyAddressLabel(label, positionInWalletArray);
            }
            return true;
        };

        TLImportedAddresses.prototype.archiveAddress = function(positionInWalletArray) {
            this.setArchived(positionInWalletArray, true);
            var toMoveAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            var indexes = this.addressToIdxDict[toMoveAddressObject.getAddress()];
            if (indexes == null) {
                indexes = [];
                this.addressToIdxDict[toMoveAddressObject.getAddress()] = indexes;
            }
            var toMoveIndex = this.importedAddresses.indexOf(toMoveAddressObject);
            for (var key in this.addressToIdxDict) {
                var indexes = angular.copy(this.addressToIdxDict[key]);
                for (var i = 0; i < indexes.length; i++) {
                    var idx = indexes[i];
                    if (idx > toMoveIndex) {
                        var indexes = this.addressToIdxDict[key];
                        indexes.splice(indexes.indexOf(idx), 1);
                        indexes.push(idx-1);
                    }
                }
            }
            indexes.splice(this.importedAddresses.indexOf(toMoveIndex), 1);
            this.importedAddresses.splice(this.importedAddresses.indexOf(toMoveAddressObject), 1);
            for (var i = 0; i < this.archivedImportedAddresses.length; i++) {
                var importedAddressObject = this.archivedImportedAddresses[i];
                if (importedAddressObject.getPositionInWalletArray() > toMoveAddressObject.getPositionInWalletArray()) {
                    this.archivedImportedAddresses.splice(i, 0, toMoveAddressObject);
                    return;
                }
            }
            this.archivedImportedAddresses.push(toMoveAddressObject);
        };

        TLImportedAddresses.prototype.unarchiveAddress = function(positionInWalletArray) {
            this.setArchived(positionInWalletArray, false);
            var toMoveAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            this.archivedImportedAddresses.splice(this.archivedImportedAddresses.indexOf(toMoveAddressObject), 1);

            for (var i = 0; i < this.importedAddresses.length; i++) {
                var importedAddressObject = this.importedAddresses[i];
                if (importedAddressObject.getPositionInWalletArray() > toMoveAddressObject.getPositionInWalletArray()) {
                    this.importedAddresses.splice(i, 0, toMoveAddressObject);
                    var indexes = this.addressToIdxDict[toMoveAddressObject.getAddress()];
                    if (indexes == null) {
                        indexes = [i];
                        this.addressToIdxDict[toMoveAddressObject.getAddress()] = indexes;
                    }
                    for (var key in this.addressToIdxDict) {
                        var indexes = angular.copy(this.addressToIdxDict[key]);
                        for (var i = 0; i < indexes.length; i++) {
                            var idx = indexes[i];
                            if (idx > i) {
                                var indexes = this.addressToIdxDict[key];
                                indexes.splice(indexes.indexOf(idx), 1);
                                indexes.push(idx-1);
                            }
                        }
                    }
                    return;
                }
            }
            this.importedAddresses.push(toMoveAddressObject);
        };

        TLImportedAddresses.prototype.setArchived = function(positionInWalletArray, archive) {
            var importedAddressObject = this.addressToPositionInWalletArrayDict[positionInWalletArray];
            importedAddressObject.setArchived(archive);
            if (this.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED) {
                this.appWallet.setImportedPrivateKeyArchive(archive, positionInWalletArray);
            } else if (self.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED_WATCH) {
                this.appWallet.setWatchOnlyAddressArchive(archive, positionInWalletArray);
            }
            return true;
        };

        TLImportedAddresses.prototype.deleteAddress = function(idx) {
            var importedAddressObject = this.archivedImportedAddresses[idx];
            this.archivedImportedAddresses.splice(idx, 1);
            if (this.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED) {
                this.appWallet.deleteImportedPrivateKey(importedAddressObject.getPositionInWalletArray());
            } else if (self.accountAddressType == TLWalletUtils.TLAccountType.IMPORTED_WATCH) {
                this.appWallet.deleteImportedWatchAddress(importedAddressObject.getPositionInWalletArray());
            }
            delete this.addressToPositionInWalletArrayDict[importedAddressObject.getPositionInWalletArray()];
            var tmpDict = angular.copy(this.addressToPositionInWalletArrayDict);
            for (var key in tmpDict) {
                var ia = this.addressToPositionInWalletArrayDict[key];
                if (ia.getPositionInWalletArray() > importedAddressObject.getPositionInWalletArray()) {
                    ia.setPositionInWalletArray(ia.getPositionInWalletArray()-1);
                    this.addressToPositionInWalletArrayDict[ia.getPositionInWalletArray()] = ia;
                }
            }
            if (importedAddressObject.getPositionInWalletArray() < this.addressToPositionInWalletArrayDict.length - 1) {
                delete this.addressToPositionInWalletArrayDict[this.addressToPositionInWalletArrayDict.length-1];
            }
            return true;
        };

        TLImportedAddresses.prototype.hasFetchedAddressesData = function() {
            for (var i = 0; i < this.importedAddresses.length; i++) {
                var importedAddressObject = this.importedAddresses[i];
                if (!importedAddressObject.hasFetchedAccountData()) {
                    return false
                }
            }
            return true;
        };

        return TLImportedAddresses;
    });
<|endoftext|>


<commit_before>/**
 * View for the PlugPro Menu
 * @module views/views/VideoViewView
 */

var VideoViewView = {

	initialize: function( options ){

	},

	/**
	* Renders the "video" view
	*/
	render: function(){

		this.activeTimeout;
		$('#playback-container').append("

");

		$('body').addClass('plugpro-video');

		$('body, #playback-container').on( "mousemove", this.makeActive.bind(this) );

		this.makeActive();
	},

	makeActive: function(){
		console.log("active");
		$('body').removeClass('inactive');
		if( this.activeTimeout ){
			clearTimeout( this.activeTimeout );
		}

		this.activeTimeout = setTimeout( this.makeInactive.bind(this), 2000 );
	},

	makeInactive: function(){
		console.log("inactive");
		$('body').addClass('inactive');
	}

};

module.exports = VideoViewView;<commit_msg>Add soundcloud artwork<commit_after>/**
 * View for the PlugPro Menu
 * @module views/views/VideoViewView
 */

var VideoViewView = {

	initialize: function( options ){

	},

	/**
	* Renders the "video" view
	*/
	render: function(){

		this.activeTimeout;
		$('#playback').append("

");

		$('body').addClass('plugpro-video');

		$('body, #playback-container').on( "mousemove", this.makeActive.bind(this) );

		API.on( API.ADVANCE, this.updateArtwork.bind(this) );

		this.makeActive();
		this.updateArtwork();
	},

	makeActive: function(){
		console.log("active");
		$('body').removeClass('inactive');
		if( this.activeTimeout ){
			clearTimeout( this.activeTimeout );
		}

		this.activeTimeout = setTimeout( this.makeInactive.bind(this), 2000 );
	},

	makeInactive: function(){
		console.log("inactive");
		$('body').addClass('inactive');
	},

	updateArtwork: function(){
		var songInfo = API.getMedia();
		console.log(songInfo);

		if( songInfo.image.indexOf('sndcdn') !== -1 ){
			var artFile = songInfo.image.replace( '-large', '-t500x500' );
			$('#video-cover').css({
				"background-image": "url('"+ artFile +"')"
			});
		}else{
			$('#video-cover').css({
				"background-image": "none"
			});
		}
	}

};

module.exports = VideoViewView;<|endoftext|>