<commit_before>'use strict'

import ViewState from './ViewState'
import BrowserRtcBufferFactory from '../BrowserRtcBufferFactory'
import YUVASurfaceShader from './YUVASurfaceShader'
import YUVSurfaceShader from './YUVSurfaceShader'
import Size from '../Size'

export default class Renderer {
  /**
   *
   * @param {BrowserSession} browserSession
   * @returns {Renderer}
   */
  static create (browserSession) {
    // create offscreen gl context
    const canvas = document.createElement('canvas')
    let gl = canvas.getContext('webgl2')
    if (!gl) {
      throw new Error('This browser doesn\'t support WebGL2!')
    }

    gl.clearColor(0, 0, 0, 0)
    const yuvaShader = YUVASurfaceShader.create(gl)
    const yuvShader = YUVSurfaceShader.create(gl)

    return new Renderer(browserSession, gl, yuvaShader, yuvShader, canvas)
  }

  /**
   * Use Renderer.create(..) instead.
   * @private
   * @param browserSession
   * @param gl
   * @param yuvaShader
   * @param yuvShader
   * @param canvas
   */
  constructor (browserSession, gl, yuvaShader, yuvShader, canvas) {
    this.browserSession = browserSession
    this.gl = gl
    this.yuvaShader = yuvaShader
    this.yuvShader = yuvShader
    this.canvas = canvas
  }

  /**
   * @param {BrowserSurface}browserSurface
   * @return Size
   */
  surfaceSize (browserSurface) {
    const grBuffer = browserSurface.grBuffer
    const bufferSize = this.bufferSize(grBuffer)
    if (browserSurface.bufferScale === 1) {
      return bufferSize
    }
    const surfaceWidth = bufferSize.w / browserSurface.bufferScale
    const surfaceHeight = bufferSize.h / browserSurface.bufferScale
    return Size.create(surfaceWidth, surfaceHeight)
  }

  /**
   * @param {GrBuffer}grBuffer
   * @return Size
   */
  bufferSize (grBuffer) {
    if (grBuffer === null) {
      return Size.create(0, 0)
    }
    // TODO we could check for null here in case we are dealing with a different kind of buffer
    const browserRtcDcBuffer = BrowserRtcBufferFactory.get(grBuffer)
    return browserRtcDcBuffer.geo
  }

  async requestRender (browserSurface) {
    const renderStart = Date.now()
    const grBuffer = browserSurface.grBuffer
    if (grBuffer === null) {
      browserSurface.renderState = null
      return
    }

    let viewState = browserSurface.renderState
    if (!viewState) {
      viewState = ViewState.create(this.gl)
      browserSurface.renderState = viewState
    }

    const browserRtcDcBuffer = BrowserRtcBufferFactory.get(grBuffer)
    const frameCallback = browserSurface.frameCallback

    browserSurface.frameCallback = null
    const views = browserSurface.browserSurfaceViews

    const syncSerial = await browserRtcDcBuffer.whenComplete()

    browserSurface.size = this.surfaceSize(browserSurface)
    browserSurface.bufferSize = browserRtcDcBuffer.geo

    // copy state into a separate object so we don't read a different state when our animation frame fires
    const state = {
      buffer: {
        type: browserRtcDcBuffer.type,
        pngContent: browserRtcDcBuffer.pngContent,
        yuvContent: browserRtcDcBuffer.yuvContent,
        yuvWidth: browserRtcDcBuffer.yuvWidth,
        yuvHeight: browserRtcDcBuffer.yuvHeight,
        alphaYuvContent: browserRtcDcBuffer.alphaYuvContent,
        alphaYuvWidth: browserRtcDcBuffer.alphaYuvWidth,
        alphaYuvHeight: browserRtcDcBuffer.alphaYuvHeight,
        geo: browserRtcDcBuffer.geo,
        resource: browserRtcDcBuffer.resource
      },

      syncSerial: syncSerial,
      renderStart: renderStart,
      frameCallback: frameCallback,
      views: views
    }

    window.requestAnimationFrame((frameTimeStamp) => {
      this._render(viewState, frameTimeStamp, state)
      this.browserSession.flush()
    })
  }

  _render (viewState, frameTimeStamp, state) {
    // update textures
    viewState.update(state)
    this._draw(frameTimeStamp, state, viewState)

    const renderDuration = Date.now() - state.renderStart
    state.buffer.resource.latency(state.syncSerial, renderDuration)
    if (state.frameCallback) {
      state.frameCallback.done(frameTimeStamp << 0)
    }
  }

  _draw (frameTimeStamp, state, renderState) {
    // paint the textures
    if (state.buffer.type === 'h264') {
      this._drawH264(state, renderState)
    } else { // if (browserRtcDcBuffer.type === 'png')
      this._drawPNG(state, renderState)
    }
  }

  _drawH264 (state, renderState) {
    const bufferSize = state.buffer.geo
    const viewPortUpdate = this.canvas.width !== bufferSize.w || this.canvas.height !== bufferSize.h
    this.canvas.width = bufferSize.w
    this.canvas.height = bufferSize.h

    if (state.buffer.alphaYuvContent != null) {
      this.yuvaShader.use()
      this.yuvaShader.draw(renderState.yTexture, renderState.uTexture, renderState.vTexture, renderState.alphaYTexture, bufferSize, viewPortUpdate)
    } else {
      this.yuvShader.use()
      this.yuvShader.draw(renderState.yTexture, renderState.uTexture, renderState.vTexture, bufferSize, viewPortUpdate)
    }

    // blit rendered texture from render canvas into view canvasses
    state.views.forEach((view) => {
      view.drawCanvas(this.canvas)
    })
  }

  _drawPNG (state, renderState) {
    state.views.forEach((view) => {
      view.drawPNG(renderState.pngImage)
    })
  }
}
<commit_msg>apply all screen updates in a single animationFrame<commit_after>'use strict'

import ViewState from './ViewState'
import BrowserRtcBufferFactory from '../BrowserRtcBufferFactory'
import YUVASurfaceShader from './YUVASurfaceShader'
import YUVSurfaceShader from './YUVSurfaceShader'
import Size from '../Size'

export default class Renderer {
  /**
   *
   * @param {BrowserSession} browserSession
   * @returns {Renderer}
   */
  static create (browserSession) {
    // create offscreen gl context
    const canvas = document.createElement('canvas')
    let gl = canvas.getContext('webgl2')
    if (!gl) {
      throw new Error('This browser doesn\'t support WebGL2!')
    }

    gl.clearColor(0, 0, 0, 0)
    const yuvaShader = YUVASurfaceShader.create(gl)
    const yuvShader = YUVSurfaceShader.create(gl)

    return new Renderer(browserSession, gl, yuvaShader, yuvShader, canvas)
  }

  /**
   * Use Renderer.create(..) instead.
   * @private
   * @param browserSession
   * @param gl
   * @param yuvaShader
   * @param yuvShader
   * @param canvas
   */
  constructor (browserSession, gl, yuvaShader, yuvShader, canvas) {
    this.browserSession = browserSession
    this.gl = gl
    this.yuvaShader = yuvaShader
    this.yuvShader = yuvShader
    this.canvas = canvas

    this._animationScheduled = false
    this._sceneUpdates = []
    this._updateScene = (timestamp) => {
      this._sceneUpdates.forEach(frameUpdate => { frameUpdate() })
      this.browserSession.flush()
      this._sceneUpdates = []
      this._animationScheduled = false
    }
  }

  /**
   * @param {BrowserSurface}browserSurface
   * @return Size
   */
  surfaceSize (browserSurface) {
    const grBuffer = browserSurface.grBuffer
    const bufferSize = this.bufferSize(grBuffer)
    if (browserSurface.bufferScale === 1) {
      return bufferSize
    }
    const surfaceWidth = bufferSize.w / browserSurface.bufferScale
    const surfaceHeight = bufferSize.h / browserSurface.bufferScale
    return Size.create(surfaceWidth, surfaceHeight)
  }

  /**
   * @param {GrBuffer}grBuffer
   * @return Size
   */
  bufferSize (grBuffer) {
    if (grBuffer === null) {
      return Size.create(0, 0)
    }
    // TODO we could check for null here in case we are dealing with a different kind of buffer
    const browserRtcDcBuffer = BrowserRtcBufferFactory.get(grBuffer)
    return browserRtcDcBuffer.geo
  }

  async requestRender (browserSurface) {
    const renderStart = Date.now()
    const grBuffer = browserSurface.grBuffer
    if (grBuffer === null) {
      browserSurface.renderState = null
      if (browserSurface.frameCallback) {
        browserSurface.frameCallback.done(Date.now() & 0x7fffffff)
      }
      this.browserSession.flush()
      return
    }

    let viewState = browserSurface.renderState
    if (!viewState) {
      viewState = ViewState.create(this.gl)
      browserSurface.renderState = viewState
    }

    const browserRtcDcBuffer = BrowserRtcBufferFactory.get(grBuffer)
    const frameCallback = browserSurface.frameCallback

    browserSurface.frameCallback = null
    const views = browserSurface.browserSurfaceViews

    const syncSerial = await browserRtcDcBuffer.whenComplete()

    browserSurface.size = this.surfaceSize(browserSurface)
    browserSurface.bufferSize = browserRtcDcBuffer.geo

    // copy state into a separate object so we don't read a different state when our animation frame fires
    const state = {
      buffer: {
        type: browserRtcDcBuffer.type,
        pngContent: browserRtcDcBuffer.pngContent,
        yuvContent: browserRtcDcBuffer.yuvContent,
        yuvWidth: browserRtcDcBuffer.yuvWidth,
        yuvHeight: browserRtcDcBuffer.yuvHeight,
        alphaYuvContent: browserRtcDcBuffer.alphaYuvContent,
        alphaYuvWidth: browserRtcDcBuffer.alphaYuvWidth,
        alphaYuvHeight: browserRtcDcBuffer.alphaYuvHeight,
        geo: browserRtcDcBuffer.geo,
        resource: browserRtcDcBuffer.resource
      },

      syncSerial: syncSerial,
      renderStart: renderStart,
      frameCallback: frameCallback,
      views: views
    }

    this._sceneUpdates.push(() => {
      this._render(viewState, Date.now() & 0x7fffffff, state)
    })
    if (!this._animationScheduled) {
      this._animationScheduled = true
      window.requestAnimationFrame(this._updateScene)
    }
  }

  _render (viewState, frameTimeStamp, state) {
    // update textures
    viewState.update(state)
    this._draw(frameTimeStamp, state, viewState)

    const renderDuration = Date.now() - state.renderStart
    state.buffer.resource.latency(state.syncSerial, renderDuration)
    if (state.frameCallback) {
      state.frameCallback.done(frameTimeStamp << 0)
    }
  }

  _draw (frameTimeStamp, state, renderState) {
    // paint the textures
    if (state.buffer.type === 'h264') {
      this._drawH264(state, renderState)
    } else { // if (browserRtcDcBuffer.type === 'png')
      this._drawPNG(state, renderState)
    }
  }

  _drawH264 (state, renderState) {
    const bufferSize = state.buffer.geo
    const viewPortUpdate = this.canvas.width !== bufferSize.w || this.canvas.height !== bufferSize.h
    this.canvas.width = bufferSize.w
    this.canvas.height = bufferSize.h

    if (state.buffer.alphaYuvContent != null) {
      this.yuvaShader.use()
      this.yuvaShader.draw(renderState.yTexture, renderState.uTexture, renderState.vTexture, renderState.alphaYTexture, bufferSize, viewPortUpdate)
    } else {
      this.yuvShader.use()
      this.yuvShader.draw(renderState.yTexture, renderState.uTexture, renderState.vTexture, bufferSize, viewPortUpdate)
    }

    // blit rendered texture from render canvas into view canvasses
    state.views.forEach((view) => {
      view.drawCanvas(this.canvas)
    })
  }

  _drawPNG (state, renderState) {
    state.views.forEach((view) => {
      view.drawPNG(renderState.pngImage)
    })
  }
}
<|endoftext|>


<commit_before>var Discord = require("discord.js");
var mysql = require("mysql");
var log = require("./logger.js");
var config =  require("./config");
var appConfig = config.appConfig;

var connection;
var commands = {};

commands.load = {
	alias: "load",
	description: "Load a command",
	hidden: true,
	action: (client, message, params) => {
		if(message.author.id == appConfig.ownerid) {
			try {
				commands[params[0]] = require("./commands/" + params[0] + ".js");
				client.sendMessage(message.channel, "Successfully loaded " + params[0]);
				log.info("Loaded " + params[0]);
			}
			catch(err) {
				client.sendMessage(message.channel, "Failed to load " + params[0]);
				log.error(err);
			}
		}
		else {
			client.sendMessage(message.channel, ":no_entry: **Permission Denied** :no_entry:");
		}
	}
};

commands.unload = {
	alias: "unload",
	description: "Unload a command",
	hidden: true,
	action:  (client, message, params) => {
		if(message.author.id == appConfig.ownerid) {
			try {
				delete commands[params[0]];
				delete require.cache[require.resolve("./commands/" + params[0] + ".js")];
				client.sendMessage(message.channel, "Successfully unloaded " + params[0]);
				log.info("Unloaded " + params[0]);
			}
			catch(err) {
				client.sendMessage(message.channel, "Failed to unload " + params[0]);
				log.error(err);
			}
		}
		else {
			client.sendMessage(message.channel, ":no_entry: **Permission Denied** :no_entry:");
		}
	}
};

commands.reload = {
	alias: "reload",
	description: "Reload a command",
	hidden: true,
	action: (client, message, params) => {
		if(message.author.id == appConfig.ownerid) {
			// commands.unload.action(client, message, params);
			// commands.load.action(client, message, params);
			try {
				delete commands[params[0]];
				delete require.cache[require.resolve("./commands/" + params[0] + ".js")];
				commands[params[0]] = require("./commands/" + params[0] + ".js");
				client.sendMessage(message.channel, "Successfully reloaded " + params[0]);
				log.info("Reloaded " + params[0]);
			}
			catch(err) {
				client.sendMessage(message.channel, "Failed to reload " + params[0]);
				log.error(err);
			}

		}
	}
};

function loadCommands() {
	var fs = require("fs");
	var files = fs.readdirSync("./commands");
	var loaded = 0;
	for(let file of files) {
		if(file.endsWith(".js")) {
			commands[file.slice(0, -3)] = require("./commands/" + file);
			loaded++;
		}
	}
	log.info("Loaded  " + loaded + " commands!");
}

function getParams(content) {
	var params = content.split(" ");
	if(content.indexOf(client.user.mention()) > -1) {
		params.shift();
	}
	params.shift();
	return params;
}

function db_connect() {
	connection = mysql.createConnection(appConfig.mysql);
	connection.connect(function(err) {
		if(err) {
			log.error(err);
			setTimeout(db_connect, 2000);
		}
	});
	connection.on("error", function(err) {
		if(err.code === "PROTOCOL_CONNECTION_LOST") {
			db_connect();
		}
		else {
			return log.error(err);
		}
	});
}

var client = new Discord.Client({autoReconnect: true});

client.on("message", (message) => {
	if(message.author.equals(client.user)) {
		var cmd = commands[message.content.split(" ")[0]];
		if(cmd != null) {
			cmd.action(client, message, getParams(message.content), config);
		}
	}
});

client.on("ready", () => {
	log.info("Logged in successfully");
	db_connect();
	log.info("Established connection to database");
	loadCommands();
});

process.on("SIGINT", () => process.exit(0));

client.loginWithToken(appConfig.apikey, (err) => { if(err) log.error(err); });
<commit_msg>Fixed message for load, unload, reload<commit_after>var Discord = require("discord.js");
var mysql = require("mysql");
var log = require("./logger.js");
var config =  require("./config");
var appConfig = config.appConfig;

var connection;
var commands = {};

commands.load = {
	alias: "load",
	description: "Load a command",
	hidden: true,
	action: (client, message, params) => {
		if(message.author.id == appConfig.ownerid) {
			try {
				commands[params[0]] = require("./commands/" + params[0] + ".js");
				client.updateMessage(message, "Successfully loaded " + params[0]);
				log.info("Loaded " + params[0]);
			}
			catch(err) {
				client.updateMessage(message, "Failed to load " + params[0]);
				log.error(err);
			}
		}
		else {
			client.updateMessage(message, ":no_entry: **Permission Denied** :no_entry:");
		}
	}
};

commands.unload = {
	alias: "unload",
	description: "Unload a command",
	hidden: true,
	action:  (client, message, params) => {
		if(message.author.id == appConfig.ownerid) {
			try {
				delete commands[params[0]];
				delete require.cache[require.resolve("./commands/" + params[0] + ".js")];
				client.updateMessage(message, "Successfully unloaded " + params[0]);
				log.info("Unloaded " + params[0]);
			}
			catch(err) {
				client.updateMessage(message, "Failed to unload " + params[0]);
				log.error(err);
			}
		}
		else {
			client.updateMessage(message, ":no_entry: **Permission Denied** :no_entry:");
		}
	}
};

commands.reload = {
	alias: "reload",
	description: "Reload a command",
	hidden: true,
	action: (client, message, params) => {
		if(message.author.id == appConfig.ownerid) {
			// commands.unload.action(client, message, params);
			// commands.load.action(client, message, params);
			try {
				delete commands[params[0]];
				delete require.cache[require.resolve("./commands/" + params[0] + ".js")];
				commands[params[0]] = require("./commands/" + params[0] + ".js");
				client.updateMessage(message, "Successfully reloaded " + params[0]);
				log.info("Reloaded " + params[0]);
			}
			catch(err) {
				client.updateMessage(message, "Failed to reload " + params[0]);
				log.error(err);
			}

		}
	}
};

function loadCommands() {
	var fs = require("fs");
	var files = fs.readdirSync("./commands");
	var loaded = 0;
	for(let file of files) {
		if(file.endsWith(".js")) {
			commands[file.slice(0, -3)] = require("./commands/" + file);
			loaded++;
		}
	}
	log.info("Loaded  " + loaded + " commands!");
}

function getParams(content) {
	var params = content.split(" ");
	if(content.indexOf(client.user.mention()) > -1) {
		params.shift();
	}
	params.shift();
	return params;
}

function db_connect() {
	connection = mysql.createConnection(appConfig.mysql);
	connection.connect(function(err) {
		if(err) {
			log.error(err);
			setTimeout(db_connect, 2000);
		}
	});
	connection.on("error", function(err) {
		if(err.code === "PROTOCOL_CONNECTION_LOST") {
			db_connect();
		}
		else {
			return log.error(err);
		}
	});
}

var client = new Discord.Client({autoReconnect: true});

client.on("message", (message) => {
	if(message.author.equals(client.user)) {
		var cmd = commands[message.content.split(" ")[0]];
		if(cmd != null) {
			cmd.action(client, message, getParams(message.content), config);
		}
	}
});

client.on("ready", () => {
	log.info("Logged in successfully");
	db_connect();
	log.info("Established connection to database");
	loadCommands();
});

process.on("SIGINT", () => process.exit(0));

client.loginWithToken(appConfig.apikey, (err) => { if(err) log.error(err); });
<|endoftext|>


<commit_before>import {
    head,
    last,
    includes,
    union,
    difference,
    indexOf,
    map,
    shuffle
} from 'lodash';

export default {
    state: {
        songs: [],
        current: null,
    },

    init() {
        // We don't have anything to do here yet.
        // How about another song then?
        //
        // LITTLE WING
        // -- by Jimi Fucking Hendrix
        //
        // Well she's walking
        // Through the clouds
        // With a circus mind
        // That's running wild
        // Butterflies and zebras and moonbeams and fairytales
        // That's all she ever thinks about
        // Riding with the wind
        //
        // When I'm sad
        // She comes to me
        // With a thousand smiles
        // She gives to me free
        // It's alright she said
        // It's alright
        // Take anything you want from me
        // Anything...
    },

    /**
     * All queued songs.
     *
     * @return {Array.<Object>}
     */
    get all() {
        return this.state.songs;
    },

    /**
     * The first song in the queue.
     *
     * @return {?Object}
     */
    get first() {
        return head(this.state.songs);
    },

    /**
     * The last song in the queue.
     *
     * @return {?Object}
     */
    get last() {
        return last(this.state.songs);
    },

    /**
     * Determine if the queue contains a song.
     *
     * @param  {Object} song
     *
     * @return {Boolean}
     */
    contains(song) {
        return includes(this.all, song);
    },

    /**
     * Add a list of songs to the end of the current queue,
     * or replace the current queue as a whole if `replace` is true.
     *
     * @param {Object|Array.<Object>}   songs   The song, or an array of songs
     * @param {Boolean}                 replace Whether to replace the current queue
     * @param {Boolean}                 toTop   Whether to prepend or append to the queue
     */
    queue(songs, replace = false, toTop = false) {
        songs = [].concat(songs);

        if (replace) {
            this.state.songs = songs;
        } else {
            if (toTop) {
                this.state.songs = union(songs, this.state.songs);
            } else {
                this.state.songs = union(this.state.songs, songs);
            }
        }
    },

    /**
     * Queue song(s) to after the current song.
     *
     * @param  {Array.<Object>|Object} songs
     */
    queueAfterCurrent(songs) {
        songs = [].concat(songs);

        if (!this.state.current || !this.state.songs.length) {
            return this.queue(songs);
        }

        const head = this.state.songs.splice(0, this.indexOf(this.state.current) + 1);
        this.state.songs = head.concat(songs, this.state.songs);
    },

    /**
     * Unqueue a song, or several songs at once.
     *
     * @param  {Object|String|Array.<Object>} songs The song(s) to unqueue
     */
    unqueue(songs) {
        this.state.songs = difference(this.state.songs, [].concat(songs));
    },

    /**
     * Move some songs to after a target.
     *
     * @param  {Array.<Object>} songs  Songs to move
     * @param  {Object}         target The target song object
     */
    move(songs, target) {
        const $targetIndex = this.indexOf(target);

        songs.forEach(song => {
            this.state.songs.splice(this.indexOf(song), 1);
            this.state.songs.splice($targetIndex, 0, song);
        });
    },

    /**
     * Clear the current queue.
     *
     * @param {?Function} cb The function to execute after clearing
     */
    clear(cb = null) {
        this.state.songs = [];
        this.state.current = null;

        if (cb) {
            cb();
        }
    },

    /**
     * Get index of a song in the queue.
     *
     * @param  {Object} song
     *
     * @return {?Integer}
     */
    indexOf(song) {
        return indexOf(this.state.songs, song);
    },

    /**
     * The next song in queue.
     *
     * @return {?Object}
     */
    get next() {
        if (!this.current) {
            return first(this.state.songs);
        }

        const idx = map(this.state.songs, 'id').indexOf(this.current.id) + 1;

        return idx >= this.state.songs.length ? null : this.state.songs[idx];
    },

    /**
     * The previous song in queue.
     *
     * @return {?Object}
     */
    get previous() {
        if (!this.current) {
            return last(this.state.songs);
        }

        const idx = map(this.state.songs, 'id').indexOf(this.current.id) - 1;

        return idx < 0 ? null : this.state.songs[idx];
    },

    /**
     * The current song.
     *
     * @return {Object}
     */
    get current() {
        return this.state.current;
    },

    /**
     * Set a song as the current queued song.
     *
     * @param  {Object} song
     *
     * @return {Object} The queued song.
     */
    set current(song) {
        this.state.current = song;

        return this.current;
    },

    /**
     * Shuffle the queue.
     *
     * @return {Array.<Object>} The shuffled array of song objects
     */
    shuffle() {
        return (this.state.songs = shuffle(this.state.songs));
    },
};
<commit_msg>Fix #292<commit_after>import {
    head,
    last,
    includes,
    union,
    difference,
    map,
    shuffle
} from 'lodash';

export default {
    state: {
        songs: [],
        current: null,
    },

    init() {
        // We don't have anything to do here yet.
        // How about another song then?
        //
        // LITTLE WING
        // -- by Jimi Fucking Hendrix
        //
        // Well she's walking
        // Through the clouds
        // With a circus mind
        // That's running wild
        // Butterflies and zebras and moonbeams and fairytales
        // That's all she ever thinks about
        // Riding with the wind
        //
        // When I'm sad
        // She comes to me
        // With a thousand smiles
        // She gives to me free
        // It's alright she said
        // It's alright
        // Take anything you want from me
        // Anything...
    },

    /**
     * All queued songs.
     *
     * @return {Array.<Object>}
     */
    get all() {
        return this.state.songs;
    },

    /**
     * The first song in the queue.
     *
     * @return {?Object}
     */
    get first() {
        return head(this.state.songs);
    },

    /**
     * The last song in the queue.
     *
     * @return {?Object}
     */
    get last() {
        return last(this.state.songs);
    },

    /**
     * Determine if the queue contains a song.
     *
     * @param  {Object} song
     *
     * @return {Boolean}
     */
    contains(song) {
        return includes(this.all, song);
    },

    /**
     * Add a list of songs to the end of the current queue,
     * or replace the current queue as a whole if `replace` is true.
     *
     * @param {Object|Array.<Object>}   songs   The song, or an array of songs
     * @param {Boolean}                 replace Whether to replace the current queue
     * @param {Boolean}                 toTop   Whether to prepend or append to the queue
     */
    queue(songs, replace = false, toTop = false) {
        songs = [].concat(songs);

        if (replace) {
            this.state.songs = songs;
        } else {
            if (toTop) {
                this.state.songs = union(songs, this.state.songs);
            } else {
                this.state.songs = union(this.state.songs, songs);
            }
        }
    },

    /**
     * Queue song(s) to after the current song.
     *
     * @param  {Array.<Object>|Object} songs
     */
    queueAfterCurrent(songs) {
        songs = [].concat(songs);

        if (!this.state.current || !this.state.songs.length) {
            return this.queue(songs);
        }

        const head = this.state.songs.splice(0, this.indexOf(this.state.current) + 1);
        this.state.songs = head.concat(songs, this.state.songs);
    },

    /**
     * Unqueue a song, or several songs at once.
     *
     * @param  {Object|String|Array.<Object>} songs The song(s) to unqueue
     */
    unqueue(songs) {
        this.state.songs = difference(this.state.songs, [].concat(songs));
    },

    /**
     * Move some songs to after a target.
     *
     * @param  {Array.<Object>} songs  Songs to move
     * @param  {Object}         target The target song object
     */
    move(songs, target) {
        const $targetIndex = this.indexOf(target);

        songs.forEach(song => {
            this.state.songs.splice(this.indexOf(song), 1);
            this.state.songs.splice($targetIndex, 0, song);
        });
    },

    /**
     * Clear the current queue.
     *
     * @param {?Function} cb The function to execute after clearing
     */
    clear(cb = null) {
        this.state.songs = [];
        this.state.current = null;

        if (cb) {
            cb();
        }
    },

    /**
     * Get index of a song in the queue.
     *
     * @param  {Object} song
     *
     * @return {?Integer}
     */
    indexOf(song) {
        return this.state.songs.indexOf(song);
    },

    /**
     * The next song in queue.
     *
     * @return {?Object}
     */
    get next() {
        if (!this.current) {
            return first(this.state.songs);
        }

        const idx = map(this.state.songs, 'id').indexOf(this.current.id) + 1;

        return idx >= this.state.songs.length ? null : this.state.songs[idx];
    },

    /**
     * The previous song in queue.
     *
     * @return {?Object}
     */
    get previous() {
        if (!this.current) {
            return last(this.state.songs);
        }

        const idx = map(this.state.songs, 'id').indexOf(this.current.id) - 1;

        return idx < 0 ? null : this.state.songs[idx];
    },

    /**
     * The current song.
     *
     * @return {Object}
     */
    get current() {
        return this.state.current;
    },

    /**
     * Set a song as the current queued song.
     *
     * @param  {Object} song
     *
     * @return {Object} The queued song.
     */
    set current(song) {
        this.state.current = song;

        return this.current;
    },

    /**
     * Shuffle the queue.
     *
     * @return {Array.<Object>} The shuffled array of song objects
     */
    shuffle() {
        return (this.state.songs = shuffle(this.state.songs));
    },
};
<|endoftext|>


<commit_before>angular.module('starter.controllers', ['starter.factory', 'hljs', 'starter.utils'])

  .controller('AppCtrl', function ($scope, $storageServices) {
    $scope.badgePoints = 0;
    $scope.$on('$ionicView.enter', function () {
      $storageServices.get('badgePoints', function (points) {
        $scope.badgePoints = points;
      });
    });
  })

  .controller('AboutCtrl', function ($scope, $analytics) {
    $analytics.trackView('About Ctrl');
    $scope.isApp = window.cordova !== undefined;
  })

  .controller('MainCtrl', function ($scope, $ionicModal, $storageServices, $analytics) {
    $scope.currentModal = null;
    $scope.subtopic = '';
    $scope.doneItems = [];

    $scope.openTodoModal = function (subtopic) {
      $scope.subtopic = subtopic;
      $scope.todoLists = [];

      $analytics.trackView('todo ' + subtopic);

      var todoLists = TODO_LISTS[subtopic]['basic'];
      var items = {};
      $storageServices.get($scope.subtopic, function (result) {
        if (result !== undefined) {
          try {
            items = JSON.parse(result);
          } catch (err) {
            console.log(err)
          }
        }
        angular.forEach(items.items, function (item, itemKey) {
          angular.forEach(todoLists, function (todoList, index) {
            if(todoList.id === itemKey) {
              $scope.doneItems.push({
                id: todoList.id,
                title: todoList.title
              });
              todoLists[index] = {};
            }
          });
        });
        $scope.todoLists = todoLists;
      });

      $ionicModal.fromTemplateUrl('templates/modal/todo.html', {
        id: subtopic,
        scope: $scope,
        animation: 'slide-in-up'
      }).then(function (modal) {
        modal.show();
        $scope.currentModal = modal;
      });
    };

    $scope.addTodo = function (item) {
      var items = {
        items: {}
      };
      $storageServices.get($scope.subtopic, function (result) {
        if (result !== undefined) {
          try {
            items = JSON.parse(result);
          } catch (err) {
            console.log(err)
          }
        }
      });

      items.items[item.id] = item.title;
      $scope.doneItems.push({
        id: item.id,
        title: item.title
      });

      $storageServices.set($scope.subtopic, JSON.stringify(items));
      $scope.todoLists.splice($scope.todoLists.indexOf(item), 1);
    };

    $scope.closeSpecialModal = function () {
      $scope.currentModal.hide();
    };

    $storageServices.get('isFirstTime', function (value) {
      if (value !== 'false') {
        $ionicModal.fromTemplateUrl('templates/intro/intro.html', {
          id: 'intro1',
          scope: $scope,
          animation: 'slide-in-up'
        }).then(function (modal) {
          modal.show();
          $scope.modal = modal;
        });

        $scope.$on('modal.hidden', function () {
          $storageServices.set('isFirstTime', 'false');
        });
      }
    });
  })

  .controller('FeedbackCtrl', function ($scope, $http, $cordovaEmailComposer) {
    $scope.issues = [];
    $http.get('https://api.github.com/repos/phodal/growth/issues').then(function (response) {
      $scope.issues = response.data;
    });

    $scope.OpenIssue = function (url) {
      window.open(url, '_system', 'location=yes');
    };

    if (window.cordova) {
      $scope.sendMail = function () {
        $cordovaEmailComposer.isAvailable().then(function () {
        }, function () {
        });
        var email = {to: 'h@phodal.com', subject: '关于《Growth Ren》', body: '', isHtml: true};
        $cordovaEmailComposer.open(email).then(null, function () {
        });
      }
    }
  })

  .controller('ArticleCtrl', function ($scope, $sce, $stateParams, $http, $ionicLoading, marked, $filter, $analytics) {
    $analytics.trackView('Article Detail');

    $ionicLoading.show({
      animation: 'fade-in',
      template: 'Loading...'
    });
    $http({
      method: 'GET',
      url: 'article/' + $stateParams.slug + '.md'
    }).success(function (response) {
      $ionicLoading.hide();
      $scope.EditArticle = function () {
        window.open('https://github.com/phodal/growth/edit/master/www/article/' + $stateParams.slug + '.md', '_system', 'location=yes');
      };
      $scope.title = $filter('filter')(AllArticle, {"slug": $stateParams.slug})[0].title;
      $scope.htmlContent = $sce.trustAsHtml(marked(response))
    }).error(function (data, status) {
      alert(data + status);
    });
  })

  .controller('ArticleListCtrl', function ($scope, $analytics) {
    $analytics.trackView('Article List');
    $scope.articles = AllArticle;
  });
<commit_msg>a quick hack fix<commit_after>angular.module('starter.controllers', ['starter.factory', 'hljs', 'starter.utils'])

  .controller('AppCtrl', function ($scope, $storageServices) {
    $scope.badgePoints = 0;
    $scope.$on('$ionicView.enter', function () {
      $storageServices.get('badgePoints', function (points) {
        $scope.badgePoints = points;
      });
    });
  })

  .controller('AboutCtrl', function ($scope, $analytics) {
    $analytics.trackView('About Ctrl');
    $scope.isApp = window.cordova !== undefined;
  })

  .controller('MainCtrl', function ($scope, $ionicModal, $storageServices, $analytics) {
    $scope.currentModal = null;
    $scope.subtopic = '';
    $scope.allDoneItems = {
      "hello": [],
      "env": [],
      "front": [],
      "mvc": []
    };

    $scope.openTodoModal = function (subtopic) {
      $scope.subtopic = subtopic;
      $scope.todoLists = [];

      $analytics.trackView('todo ' + subtopic);

      var todoLists = TODO_LISTS[subtopic]['basic'];
      var items = {};
      $storageServices.get($scope.subtopic, function (result) {
        if (result !== undefined) {
          try {
            items = JSON.parse(result);
          } catch (err) {
            console.log(err)
          }
        }
        angular.forEach(items.items, function (item, itemKey) {
          angular.forEach(todoLists, function (todoList, index) {
            if(todoList.id === itemKey) {
              $scope.allDoneItems[subtopic].push({
                id: todoList.id,
                title: todoList.title
              });
              todoLists[index] = {};
            }
          });
        });
      });
      console.log($scope.allDoneItems[subtopic]);
      $scope.doneItems = $scope.allDoneItems[subtopic];
      $scope.todoLists = todoLists;

      $ionicModal.fromTemplateUrl('templates/modal/todo.html', {
        id: subtopic,
        scope: $scope,
        animation: 'slide-in-up'
      }).then(function (modal) {
        modal.show();
        $scope.currentModal = modal;
      });
    };

    $scope.addTodo = function (item) {
      var items = {
        items: {}
      };
      $storageServices.get($scope.subtopic, function (result) {
        if (result !== undefined) {
          try {
            items = JSON.parse(result);
          } catch (err) {
            console.log(err)
          }
        }
      });

      items.items[item.id] = item.title;
      $scope.doneItems.push({
        id: item.id,
        title: item.title
      });

      $storageServices.set($scope.subtopic, JSON.stringify(items));
      $scope.todoLists.splice($scope.todoLists.indexOf(item), 1);
    };

    $scope.closeSpecialModal = function () {
      $scope.currentModal.hide();
    };

    $storageServices.get('isFirstTime', function (value) {
      if (value !== 'false') {
        $ionicModal.fromTemplateUrl('templates/intro/intro.html', {
          id: 'intro1',
          scope: $scope,
          animation: 'slide-in-up'
        }).then(function (modal) {
          modal.show();
          $scope.modal = modal;
        });

        $scope.$on('modal.hidden', function () {
          $storageServices.set('isFirstTime', 'false');
        });
      }
    });
  })

  .controller('FeedbackCtrl', function ($scope, $http, $cordovaEmailComposer) {
    $scope.issues = [];
    $http.get('https://api.github.com/repos/phodal/growth/issues').then(function (response) {
      $scope.issues = response.data;
    });

    $scope.OpenIssue = function (url) {
      window.open(url, '_system', 'location=yes');
    };

    if (window.cordova) {
      $scope.sendMail = function () {
        $cordovaEmailComposer.isAvailable().then(function () {
        }, function () {
        });
        var email = {to: 'h@phodal.com', subject: '关于《Growth Ren》', body: '', isHtml: true};
        $cordovaEmailComposer.open(email).then(null, function () {
        });
      }
    }
  })

  .controller('ArticleCtrl', function ($scope, $sce, $stateParams, $http, $ionicLoading, marked, $filter, $analytics) {
    $analytics.trackView('Article Detail');

    $ionicLoading.show({
      animation: 'fade-in',
      template: 'Loading...'
    });
    $http({
      method: 'GET',
      url: 'article/' + $stateParams.slug + '.md'
    }).success(function (response) {
      $ionicLoading.hide();
      $scope.EditArticle = function () {
        window.open('https://github.com/phodal/growth/edit/master/www/article/' + $stateParams.slug + '.md', '_system', 'location=yes');
      };
      $scope.title = $filter('filter')(AllArticle, {"slug": $stateParams.slug})[0].title;
      $scope.htmlContent = $sce.trustAsHtml(marked(response))
    }).error(function (data, status) {
      alert(data + status);
    });
  })

  .controller('ArticleListCtrl', function ($scope, $analytics) {
    $analytics.trackView('Article List');
    $scope.articles = AllArticle;
  });
<|endoftext|>


<commit_before>angular.module('sticky', [])

.directive('sticky', function(){
	return {
		restrict: 'A',
		scope: {
			offset: '@',
		},
		link: function($scope, $elem, $attrs){
			var offsetTop = $scope.offset || 0,
				$window = angular.element(window),
				doc = document.documentElement,
				initialPositionStyle = $elem.css('position'),
				stickyLine,
				scrollTop;

			// Set the top offset
			//
			$elem.css('top', offsetTop+'px');

			// Get the sticky line
			//
			function setInitial(){
				$elem.css('position', initialPositionStyle);
				stickyLine = $elem[0].offsetTop - offsetTop;
				checkSticky();
			}

			// Check if the window has passed the sticky line
			//
			function checkSticky(){
				scrollTop = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);

				if ( scrollTop >= stickyLine ){
					$elem.css('position', 'fixed');
				} else {
					$elem.css('position', initialPositionStyle);
				}
			}

			// Attach our listeners
			//
			$window.on('scroll', checkSticky);
			$window.on('resize', setInitial);

			setInitial();
		},
	};
})<commit_msg>Wrapped in  to avoid element's position not being defined on link<commit_after>angular.module('sticky', [])

.directive('sticky', function($timeout){
	return {
		restrict: 'A',
		scope: {
			offset: '@',
		},
		link: function($scope, $elem, $attrs){
			$timeout(function(){
				var offsetTop = $scope.offset || 0,
					$window = angular.element(window),
					doc = document.documentElement,
					initialPositionStyle = $elem.css('position'),
					stickyLine,
					scrollTop;

				// Set the top offset
				//
				$elem.css('top', offsetTop+'px');

				console.log(initialPositionStyle);
				// Get the sticky line
				//
				function setInitial(){
					console.log($elem[0].offsetTop);
					stickyLine = $elem[0].offsetTop - offsetTop;
					checkSticky();
				}

				// Check if the window has passed the sticky line
				//
				function checkSticky(){
					scrollTop = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);

					if ( scrollTop >= stickyLine ){
						$elem.css('position', 'fixed');
					} else {
						$elem.css('position', initialPositionStyle);
					}
				}

				// Attach our listeners
				//
				$window.on('scroll', checkSticky);
				$window.on('resize', setInitial);

				setInitial();
			});
		},
	};
})<|endoftext|>


<commit_before>var module = angular.module('starter.controllers', [])

// A simple controller that fetches a list of data from a service
// TODO : Group together Queryer services
module.controller('SearchCtrl', function($scope, Queryer, ReplacePrefixesService, DatasetStore) {

  // "Pets" is a service returning mock data (services.js)
  // $scope.pets = PetService.all();

  $scope.querySearch = function () {

    // $scope.pets = PetService.all();
    // console.log(angular.lowercase(this.queryTerm));

    console.log(DatasetStore.current[0]);
    Queryer.setQuery(DatasetStore.current[0],'search_ns', 'json-ld', {"parm1" : this.queryTerm});

    Queryer.getJson().success(function(data) {
    // Switch the prefix in @id with the complete url from @context
    ReplacePrefixesService.replacePrefix(data["@context"], data["@graph"]);
    $scope.searchResultGraph = data["@graph"];
    })
  };

});

module.controller('DescribeCtrl', function($scope, $stateParams, Queryer, ProcessGraph) {
  $scope.uri = $stateParams.uri;
  var endpoint = $stateParams.endpoint;
  // Temporairement json hardcoder
  /*Queryer.setQuery($stateParams.endpoint,'describe2', 'json-ld', {"uri" : $scope.uri});*/
  console.log($scope.uri);
  console.log(endpoint);
  Queryer.setQuery( endpoint ,'describe2', 'json-ld', {"uri" : $scope.uri});
  Queryer.getJson().success(function(data){
    var idList=ProcessGraph.graph(data);
    var main = idList[$stateParams.uri]

    $scope.title = main["rdfs:label"]
    $scope.obodef = main["obolibrary:IAO_0000115"]

    $scope.obosubclasses = []
    _.each(main["rdfs:subClassOf"], function(elem) {
      $scope.obosubclasses.push(idList[elem["@id"]]);
    });

  });

  /*Queryer.setQuery('pubmed','describe','json-ld', {"uri" : $scope.uri});*/
  /*Queryer.getJson().success(function(data){*/
  /*console.log(data);*/
  /*var idList=ProcessGraph.graph(data);*/
  /*var main = idList[$stateParams.uri]*/

  /*$scope.title = main["rdfs:label"]*/
  /*$scope.pmabstract = idList[main["dcterms:abstract"]["@id"]]["pubmed_vocabulary:abstract_text"]*/

  /*$scope.pmauthors = []*/
  /*_.each(main["pubmed_vocabulary:author"], function(elem) {*/
  /*$scope.pmauthors.push(idList[elem["@id"]]);*/
  /*});*/

  /*});*/
});

// Event controller to toggle side panels with buttons
module.controller('MainCtrl', function($scope, DatasetStore) {

  $scope.toggleLeftPanel = function() {
    $scope.sideMenuController.toggleLeft();
  };
  $scope.toggleRightPanel = function() {
    $scope.sideMenuController.toggleRight();
  };

  $scope.setHeaderImg = function () {
    $scope.headerImg = DatasetStore.all[DatasetStore.current].foafDepiction;
    console.log(DatasetStore.all[DatasetStore.current].foafDepiction);
  };

  $scope.setHeaderImg();

});

// LeftMenuCtrl:
//
module.controller('LeftMenuCtrl',function($scope, DatasetStore, DatasetService, ReplacePrefixesService){

  $scope.databases = [];

  DatasetService.listDB().getJson().success(function(data) {

    ReplacePrefixesService.replacePrefix(data["@context"], data["@graph"]);

    for (var i in data["@graph"]){
      if(data["@graph"][i]["dc:title"] != "namespace:endpoints_mother"){

	var id = data["@graph"][i]["@id"].split(/:/).pop();
	console.log(id);
        $scope.databases.push({
	  id: id,
          title: data["@graph"][i]["dc:title"],
          tripleCount: data["@graph"][i]["bm:bio2rdf_vocabulary:triple_count"],
          foafDepiction: data["@graph"][i]['http://xmlns.com/foaf/0.1/depiction']['@id']
        });

        DatasetStore.all[id] = {
          title: data["@graph"][i]["dc:title"],
          tripleCount: data["@graph"][i]["bm:bio2rdf_vocabulary:triple_count"],
          foafDepiction: data["@graph"][i]['http://xmlns.com/foaf/0.1/depiction']['@id'],
	  endpoint: data["@graph"][i]['bm:bio2rdf_vocabulary:endpoint']['@id']
	};

      } else {
        $scope.header = data["@graph"][i];
      }
    }

    console.log(DatasetStore);

  });

  // Put it somewhere else ?
  $scope.onItemHold = function(item) {
    alert("HOLD ON");
  };

  $scope.changeCurrentDatabase = function(dbId) {
    DatasetStore.current = [dbId];
    $scope.setHeaderImg();
    console.log(DatasetStore.current[0]);
  };

});

module.directive('myOnHold', function($ionicGesture) {
  return {
    restrict: 'A',
    link: function($scope, $element, $attr) {
      $ionicGesture.on('hold', function(e) {
        $scope.$eval($attr.myOnHold);
      }, $element);
    }
  }
});

// A simple controller that shows a tapped item's data
module.controller('PetDetailCtrl', function($scope, $stateParams, PetService) {
  // "Pets" is a service returning mock data (services.js)
  $scope.pet = PetService.get($stateParams.petId);
});

<commit_msg>reroute to search when selecting a DB<commit_after>var module = angular.module('starter.controllers', [])

// A simple controller that fetches a list of data from a service
// TODO : Group together Queryer services
module.controller('SearchCtrl', function($scope, Queryer, ReplacePrefixesService, DatasetStore) {

  $scope.querySearch = function () {

    Queryer.setQuery(DatasetStore.current[0],'search_ns', 'json-ld', {"parm1" : this.queryTerm});

    Queryer.getJson().success(function(data) {

      // Switch the prefix in @id with the complete url from @context
      ReplacePrefixesService.replacePrefix(data["@context"], data["@graph"]);
      $scope.searchResultGraph = data["@graph"];
    })

  };

});

module.controller('DescribeCtrl', function($scope, $stateParams, Queryer, ProcessGraph) {
  $scope.uri = $stateParams.uri;
  var endpoint = $stateParams.endpoint;
  // Temporairement json hardcoder
  /*Queryer.setQuery($stateParams.endpoint,'describe2', 'json-ld', {"uri" : $scope.uri});*/
  console.log($scope.uri);
  console.log(endpoint);
  Queryer.setQuery( endpoint ,'describe2', 'json-ld', {"uri" : $scope.uri});
  Queryer.getJson().success(function(data){
    var idList=ProcessGraph.graph(data);
    var main = idList[$stateParams.uri]

    $scope.title = main["rdfs:label"]
    $scope.obodef = main["obolibrary:IAO_0000115"]

    $scope.obosubclasses = []
    _.each(main["rdfs:subClassOf"], function(elem) {
      $scope.obosubclasses.push(idList[elem["@id"]]);
    });

  });

  /*Queryer.setQuery('pubmed','describe','json-ld', {"uri" : $scope.uri});*/
  /*Queryer.getJson().success(function(data){*/
  /*console.log(data);*/
  /*var idList=ProcessGraph.graph(data);*/
  /*var main = idList[$stateParams.uri]*/

  /*$scope.title = main["rdfs:label"]*/
  /*$scope.pmabstract = idList[main["dcterms:abstract"]["@id"]]["pubmed_vocabulary:abstract_text"]*/

  /*$scope.pmauthors = []*/
  /*_.each(main["pubmed_vocabulary:author"], function(elem) {*/
  /*$scope.pmauthors.push(idList[elem["@id"]]);*/
  /*});*/

  /*});*/
});

// Event controller to toggle side panels with buttons
module.controller('MainCtrl', function($scope, DatasetStore) {

  $scope.toggleLeftPanel = function() {
    $scope.sideMenuController.toggleLeft();
  };
  $scope.toggleRightPanel = function() {
    $scope.sideMenuController.toggleRight();
  };

  $scope.setHeaderImg = function () {
    $scope.headerImg = DatasetStore.all[DatasetStore.current].foafDepiction;
    console.log(DatasetStore.all[DatasetStore.current].foafDepiction);
  };

  $scope.setHeaderImg();

});

// LeftMenuCtrl:
module.controller('LeftMenuCtrl',function($scope, $location, DatasetStore, DatasetService, ReplacePrefixesService){

  $scope.databases = [];

  DatasetService.listDB().getJson().success(function(data) {

    ReplacePrefixesService.replacePrefix(data["@context"], data["@graph"]);

    for (var i in data["@graph"]){

      if(data["@graph"][i]["dc:title"] != "namespace:endpoints_mother"){

	var id = data["@graph"][i]["@id"].split(/:/).pop();

        $scope.databases.push({
	  id: id,
          title: data["@graph"][i]["dc:title"],
          tripleCount: data["@graph"][i]["bm:bio2rdf_vocabulary:triple_count"],
          foafDepiction: data["@graph"][i]['http://xmlns.com/foaf/0.1/depiction']['@id']
        });

        DatasetStore.all[id] = {
          title: data["@graph"][i]["dc:title"],
          tripleCount: data["@graph"][i]["bm:bio2rdf_vocabulary:triple_count"],
          foafDepiction: data["@graph"][i]['http://xmlns.com/foaf/0.1/depiction']['@id'],
	  endpoint: data["@graph"][i]['bm:bio2rdf_vocabulary:endpoint']['@id']
	};

      } else {
        $scope.header = data["@graph"][i];
      }
    }

    console.log(DatasetStore);

  });

  // Put it somewhere else ?
  $scope.onItemHold = function(item) {
    alert("HOLD ON");
  };

  $scope.changeCurrentDatabase = function(dbId) {
    DatasetStore.current = [dbId];
    $scope.setHeaderImg();
    console.log(DatasetStore.current[0]);
    $location.path("/#/tab/search");
  };

});

module.directive('myOnHold', function($ionicGesture) {
  return {
    restrict: 'A',
    link: function($scope, $element, $attr) {
      $ionicGesture.on('hold', function(e) {
        $scope.$eval($attr.myOnHold);
      }, $element);
    }
  }
});

// A simple controller that shows a tapped item's data
module.controller('PetDetailCtrl', function($scope, $stateParams, PetService) {
  // "Pets" is a service returning mock data (services.js)
  $scope.pet = PetService.get($stateParams.petId);
});

<|endoftext|>


<commit_before>var appControllers = angular.module('appControllers', ['appProviders', 'appDirectives']);

/*
 *  HELPER
 */
var nearInfoAlert = "Ihr Ziel ist in unmittelbarer N%E4he%2C m%F6chten sie nun Informationen dazu erhalten%3F";

/*
 *  CONTROLLER
 */
appControllers.controller('PoiCtrl', function ($rootScope, $scope, $location, $routeParams, notification, media, device) {

    $rootScope.poi = $rootScope.pois[$routeParams.stationID];
    $rootScope.stationID = $routeParams.stationID;

    $scope.getMargin = function(){
        if(device.width >= 500){
            return {margin: '50px'};
        }
    }

    $scope.getImageWidth = function(){
        if(device.width >= 500){
            return { width: '460px'};
        }
        return { width: '230px'};
    }

    $scope.stopAndRedirect = function(path){
        $location.path(path);
        media.stop($scope.media);
        show = false;
    }

    $scope.mediaPlay = function() {
        media.play($rootScope.poi.audio)
    }

    $scope.mediaStop = function() {
        media.stop($scope.media)
        show = false;
    }

    $scope.showButton = function(){
        if ($rootScope.media) {
            return true;
        }
    }

    /*
     * Watch position for changes.
     * If distance to poi <= 50 alert with media-information
     */
//    $scope.$watch('pos', function (newValue, oldValue) {
//        distance = calculateDistance($rootScope.pos.latitude, $rootScope.pos.longitude,
//            $scope.poi.coords.latitude, $scope.poi.coords.longitude);
//        $rootScope.pos.distance = distance;
//        if (distance <= 0.050 && $scope.lastcheck !== $scope.poi) {
//            notification.confirm(unescape(nearInfoAlert), function (btnNos) {
//                if (btnNos [0] === 1) {
//                    media.play($scope.poi.audio, function () {
//                        window.alert("Ende!");
//                        console.log("JA");
//                    });
//                }
//            }, unescape("Informationen verf%FCgbar"), ["Ja", "Nein"]);
//            $scope.lastcheck = $scope.poi;
//        }
//    });

    $scope.getDeviceSize = function() {
        $scope.deviceSize = device.size();
    }

  /*  $scope.$watch('pos', function (newValue) {

        if(!newValue) {
            $scope.userposition = null;
            return;
        }

        $scope.userposition = {
            latitude: $scope.pos.latitude,
            longitude: $scope.pos.longitude
        };

    });*/

});

appControllers.controller('ImgCtrl', function($scope, $rootScope, $routeParams, device){

    $scope.getWidth = {
        "width" : device.width + 'px'
    }

    $scope.imgID = $routeParams.imgID;
});

appControllers.controller('MainCtrl', function ($rootScope, geolocation, TOUR, Map) {

    $rootScope.mapOffset = {top: 0, left: 0};
    $rootScope.pois = TOUR.pointsOfInterest;
    $rootScope.poi = $rootScope.pois[0];

    geolocation.watchPosition(function (position) {
        /* Add pos to rootScope pos will be watched for changes in PoiCtrl */
        /*alert(position.coords.accuracy);*/
        $rootScope.pos = {latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy};
    });

    $rootScope.$watch('pos', function (newValue) {
        $rootScope.userPosition = (!newValue)?  Map.icons[0].coords : newValue;
        angular.forEach(Map.icons, function(icon, index) {
            var distance = Map.distance(icon.coords, $rootScope.userPosition);
            icon.isActive = (distance <= 0.1);
        });
    });

    /*console.log($scope);*/
});<commit_msg>Further cleaned controller<commit_after>var appControllers = angular.module('appControllers', ['appProviders', 'appDirectives']);

/*
 *  HELPER
 */
var nearInfoAlert = "Ihr Ziel ist in unmittelbarer N%E4he%2C m%F6chten sie nun Informationen dazu erhalten%3F";

/*
 *  CONTROLLER
 */
appControllers.controller('PoiCtrl', function ($rootScope, $scope, $location, $routeParams, notification, media, device) {

    $scope.stationID = $routeParams.stationID;
    $scope.poi = $scope.pois[$scope.stationID];

    $scope.getMargin = function(){
        if(device.width >= 500){
            return {margin: '50px'};
        }
    }

    $scope.getImageWidth = function(){
        if(device.width >= 500){
            return { width: '460px'};
        }
        return { width: '230px'};
    }

    $scope.stopAndRedirect = function(path){
        $location.path(path);
        media.stop($scope.media);
        show = false;
    }

    $scope.mediaPlay = function() {
        media.play($rootScope.poi.audio)
    }

    $scope.mediaStop = function() {
        media.stop($scope.media)
        show = false;
    }

    $scope.showButton = function(){
        if ($rootScope.media) {
            return true;
        }
    }

    /*
     * Watch position for changes.
     * If distance to poi <= 50 alert with media-information
     */
//    $scope.$watch('pos', function (newValue, oldValue) {
//        distance = calculateDistance($rootScope.pos.latitude, $rootScope.pos.longitude,
//            $scope.poi.coords.latitude, $scope.poi.coords.longitude);
//        $rootScope.pos.distance = distance;
//        if (distance <= 0.050 && $scope.lastcheck !== $scope.poi) {
//            notification.confirm(unescape(nearInfoAlert), function (btnNos) {
//                if (btnNos [0] === 1) {
//                    media.play($scope.poi.audio, function () {
//                        window.alert("Ende!");
//                        console.log("JA");
//                    });
//                }
//            }, unescape("Informationen verf%FCgbar"), ["Ja", "Nein"]);
//            $scope.lastcheck = $scope.poi;
//        }
//    });

  /*  $scope.$watch('pos', function (newValue) {
    $scope.getDeviceSize = function() {
        $scope.deviceSize = device.size();
    }

  /*  $scope.$watch('pos', function (newValue) {

        if(!newValue) {
            $scope.userposition = null;
            return;
        }

        $scope.userposition = {
            latitude: $scope.pos.latitude,
            longitude: $scope.pos.longitude
        };

    });*/

});

appControllers.controller('ImgCtrl', function($scope, $routeParams, device){
    $scope.getWidth = {
        "width" : device.width + 'px'
    }

    $scope.imgID = $routeParams.imgID;
});

appControllers.controller('MainCtrl', function ($scope, geolocation, TOUR, Map) {

    $scope.mapOffset = {top: 0, left: 0};
    $scope.pois = TOUR.pointsOfInterest;
    $scope.poi = $scope.pois[0];

    geolocation.watchPosition(function (position) {
        /* Add pos to rootScope pos will be watched for changes in PoiCtrl */
        /*alert(position.coords.accuracy);*/
        $scope.pos = {latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy};
    });

    $scope.$watch('pos', function (newValue) {
        $scope.userPosition = (!newValue)?  Map.icons[0].coords : newValue;
        angular.forEach(Map.icons, function(icon, index) {
            var distance = Map.distance(icon.coords, $scope.userPosition);
            icon.isActive = (distance <= 0.1);
        });
    });

    /*console.log($scope);*/
});<|endoftext|>


<commit_before>angular.module('starter.controllers', [])

.controller('LoginCtrl', function($scope, auth, $state, store) {
  auth.signin({
    closable: false,
    // This asks for the refresh token
    // So that the user never has to log in again
    authParams: {
      scope: 'openid offline_access'
    }
  }, function(profile, idToken, accessToken, state, refreshToken) {
    store.set('profile', profile);
    store.set('token', idToken);
    store.set('refreshToken', refreshToken);
    //temporarily just go to tab.polls
    $state.go('tab.polls');
    /////////////////////
    auth.getToken({
      api: 'firebase'
    }).then(function(delegation) {
      store.set('firebaseToken', delegation.id_token);
      $state.go('tab.polls');
    }, function(error) {
      console.log("There was an error logging in", error);
    })
  }, function(error) {
    console.log("There was an error logging in", error);
  });
})

.controller('PollsCtrl', function($scope, Polls, $ionicModal) {
 $ionicModal.fromTemplateUrl('templates/poll-add-modal.html', {
    scope: $scope,
    animation: 'slide-in-up'
  }).then(function(modal) {
    $scope.modal = modal;
  });

  $scope.newFriend = {
    name: '',
    description: ''
  };

  $scope.aggregateResults = function(poll){
    results = {'yes': 0, 'no': 0}
    if(poll.pollResponses){
      for(var key in poll.pollResponses){
        if(poll.pollResponses[key]){
          poll.pollResponses[key].thisUsersAnswer.toLowerCase()==='Yes' ? results.yes++ : results.no++;
        }
      }
    }
    return results;
  };

  $scope.polls = Polls.asArray;

  $scope.showAddFriend = function() {
    $scope.modal.show();
  };

  $scope.addFriend = function() {
    if(!$scope.newFriend.$id) {
      Polls.add($scope.newFriend);
    } else {
      Polls.save($scope.newFriend);
    }
    $scope.newFriend = {};
    $scope.modal.hide();
  };

  $scope.deleteFriend = function(friend) {
    Polls.delete(friend);
  };

  $scope.editFriend = function(friend) {
    $scope.newFriend = friend;
    $scope.modal.show();
  };

  $scope.close = function() {
    $scope.modal.hide();
  };

  $scope.$on('$destroy', function() {
    $scope.modal.remove();
  });
})

.controller('singlePollCtrl', function($scope, $stateParams, Polls) {
  $scope.poll = Poll.get($stateParams.pollId);
})

.controller('AccountCtrl', function($scope, auth, $state, store) {

  $scope.logout = function() {
    auth.signout();
    store.remove('token');
    store.remove('profile');
    store.remove('refreshToken');
    $state.go('login');
  }
});
<commit_msg>fix typo<commit_after>angular.module('starter.controllers', [])

.controller('LoginCtrl', function($scope, auth, $state, store) {
  auth.signin({
    closable: false,
    // This asks for the refresh token
    // So that the user never has to log in again
    authParams: {
      scope: 'openid offline_access'
    }
  }, function(profile, idToken, accessToken, state, refreshToken) {
    store.set('profile', profile);
    store.set('token', idToken);
    store.set('refreshToken', refreshToken);
    //temporarily just go to tab.polls
    $state.go('tab.polls');
    /////////////////////
    auth.getToken({
      api: 'firebase'
    }).then(function(delegation) {
      store.set('firebaseToken', delegation.id_token);
      $state.go('tab.polls');
    }, function(error) {
      console.log("There was an error logging in", error);
    })
  }, function(error) {
    console.log("There was an error logging in", error);
  });
})

.controller('PollsCtrl', function($scope, Polls, $ionicModal) {
 $ionicModal.fromTemplateUrl('templates/poll-add-modal.html', {
    scope: $scope,
    animation: 'slide-in-up'
  }).then(function(modal) {
    $scope.modal = modal;
  });

  $scope.newFriend = {
    name: '',
    description: ''
  };

  $scope.aggregateResults = function(poll){
    results = {'yes': 0, 'no': 0}
    if(poll.pollResponses){
      for(var key in poll.pollResponses){
        if(poll.pollResponses[key]){
          poll.pollResponses[key].thisUsersAnswer.toLowerCase()==='yes' ? results.yes++ : results.no++;
        }
      }
    }
    return results;
  };

  $scope.polls = Polls.asArray;

  $scope.showAddFriend = function() {
    $scope.modal.show();
  };

  $scope.addFriend = function() {
    if(!$scope.newFriend.$id) {
      Polls.add($scope.newFriend);
    } else {
      Polls.save($scope.newFriend);
    }
    $scope.newFriend = {};
    $scope.modal.hide();
  };

  $scope.deleteFriend = function(friend) {
    Polls.delete(friend);
  };

  $scope.editFriend = function(friend) {
    $scope.newFriend = friend;
    $scope.modal.show();
  };

  $scope.close = function() {
    $scope.modal.hide();
  };

  $scope.$on('$destroy', function() {
    $scope.modal.remove();
  });
})

.controller('singlePollCtrl', function($scope, $stateParams, Polls) {
  $scope.poll = Poll.get($stateParams.pollId);
})

.controller('AccountCtrl', function($scope, auth, $state, store) {

  $scope.logout = function() {
    auth.signout();
    store.remove('token');
    store.remove('profile');
    store.remove('refreshToken');
    $state.go('login');
  }
});
<|endoftext|>


<commit_before>'use strict';

angular.module('samplePad.controllers', [])

  .controller('headerController', ['$scope', '$location', 'Board', 'EditMode', function ($scope, $location, Board, EditMode) {

    $scope.editMode = false;
    $scope.boards = [];

    Board.getAll()
      .then(function(response) {
        $scope.boards = response.data;
      });

    $scope.$on('editModeUpdated', function() {
      $scope.editMode = EditMode.status;
    });

    $scope.isActive = function (viewLocation) {
      return $location.path().indexOf(viewLocation) == 0;
    }

    $scope.createBoard = function() {
      Board.create()
        .then(function(response) {
          console.log(response.data.message);
          $location.path('/boards/' + response.data.board_id);
        });
    }

    $scope.deleteBoard = function () {    //TODO: add confirmation for delete
      var board_id = $location.path().split('/')[2];
      Board.delete(board_id)
        .then(function(response) {
          console.log(response.data.message);
          EditMode.updateEditMode(false);
          $scope.boards
          $location.path('/');
        });
    }

  }])

  .controller('mainController', ['$scope', function ($scope) {

    $scope.googleInit = function() {
      gapi.signin2.render('g-signin2', {
        onsuccess: $scope.onSignIn
      });
    }
    $scope.googleInit();

    $scope.onSignIn = function (googleUser) {
      var profile = googleUser.getBasicProfile();
      console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
      console.log('Name: ' + profile.getName());
      console.log('Image URL: ' + profile.getImageUrl());
      console.log('Email: ' + profile.getEmail());
    }

    $scope.signOut = function () {
      var auth2 = gapi.auth2.getAuthInstance();
      auth2.signOut().then(function () {
        console.log('User signed out.');
      });
    }

  }])

  .controller('boardController', ['$scope', '$timeout', '$routeParams', '$location', 'Board', 'EditMode',
    function ($scope, $timeout, $routeParams, $location, Board, EditMode) {

    $scope.board = {};
    $scope.charCodeArr = [];
    $scope.editMode = false;
    $scope.padNumBeingEdited = '';
    $scope.editingBoardName = false;
    $scope.oldBoardName = '';

    $scope.initBoard = function() {
      Board.load($routeParams.id)
        .then(function(response) {
          console.log(response);
          $scope.board = response.data;

          // load pad sounds
          lowLag.init({sm2url: "lib/sm2/swf/"});
          for (var i = 1; i < 13; i++) {
            $scope.loadSound(i, $scope.board.pads[i-1].src);
          }

          $scope.updateCharCodeArr();

        });

    }

    $scope.initBoard();

    // Event Listeners
    $scope.$watch('editMode', function() {
      EditMode.updateEditMode($scope.editMode);
    });

    $('body').keydown(function(event) {
      if ($scope.charCodeArr.indexOf(event.which) !== -1) {
        $scope.triggerPad($scope.charCodeArr.indexOf(event.which) + 1);
      }
    });
    //////////////

    $scope.loadSound = function(padNum, src) {
      lowLag.load(src, padNum)
    }

    $scope.updateCharCodeArr = function () {   // default is [49,50,51,52,81,87,69,82,65,83,68,70];
      $scope.board.pads.forEach(function(pad, i) {
        $scope.charCodeArr[i] = pad.hotkey.charCodeAt(0);
      });
    }

    $scope.saveBoard = function () {
      Board.save($scope.board)
        .then(function(response) {
          console.log(response.data.message);
        });
    }

    $scope.triggerPad = function(padNum) {

      if (!$scope.editMode && !$scope.editingBoardName) {

        var $padCuboid = $('#pad-' + padNum).parent();
        var $edges = $padCuboid.find(".face").not(".tp")

        // change edge color when triggered
        $edges.css("background-color", "#76FF03");

        // button pressed appearance
        var observedTransform = $padCuboid.css("transform");
        var observedTransformArr = observedTransform.split(',');
        observedTransformArr[13] = " -14";
        var pressedTransform = observedTransformArr.join(',');
        $padCuboid.css("transform", pressedTransform);

        // fixed issue with multiple clicks within 200ms
        var initialTransformArr = observedTransform.split(',');
        initialTransformArr[13] = " -21";
        var initialTransform = initialTransformArr.join(',');

        $timeout(function() {
          $padCuboid.css("transform", initialTransform);
        }, 200);

        // I modified lowLag.js to accept an optional callback
        // to play() that fires on the 'ended' event.

        lowLag.play(padNum, function () {
          $edges.css("background-color", "#651FFF");
        });

        // TODO: it would be nice to use mouse down and mouse up events to keep the pad pressed
        // down as long as the mouse button is held, even though there would be no functional value.
      }

    };

    $scope.toggleEditMode = function ($event) {

      // Change appearance of button and toggle $scope.editMode
      var $editModeButton = $('#edit-mode-button');

      var $span = $editModeButton.find("span");
      var $edges = $editModeButton.parent().find(".face").not(".tp");
      var $top = $editModeButton.find(".tp");

      if ($scope.editMode) {

        $(document).off("click");

        $edges.css("background-color", "#FF3D00");
        $span
          .css("color", "#FF3D00")
          .text('EDIT');
        $scope.saveBoard();
        $scope.editMode = false;

      } else {

        $(document).click(function(event) {
          var $element = $(event.target);
          $element.prevAll('.edit-pad-button').click();
        });

        $edges.css("background-color", "#76FF03");
        $span
          .css("color", "#76FF03")
          .text('SAVE');
        $scope.editMode = true;
      }

    }

    $scope.editPad = function (padNum) {
      $scope.padNumBeingEdited = padNum;
      $scope.padDetails = {
        name: $scope.board.pads[padNum-1].name,
        src: $scope.board.pads[padNum-1].src,
        hotkey: $scope.board.pads[padNum-1].hotkey
      }
      $('#modal').modal('show');

      $(document).keydown(function(e) {
        if (e.keyCode == 27) {   // esc
          $('.cancel-pad-edits-button').click();
          $(document).off("keydown");
        }
      });

    };

    $scope.submitPadEdits = function (padDetails) {
      $scope.board.pads[$scope.padNumBeingEdited-1] = {
        name: padDetails.name,
        src: padDetails.src,
        hotkey: padDetails.hotkey
      }
      $scope.loadSound($scope.padNumBeingEdited, padDetails.src);
      $scope.updateCharCodeArr();
      $scope.padNumBeingEdited = '';
      $('#modal').modal('hide');
    }

    $scope.cancelPadEdits = function() {
      $scope.padNumBeingEdited = '';
      $(document).off("keydown");
    }

    $scope.editBoardName = function() {
      $scope.editingBoardName = true;
      $scope.oldBoardName = $scope.board.name;
      $(document).keydown(function(e) {
        console.log(e.keyCode);
        if (e.keyCode == 13) {       // enter
          $scope.$apply(function() {
            $scope.submitBoardNameEdit();
          });
          $(document).off("keydown");
        }
        if (e.keyCode == 27) {       // esc
          $scope.$apply(function () {
            $scope.cancelBoardNameEdit();
          });
          $(document).off("keydown");
        }
      });
    }

    $scope.submitBoardNameEdit = function () {
      $scope.editingBoardName = false;
      $scope.oldBoardName = '';
      $scope.saveBoard();
    }

    $scope.cancelBoardNameEdit = function () {
      $scope.board.name = $scope.oldBoardName;
      $scope.editingBoardName = false;
    }

  }]);
<commit_msg>oauth init work<commit_after>'use strict';

angular.module('samplePad.controllers', [])

  .controller('headerController', ['$scope', '$location', 'Board', 'EditMode', function ($scope, $location, Board, EditMode) {

    $scope.editMode = false;
    $scope.boards = [];

    Board.getAll()
      .then(function(response) {
        $scope.boards = response.data;
      });

    $scope.$on('editModeUpdated', function() {
      $scope.editMode = EditMode.status;
    });

    $scope.isActive = function (viewLocation) {
      return $location.path().indexOf(viewLocation) == 0;
    }

    $scope.createBoard = function() {
      Board.create()
        .then(function(response) {
          console.log(response.data.message);
          $location.path('/boards/' + response.data.board_id);
        });
    }

    $scope.deleteBoard = function () {    //TODO: add confirmation for delete
      var board_id = $location.path().split('/')[2];
      Board.delete(board_id)
        .then(function(response) {
          console.log(response.data.message);
          EditMode.updateEditMode(false);
          $scope.boards
          $location.path('/');
        });
    }

  }])

  .controller('mainController', ['$scope', function ($scope) {

    $scope.googleInit = function() {
      gapi.signin2.render('g-signin2', {
        'scope': 'email',
        'width': 200,
        'height': 50,
        'longtitle': true,
        'theme': 'dark',
        'onsuccess': $scope.onSignIn(googleUser)
      });
    }
    $scope.googleInit();

    $scope.onSignIn = function (googleUser) {
      var profile = googleUser.getBasicProfile();
      console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
      console.log('Name: ' + profile.getName());
      console.log('Image URL: ' + profile.getImageUrl());
      console.log('Email: ' + profile.getEmail());
    }

    $scope.signOut = function () {
      var auth2 = gapi.auth2.getAuthInstance();
      auth2.signOut().then(function () {
        console.log('User signed out.');
      });
    }

  }])

  .controller('boardController', ['$scope', '$timeout', '$routeParams', '$location', 'Board', 'EditMode',
    function ($scope, $timeout, $routeParams, $location, Board, EditMode) {

    $scope.board = {};
    $scope.charCodeArr = [];
    $scope.editMode = false;
    $scope.padNumBeingEdited = '';
    $scope.editingBoardName = false;
    $scope.oldBoardName = '';

    $scope.initBoard = function() {
      Board.load($routeParams.id)
        .then(function(response) {
          console.log(response);
          $scope.board = response.data;

          // load pad sounds
          lowLag.init({sm2url: "lib/sm2/swf/"});
          for (var i = 1; i < 13; i++) {
            $scope.loadSound(i, $scope.board.pads[i-1].src);
          }

          $scope.updateCharCodeArr();

        });

    }

    $scope.initBoard();

    // Event Listeners
    $scope.$watch('editMode', function() {
      EditMode.updateEditMode($scope.editMode);
    });

    $('body').keydown(function(event) {
      if ($scope.charCodeArr.indexOf(event.which) !== -1) {
        $scope.triggerPad($scope.charCodeArr.indexOf(event.which) + 1);
      }
    });
    //////////////

    $scope.loadSound = function(padNum, src) {
      lowLag.load(src, padNum)
    }

    $scope.updateCharCodeArr = function () {   // default is [49,50,51,52,81,87,69,82,65,83,68,70];
      $scope.board.pads.forEach(function(pad, i) {
        $scope.charCodeArr[i] = pad.hotkey.charCodeAt(0);
      });
    }

    $scope.saveBoard = function () {
      Board.save($scope.board)
        .then(function(response) {
          console.log(response.data.message);
        });
    }

    $scope.triggerPad = function(padNum) {

      if (!$scope.editMode && !$scope.editingBoardName) {

        var $padCuboid = $('#pad-' + padNum).parent();
        var $edges = $padCuboid.find(".face").not(".tp")

        // change edge color when triggered
        $edges.css("background-color", "#76FF03");

        // button pressed appearance
        var observedTransform = $padCuboid.css("transform");
        var observedTransformArr = observedTransform.split(',');
        observedTransformArr[13] = " -14";
        var pressedTransform = observedTransformArr.join(',');
        $padCuboid.css("transform", pressedTransform);

        // fixed issue with multiple clicks within 200ms
        var initialTransformArr = observedTransform.split(',');
        initialTransformArr[13] = " -21";
        var initialTransform = initialTransformArr.join(',');

        $timeout(function() {
          $padCuboid.css("transform", initialTransform);
        }, 200);

        // I modified lowLag.js to accept an optional callback
        // to play() that fires on the 'ended' event.

        lowLag.play(padNum, function () {
          $edges.css("background-color", "#651FFF");
        });

        // TODO: it would be nice to use mouse down and mouse up events to keep the pad pressed
        // down as long as the mouse button is held, even though there would be no functional value.
      }

    };

    $scope.toggleEditMode = function ($event) {

      // Change appearance of button and toggle $scope.editMode
      var $editModeButton = $('#edit-mode-button');

      var $span = $editModeButton.find("span");
      var $edges = $editModeButton.parent().find(".face").not(".tp");
      var $top = $editModeButton.find(".tp");

      if ($scope.editMode) {

        $(document).off("click");

        $edges.css("background-color", "#FF3D00");
        $span
          .css("color", "#FF3D00")
          .text('EDIT');
        $scope.saveBoard();
        $scope.editMode = false;

      } else {

        $(document).click(function(event) {
          var $element = $(event.target);
          $element.prevAll('.edit-pad-button').click();
        });

        $edges.css("background-color", "#76FF03");
        $span
          .css("color", "#76FF03")
          .text('SAVE');
        $scope.editMode = true;
      }

    }

    $scope.editPad = function (padNum) {
      $scope.padNumBeingEdited = padNum;
      $scope.padDetails = {
        name: $scope.board.pads[padNum-1].name,
        src: $scope.board.pads[padNum-1].src,
        hotkey: $scope.board.pads[padNum-1].hotkey
      }
      $('#modal').modal('show');

      $(document).keydown(function(e) {
        if (e.keyCode == 27) {   // esc
          $('.cancel-pad-edits-button').click();
          $(document).off("keydown");
        }
      });

    };

    $scope.submitPadEdits = function (padDetails) {
      $scope.board.pads[$scope.padNumBeingEdited-1] = {
        name: padDetails.name,
        src: padDetails.src,
        hotkey: padDetails.hotkey
      }
      $scope.loadSound($scope.padNumBeingEdited, padDetails.src);
      $scope.updateCharCodeArr();
      $scope.padNumBeingEdited = '';
      $('#modal').modal('hide');
    }

    $scope.cancelPadEdits = function() {
      $scope.padNumBeingEdited = '';
      $(document).off("keydown");
    }

    $scope.editBoardName = function() {
      $scope.editingBoardName = true;
      $scope.oldBoardName = $scope.board.name;
      $(document).keydown(function(e) {
        console.log(e.keyCode);
        if (e.keyCode == 13) {       // enter
          $scope.$apply(function() {
            $scope.submitBoardNameEdit();
          });
          $(document).off("keydown");
        }
        if (e.keyCode == 27) {       // esc
          $scope.$apply(function () {
            $scope.cancelBoardNameEdit();
          });
          $(document).off("keydown");
        }
      });
    }

    $scope.submitBoardNameEdit = function () {
      $scope.editingBoardName = false;
      $scope.oldBoardName = '';
      $scope.saveBoard();
    }

    $scope.cancelBoardNameEdit = function () {
      $scope.board.name = $scope.oldBoardName;
      $scope.editingBoardName = false;
    }

  }]);
<|endoftext|>


<commit_before>/*
 * Author: Maverick Chan
 * License: MIT License
 */

(function() {
/*
 * Module's settings and public API.
 */
var storage = {
  storageType: 'localStorage',
  async: true,
};
storage.works = storageSupported(storage.storageType);
var storageTypes = {
  'localStorage': localStorage,
  'sessionStorage': sessionStorage
};
var defaultStorage = storageTypes[storage.storageType];
var setItem = defaultStorage.setItem.bind(defaultStorage);
var getItem = defaultStorage.getItem.bind(defaultStorage);
var removeItem = defaultStorage.removeItem.bind(defaultStorage);

/*
 * Check browser support for storage
 *
 * @param {String} storageType
 * @return {Boolean} support for storage
 * @api private
 */
function storageSupported(storageType) {
  try {
    return storageType in window && window[storageType] !== null;
  } catch(e) {
    return false;
  }
}

/*
 * Runs function asynchronously.
 *
 * Usage:
 * > async(localStorage.setItem)
       .run('hello', 'world', function() {})
 * > var result = async(localStorage.getItem)
 *     .run('hello', function(value){console.log(result)});
 *
 * @param {Function} synchronous function
 * @return {Object} asyncFunc
 * @api private
 */
function async(func) {
  var NOTSTARTED = 0, PENDING = 1, SUCCESS = 2, FAIL = -1;
  var asyncFunc = {};
  asyncFunc.status = NOTSTARTED;
  asyncFunc.run = function doAsyncFunc() {
    var args = Array.prototype.slice.call(arguments);
    var callback = args.pop();
    asyncFunc.status = PENDING;
    // Pushes it to background with 0ms delay
    var funcToBackground = setTimeout(function() {
      try {
        var result = func.apply(this, args);
        asyncFunc.status = SUCCESS;
        asyncFunc.result = result;
      } catch(e) {
        asyncFunc.status = FAIL;
        asyncFunc.result = e;
      }
    }, 0);
    // Runs continuously checking for status of asyncFunc
    // Runs after-task attached at asyncFunc.done
    var asyncFuncChecker = setInterval(function() {
      var status = asyncFunc.status;
      if (status === SUCCESS || status === FAIL) {
        clearInterval(asyncFuncChecker);
        callback(asyncFunc.result);
      }
    }, 0);
    // Attached to returned asyncFunc.done
    return asyncFunc;
  };
  return asyncFunc;
}

/*
 * Goes through settings and make changes to module.
 *
 * @api private
 */
(function parseSettings() {
  // Bail if it doesn't work, no fallback
  if (!storage.works) storage = undefined;
})();

/*
 * Attempt to parse string for JSON.
 *
 * @return {String} if not JSON
 * @return {Object} if able to JSON.parse
 * @api private
 */
function parseIfPossible(obj) {
  try {
    return JSON.parse(obj);
  } catch(e) {
    return obj;
  }
}

/*
 * Attempt to stringify JSON.
 *
 * @return {String} if serializable
 * @return {Object} if JSON.stringify fails
 * @api private
 */
function stringifyIfPossible(obj) {
  try {
    return JSON.stringify(obj);
  } catch(e) {
    return obj;
  }
}

/*
 * Functions for accessing storage:
 * get, getSync, getMulti
 * set, setSync, setMulti
 * remove, removeSync, removeMulti
 */

/*
 * Wrapper function for localStorage.setItem
 * which is asynchronous and deserializes to string.
 * Callback accepts no parameters.
 *
 * @param {String} key
 * @param {Object} value
 * @param {Function} callback
 * @api public
 */
storage.set = function setStorage(key, value, callback) {
  value = stringifyIfPossible(value);
  async(setItem).run(key, value, function(){
    if (callback) callback();
  });
};

/*
 * Wrapper function for localStorage.setItem
 * which just deserializes to string.
 *
 * @param {String} key
 * @param {Object} value
 * @api public
 */
storage.setSync = function(key, value) {
  defaultStorage.setItem(key, stringifyIfPossible(value));
};

/*
 * Iterates through keyValue Object and does storage.set.
 * Callback accepts no parameters.
 *
 * @param {Object} keyValue
 * @param {Function} callback
 * @api public
 */
storage.setMulti = function(keyValue, callback) {
  var keys = Object.keys(keyValue);
  var counter = 0;
  function incrementCounter() { counter++; }
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    var value = keyValue[key];
    storage.set(key, value, incrementCounter);
  }
  var counterChecker = setInterval(function() {
    if (counter === keys.length) {
      clearInterval(counterChecker);
      if (callback) callback();
    }
  }, 0);
};

/*
 * Wrapper function for localStorage.getItem
 * which is asynchronous and serializes to JSON.
 * Callback accepts value as parameter.
 *
 * @param {String} key
 * @param {Function} callback with value passed
 *   @param {Object} value (null if not present)
 * @api public
 */
storage.get = function getStorage(key, callback) {
  async(getItem).run(key, function(value) {
    // null if not present
    callback(parseIfPossible(value));
  });
};

// For syntactic sugar
storage.has = storage.get;

/*
 * Wrapper function for localStorage.setItem
 * which just deserializes to string.
 *
 * @param {String} key
 * @param {Object} value
 * @api public
 */
storage.getSync = function(key) {
  return parseIfPossible(defaultStorage.getItem(key));
};

/*
 * Iterates through keys and does storage.get.
 * Callback accepts array of values as parameter.
 *
 * @param {Array} keys
 * @param {Function} callback
 *   @param {Array} values
 * @api public
 */
storage.getMulti = function getMultiStorage(keys, callback) {
  var values = [];
  function rememberValue(value) {
    values.push(parseIfPossible(value));
  }
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    storage.get(key, rememberValue);
  }
  // Continuously check for function completion
  var counterChecker = setInterval(function() {
    if (values.length === keys.length) {
      clearInterval(counterChecker);
      callback(values);
    }
  }, 0);
};

/*
 * Wrapper function for localStorage.removeItem
 * which is asynchronous.
 * Callback takes no parameters.
 *
 * @param {String} key
 * @param {Function} callback
 * @api public
 */
storage.remove = function removeStorage(key, callback) {
  async(removeItem).run(key, function() {
    callback();
  });
};

/*
 * Wrapper function for localStorage.removeItem
 * which is behaves exactly the same.
 *
 * @param {String} key
 * @api public
 */
storage.removeSync = function removeSyncStorage(key) {
  defaultStorage.removeItem(key);
};

/*
 * Iterates through keys and does storage.remove.
 * Callback accepts array of values as parameter.
 *
 * @param {Array} keys
 * @param {Function} callback
 * @api public
 */
storage.removeMulti = function removeMultiStorage(keys, callback) {
  var counter = 0;
  function incrementCounter() { counter++; }
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    storage.remove(key, incrementCounter);
  }
  var counterChecker = setInterval(function() {
    if (counter === keys.length) {
      clearInterval(counterChecker);
      callback();
    }
  });
};

/*
 * Runs function on each storage item asynchronously.
 *
 * @param {Array} key
 * @param {Function} callback
 *   @param {Boolean} hasValue
 * @api public
 */
storage.forEach = function forEach(keys, func) {
  var newValues, keyValue;
  storage.getMulti(keys, function(values) {
    newValues = values.forEach(func);
    keyValue = constructKeyValue(keys, newValues);
    storage.setMulti(keyValue); // callback not compulsory here
  });

  // constructKeyValue([1, 2, 3], [2, 3, 4])
  // => {1: 2, 2: 3, 3: 4}
  function constructKeyValue(keys, values) {
    var keyValue = {};
    for (var i = 0; i < keys.length; i++) {
      keyValue[keys[i]] = values[i];
    }
    return keyValue;
  }
};

/*
 * Functions for space management:
 * size, left
 */

var MAX_SIZE = 1024 * 1024 * 5;  // 5 MB is default size of storage

/*
 * Iterates through keys and values, records their lengths.
 *
 * @api public
 */
storage.size = function getStorageSize() {
  var keys = Object.keys(defaultStorage);
  var keysLength = keys.join('').length;
  var value, values = [];
  for (var i = 0; i < keys.length; i++) {
    value = defaultStorage.getItem(keys[i]);
    values.push(value);
  }
  var valuesLength = values.join('').length;
  return keysLength + valuesLength;
};

/*
 * Performs subtraction between MAX_SIZE and storage.size
 * Callback accepts storage left as param
 *
 * @api public
 */
storage.left = function getStorageLeft() {
  return MAX_SIZE - this.size();
};

window.storey = storage;

})();  // storage.js encapsulation
<commit_msg>Simplified code to be without setIntervals<commit_after>/*
 * Author: Maverick Chan
 * License: MIT License
 */

(function() {
/*
 * Module's settings and public API.
 */
var storage = {
  storageType: 'localStorage',
  async: true,
};
storage.works = storageSupported(storage.storageType);
var storageTypes = {
  'localStorage': localStorage,
  'sessionStorage': sessionStorage
};
var defaultStorage = storageTypes[storage.storageType];
var setItem = defaultStorage.setItem.bind(defaultStorage);
var getItem = defaultStorage.getItem.bind(defaultStorage);
var removeItem = defaultStorage.removeItem.bind(defaultStorage);

/*
 * Check browser support for storage
 *
 * @param {String} storageType
 * @return {Boolean} support for storage
 * @api private
 */
function storageSupported(storageType) {
  try {
    return storageType in window && window[storageType] !== null;
  } catch(e) {
    return false;
  }
}

/*
 * Runs function asynchronously.
 *
 * Usage:
 * > async(localStorage.setItem)
       .run('hello', 'world', function() {})
 * > var result = async(localStorage.getItem)
 *     .run('hello', function(value){console.log(result)});
 *
 * @param {Function} synchronous function
 * @return {Object} asyncFunc
 * @api private
 */
function async(func) {
  var NOTSTARTED = 0, PENDING = 1, SUCCESS = 2, FAIL = -1;
  var asyncFunc = {};
  asyncFunc.status = NOTSTARTED;
  asyncFunc.run = function doAsyncFunc() {
    var args = Array.prototype.slice.call(arguments);
    var callback = args.pop();
    asyncFunc.status = PENDING;
    // Pushes it to background with 0ms delay
    setTimeout(function() {
      try {
        var result = func.apply(this, args);
        callback(result);
        asyncFunc.status = SUCCESS;
        asyncFunc.result = result;
      } catch(e) {
        asyncFunc.status = FAIL;
        callback(e);
      }
    }, 0);
  };
  return asyncFunc;
}

/*
 * Goes through settings and make changes to module.
 *
 * @api private
 */
(function parseSettings() {
  // Bail if it doesn't work, no fallback
  if (!storage.works) storage = undefined;
})();

/*
 * Attempt to parse string for JSON.
 *
 * @return {String} if not JSON
 * @return {Object} if able to JSON.parse
 * @api private
 */
function parseIfPossible(obj) {
  try {
    return JSON.parse(obj);
  } catch(e) {
    return obj;
  }
}

/*
 * Attempt to stringify JSON.
 *
 * @return {String} if serializable
 * @return {Object} if JSON.stringify fails
 * @api private
 */
function stringifyIfPossible(obj) {
  try {
    return JSON.stringify(obj);
  } catch(e) {
    return obj;
  }
}

/*
 * Functions for accessing storage:
 * get, getSync, getMulti
 * set, setSync, setMulti
 * remove, removeSync, removeMulti
 */

/*
 * Wrapper function for localStorage.setItem
 * which is asynchronous and deserializes to string.
 * Callback accepts no parameters.
 *
 * @param {String} key
 * @param {Object} value
 * @param {Function} callback
 * @api public
 */
storage.set = function setStorage(key, value, callback) {
  value = stringifyIfPossible(value);
  async(setItem).run(key, value, function(){
    if (callback) callback();
  });
};

/*
 * Wrapper function for localStorage.setItem
 * which just deserializes to string.
 *
 * @param {String} key
 * @param {Object} value
 * @api public
 */
storage.setSync = function(key, value) {
  defaultStorage.setItem(key, stringifyIfPossible(value));
};

/*
 * Iterates through keyValue Object and does storage.set.
 * Callback accepts no parameters.
 *
 * @param {Object} keyValue
 * @param {Function} callback
 * @api public
 */
storage.setMulti = function(keyValue, callback) {
  var keys = Object.keys(keyValue);
  var counter = 0;
  function incrementCounter() {
    counter++;
    if (counter === keys.length) callback();
  }
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    var value = keyValue[key];
    storage.set(key, value, incrementCounter);
  }
};

/*
 * Wrapper function for localStorage.getItem
 * which is asynchronous and serializes to JSON.
 * Callback accepts value as parameter.
 *
 * @param {String} key
 * @param {Function} callback with value passed
 *   @param {Object} value (null if not present)
 * @api public
 */
storage.get = function getStorage(key, callback) {
  async(getItem).run(key, function(value) {
    // null if not present
    callback(parseIfPossible(value));
  });
};

// For syntactic sugar
storage.has = storage.get;

/*
 * Wrapper function for localStorage.setItem
 * which just deserializes to string.
 *
 * @param {String} key
 * @param {Object} value
 * @api public
 */
storage.getSync = function(key) {
  return parseIfPossible(defaultStorage.getItem(key));
};

/*
 * Iterates through keys and does storage.get.
 * Callback accepts array of values as parameter.
 *
 * @param {Array} keys
 * @param {Function} callback
 *   @param {Array} values
 * @api public
 */
storage.getMulti = function getMultiStorage(keys, callback) {
  var values = [];
  function rememberValue(value) {
    values.push(parseIfPossible(value));
    if (values.length === keys.length) callback(values);
  }
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    storage.get(key, rememberValue);
  }
};

/*
 * Wrapper function for localStorage.removeItem
 * which is asynchronous.
 * Callback takes no parameters.
 *
 * @param {String} key
 * @param {Function} callback
 * @api public
 */
storage.remove = function removeStorage(key, callback) {
  async(removeItem).run(key, function() {
    callback();
  });
};

/*
 * Wrapper function for localStorage.removeItem
 * which is behaves exactly the same.
 *
 * @param {String} key
 * @api public
 */
storage.removeSync = function removeSyncStorage(key) {
  defaultStorage.removeItem(key);
};

/*
 * Iterates through keys and does storage.remove.
 * Callback accepts array of values as parameter.
 *
 * @param {Array} keys
 * @param {Function} callback
 * @api public
 */
storage.removeMulti = function removeMultiStorage(keys, callback) {
  var counter = 0;
  function incrementCounter() {
    counter++;
    if (counter === keys.length) callback();
  }
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    storage.remove(key, incrementCounter);
  }
};

/*
 * Runs function on each storage item asynchronously.
 *
 * @param {Array} key
 * @param {Function} callback
 *   @param {Boolean} hasValue
 * @api public
 */
storage.forEach = function forEach(keys, func) {
  var newValues, keyValue;
  storage.getMulti(keys, function(values) {
    newValues = values.forEach(func);
    keyValue = constructKeyValue(keys, newValues);
    storage.setMulti(keyValue); // callback not compulsory here
  });

  // constructKeyValue([1, 2, 3], [2, 3, 4])
  // => {1: 2, 2: 3, 3: 4}
  function constructKeyValue(keys, values) {
    var keyValue = {};
    for (var i = 0; i < keys.length; i++) {
      keyValue[keys[i]] = values[i];
    }
    return keyValue;
  }
};

/*
 * Functions for space management:
 * size, left
 */

var MAX_SIZE = 1024 * 1024 * 5;  // 5 MB is default size of storage

/*
 * Iterates through keys and values, records their lengths.
 *
 * @api public
 */
storage.size = function getStorageSize() {
  var keys = Object.keys(defaultStorage);
  var keysLength = keys.join('').length;
  var value, values = [];
  for (var i = 0; i < keys.length; i++) {
    value = defaultStorage.getItem(keys[i]);
    values.push(value);
  }
  var valuesLength = values.join('').length;
  return keysLength + valuesLength;
};

/*
 * Performs subtraction between MAX_SIZE and storage.size
 * Callback accepts storage left as param
 *
 * @api public
 */
storage.left = function getStorageLeft() {
  return MAX_SIZE - this.size();
};

window.storey = storage;

})();  // storage.js encapsulation
<|endoftext|>