<commit_before>var m = require('mithril');

module.exports = function(opts, name) {

  var busy = false;
  var instance = null;

  var send = function(text) {
    instance.postMessage(text);
  };

  var processOutput = function(text, work) {
    if (/bestmove .*/.test(text)) {
      busy = false;
      return;
    }
    if (/currmovenumber|lowerbound|upperbound/.test(text)) return;
    var matches = text.match(/depth (\d+) .*score (cp|mate) ([-\d]+) .*pv (.+)/);
    if (!matches) return;
    var depth = parseInt(matches[1]);
    if (depth < opts.minDepth) return;
    var cp, mate;
    if (matches[2] === 'cp') cp = parseFloat(matches[3]);
    else mate = parseFloat(matches[3]);
    if (work.ply % 2 === 1) {
      if (matches[2] === 'cp') cp = -cp;
      else mate = -mate;
    }
    var best = matches[4].split(' ')[0];
    work.emit({
      work: work,
      eval: {
        depth: depth,
        cp: cp,
        mate: mate,
        best: best
      },
      name: name
    });
  };

  var stop = function() {
    if (busy && instance) {
      instance.terminate();
      instance = null;
    }
    if (!instance) {
      instance = new Worker(opts.path);
      if (opts.variant.key === 'fromPosition' || opts.variant.key === 'chess960')
        send('setoption name UCI_Chess960 value true');
      else if (opts.variant.key === 'atomic')
        send('setoption name UCI_Atomic value true');
      else if (opts.variant.key === 'horde')
        send('setoption name UCI_Horde value true');
      else if (opts.variant.key === 'crazyhouse')
        send('setoption name UCI_House value true');
      else if (opts.variant.key === 'kingOfTheHill')
        send('setoption name UCI_KingOfTheHill value true');
      else if (opts.variant.key === 'racingKings')
        send('setoption name UCI_Race value true');
      else if (opts.variant.key === 'threeCheck')
        send('setoption name UCI_3Check value true');
      else
        send('uci'); // send something to warm up
    }
    busy = false;
  };

  stop();

  return {
    start: function(work) {
      busy = true;
      send(['position', 'fen', work.position, 'moves'].concat(work.moves).join(' '));
      send('go depth ' + opts.maxDepth);
      instance.onmessage = function(msg) {
        processOutput(msg.data, work);
      };
    },
    stop: stop
  };
};
<commit_msg>code duplication<commit_after>var m = require('mithril');

var variantMap = {
  fromPosition: 'Chess960',
  chess960: 'Chess960',
  atomic: 'Atomic',
  horde: 'Horde',
  crazyhouse: 'House',
  kingOfTheHill: 'KingOfTheHill',
  racingKings: 'Race',
  threeCheck: '3Check'
};

module.exports = function(opts, name) {

  var busy = false;
  var instance = null;

  var send = function(text) {
    instance.postMessage(text);
  };

  var processOutput = function(text, work) {
    if (/bestmove .*/.test(text)) {
      busy = false;
      return;
    }
    if (/currmovenumber|lowerbound|upperbound/.test(text)) return;
    var matches = text.match(/depth (\d+) .*score (cp|mate) ([-\d]+) .*pv (.+)/);
    if (!matches) return;
    var depth = parseInt(matches[1]);
    if (depth < opts.minDepth) return;
    var cp, mate;
    if (matches[2] === 'cp') cp = parseFloat(matches[3]);
    else mate = parseFloat(matches[3]);
    if (work.ply % 2 === 1) {
      if (matches[2] === 'cp') cp = -cp;
      else mate = -mate;
    }
    var best = matches[4].split(' ')[0];
    work.emit({
      work: work,
      eval: {
        depth: depth,
        cp: cp,
        mate: mate,
        best: best
      },
      name: name
    });
  };

  var stop = function() {
    if (busy && instance) {
      instance.terminate();
      instance = null;
    }
    if (!instance) {
      instance = new Worker(opts.path);
      var uciVariant = variantMap[opts.variant.key];
      if (uciVariant) send('setoption name UCI_' + uciVariant + ' value true');
      else send('uci'); // send something to warm up
    }
    busy = false;
  };

  stop();

  return {
    start: function(work) {
      busy = true;
      send(['position', 'fen', work.position, 'moves'].concat(work.moves).join(' '));
      send('go depth ' + opts.maxDepth);
      instance.onmessage = function(msg) {
        processOutput(msg.data, work);
      };
    },
    stop: stop
  };
};
<|endoftext|>


<commit_before>/*
 * Basics.
 *
 * Use of semicolon ";" in end of lines is optional.
 *
 * Underscore.js used to provide easy to use tools.
 */

// define class with parameters
class BaseClass {
    a = null
    b = 10
    _x = "hidden property of BaseClass"
}
obj = new BaseClass()
// -->
function BaseClass() {
    var self = this;

    // properties
    self.a = null;
    self.b = 10;
    var _x = "hidden property of BaseClass";
}
obj = new BaseClass();

// define class with parameters and constructor
class Base2Class {
    a = null
    b = 10
    var _x = "hidden property of Base2Class";

    function construct(a, b) {
        self.a = a
        self.b = b
    }

    function add() {
        return self.a + self.b
    }

    function get_x() {
        return _x
    }
}
obj = new Base2Class(10, 20)
// -->
function Base2Class(a, b) {
    var self = this;

    // properties
    self.a = null;
    self.b = 10;
    var _x = "hidden property of Base2Class";

    // constructor
    self.a = a;
    self.b = b;

    // method add()
    self.add = function add() {
        return self.a + self.b;
    }

    // method get_x()
    self.get_x = function get_x() {
        return _x;
    }
}
obj = new Base2Class(10, 20);

// class inheritance
class MyClass1 extends Base2Class {
    c = "ccc"
    _y = "hidden property of MyClass1"

    // redefine method of parent's class
    function get_x() {
        return "Redefined method get_x() of parent's class"
    }

    function get_y() {
        return _y
    }
}
obj = new MyClass1(10, 20)
// -->
function MyClass1() {
    var self = this;

    // properties
    self.c = "ccc";
    var _y = "hidden property of MyClass1";

    // method get_x()
    self.get_x = function get_x() {
        return "Redefined method get_x() of parent's class";
    }

    // method get_y()
    self.get_y = function get_y() {
        return _y;
    }
}
_.extend(MyClass1, Base2Class);
obj = new MyClass1(10, 20);
<commit_msg>Changed styles for classes: now private variables comes with leading "var"<commit_after>/*
 * Basics.
 *
 * Use of semicolon ";" in end of lines is optional.
 *
 * Underscore.js used to provide easy to use tools.
 */

// define class with parameters
class BaseClass {
    a = null
    b = 10
    var x = "hidden property of BaseClass"
}
obj = new BaseClass()
// -->
function BaseClass() {
    var self = this;

    // properties
    self.a = null;
    self.b = 10;
    var x = "hidden property of BaseClass";
}
obj = new BaseClass();

// define class with parameters and constructor
class Base2Class {
    a = null
    b = 10
    var x = "hidden property of Base2Class"

    function construct(a, b) {
        self.a = a
        self.b = b
    }

    function add() {
        return self.a + self.b
    }

    function get_x() {
        return x
    }
}
obj = new Base2Class(10, 20)
// -->
function Base2Class(a, b) {
    var self = this;

    // properties
    self.a = null;
    self.b = 10;
    var x = "hidden property of Base2Class";

    // constructor
    self.a = a;
    self.b = b;

    // method add()
    self.add = function add() {
        return self.a + self.b;
    }

    // method get_x()
    self.get_x = function get_x() {
        return _x;
    }
}
obj = new Base2Class(10, 20);

// class inheritance
class MyClass1 extends Base2Class {
    c = "ccc"
    var y = "hidden property of MyClass1"

    // redefine method of parent's class
    function get_x() {
        return "Redefined method get_x() of parent's class"
    }

    function get_y() {
        return y
    }
}
obj = new MyClass1(10, 20)
// -->
function MyClass1() {
    var self = this;

    // properties
    self.c = "ccc";
    var y = "hidden property of MyClass1";

    // method get_x()
    self.get_x = function get_x() {
        return "Redefined method get_x() of parent's class";
    }

    // method get_y()
    self.get_y = function get_y() {
        return y;
    }
}
_.extend(MyClass1, Base2Class);
obj = new MyClass1(10, 20);
<|endoftext|>


<commit_before>/**
 * notify message_pusher event to clients via websocket and postMessage
 * @author codefirst
 */
(function($, document, undefined) {
    /**
     * notify message_pusher event to clients via websocket and postMessage
     * @param {Object} config.pusher message pusher object like Pusher, Keima, Socky
     * @return this
     */
    $.fn.webSocket = function(config){
        var target = this;

        var pusher = config.pusher;

        function fire(name, data){
            function isMessageEvent(name){
                return (name == "create" || name == "update" || name == "destroy");
            }

            target.trigger("websocket::"+name, data);

            if(window.postMessage) {
                window.postMessage({ 'type': name,
                                     'current': AsakusaSatellite.current,
                                     'data': data
                                   }, location.protocol+"//"+location.host);
            }
        }

        function parse(obj) {
            if(typeof(obj) == 'string') {
                return $.parseJSON(obj);
            } else {
                return obj;
            }
        }

        if (pusher == null) {
            return this;
        }

        pusher.connection.bind('connected',
            function(e) { fire('connect', e); }
        );
        pusher.connection.bind('failed',
            function(e){ fire('error', e); }
        );
        pusher.connection.bind('disconnected',
            function(e){ fire('disconnect', e); }
        );

        var channel = pusher.subscribe('as-' + config.room );
        channel.bind('message_create',
            function(obj){ fire('create', parse(obj).content); }
        );
        channel.bind('message_update',
            function(obj){ fire('update', parse(obj).content); }
        );
        channel.bind('message_delete',
            function(obj){ fire('delete', parse(obj).content); }
        );

        return this;
    }
})(jQuery, document);
<commit_msg>Fixed: WebSocket reconnection failure refs #71<commit_after>/**
 * notify message_pusher event to clients via websocket and postMessage
 * @author codefirst
 */
(function($, document, undefined) {
    /**
     * notify message_pusher event to clients via websocket and postMessage
     * @param {Object} config.pusher message pusher object like Pusher, Keima, Socky
     * @return this
     */
    $.fn.webSocket = function(config){
        var target = this;

        var pusher = config.pusher;
        var currentChannel = null;

        function fire(name, data){
            function isMessageEvent(name){
                return (name == "create" || name == "update" || name == "destroy");
            }

            target.trigger("websocket::"+name, data);

            if(window.postMessage) {
                window.postMessage({ 'type': name,
                                     'current': AsakusaSatellite.current,
                                     'data': data
                                   }, location.protocol+"//"+location.host);
            }
        }

        function parse(obj) {
            if(typeof(obj) == 'string') {
                return $.parseJSON(obj);
            } else {
                return obj;
            }
        }

        function subscribe(pusher, config) {
            var channel = pusher.subscribe('as-' + config.room);
            if (currentChannel != channel) {
                 currentChannel = channel;
                 channel.bind('message_create',
                     function(obj){ fire('create', parse(obj).content); }
                 );
                 channel.bind('message_update',
                     function(obj){ fire('update', parse(obj).content); }
                 );
                 channel.bind('message_delete',
                     function(obj){ fire('delete', parse(obj).content); }
                 );
            }
        }

        if (pusher == null) {
            return this;
        }

        pusher.connection.bind('connected',
            function(e) {
                subscribe(pusher, config);
                fire('connect', e);
            }
        );
        pusher.connection.bind('failed',
            function(e){ fire('error', e); }
        );
        pusher.connection.bind('disconnected',
            function(e){ fire('disconnect', e); }
        );

        return this;
    }
})(jQuery, document);
<|endoftext|>


<commit_before>import React, { Component } from "react";
import { Button } from "react-bootstrap";
import { updateIntl } from "react-intl-redux";
import { connect } from "react-redux";

import { selectIntl } from "../selectors";

class LocaleSelector extends Component {
  selectLocale = locale => {
    const { updateIntl } = this.props;

    updateIntl({
      locale,
      messages: require(`../i18n/locales/${locale}.json`)[locale]
    });
  };

  render() {
    return (

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("id")}
          >
            Bahasa Indonesia
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("de")}
          >
            Deutsch
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("en")}
          >
            English
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("es")}
          >
            Español
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("fr")}
          >
            Français
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("it")}
          >
            Italiano
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("nl_NL")}
          >
            Nederlands
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("pt")}
          >
            Português
          </Button>

    );
  }
}

const mapStateToProps = state => ({
  intl: selectIntl(state)
});

export default connect(mapStateToProps, { updateIntl })(LocaleSelector);
<commit_msg>Use default strings if locale doesn't include any<commit_after>import React, { Component } from "react";
import { Button } from "react-bootstrap";
import { updateIntl } from "react-intl-redux";
import { connect } from "react-redux";

import { selectIntl } from "../selectors";

class LocaleSelector extends Component {
  selectLocale = locale => {
    const { updateIntl } = this.props;

    try {
      updateIntl({
        locale,
        messages: require(`../i18n/locales/${locale}.json`)[locale]
      });
    } catch (err) {
      updateIntl({
        locale
      });
    }
  };

  render() {
    return (

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("id")}
          >
            Bahasa Indonesia
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("de")}
          >
            Deutsch
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("en")}
          >
            English
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("es")}
          >
            Español
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("fr")}
          >
            Français
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("it")}
          >
            Italiano
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("nl_NL")}
          >
            Nederlands
          </Button>

          <Button
            type="button"
            bsStyle="link"
            onClick={() => this.selectLocale("pt")}
          >
            Português
          </Button>

    );
  }
}

const mapStateToProps = state => ({
  intl: selectIntl(state)
});

export default connect(mapStateToProps, { updateIntl })(LocaleSelector);
<|endoftext|>


<commit_before>/* Import mongoose and define any variables needed to create the schema */
var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

/* Create your schema */
var blankRubricSchema = new Schema({
  presentationType: {
    type: String,
    required: true
  },
  instructions: {
    type: String,
    required: true
  },
  //not sure if this below, for ratedItems will work... Try and see see
  ratedItems: {
    itemCategory: {
    	type: String,
    	required: true
    }
    description1: String,
    description2: String,
    description3: String
  },
  created_at: Date,
  updated_at: Date
});

/* create a 'pre' function that adds the updated_at (and created_at if not already there) property */
blankRubricSchema.pre('save', function(next) {
  var currentTime = new Date;
  this.updated_at = currentTime;
  if(!this.created_at)
  {
    this.created_at = currentTime;
  }
  next();
});

/* Use your schema to instantiate a Mongoose model */
var BlankRubric = mongoose.model('BlankRubric', blankRubricSchema);

/* Export the model to make it avaiable to other parts of your Node application */
module.exports = BlankRubric;

<commit_msg>Delete blankRubric-review.server.model.js<commit_after><|endoftext|>


<commit_before>
identity = function(x) { return x; };

acc = function(key) {
  if (!key) {
    return identity;
  }
  if (typeof key == 'string') {
    return acc(key.split('.'));
  }
  return key.reduce(function(soFar, next) {
    return function(x) {
      var sf = soFar(x);
      return sf ? sf[next] : undefined;
    };
  }, function(x) { return x; });
};

//makeCmpFn = function(key) {
//  var fn = null;
//  if (typeof key == 'function') {
//    fn = key;
//  } else if (typeof key == 'string') {
//    fn = acc(key);
//  } else {
//    throw new Error("Can't sort by: " + key);
//  }
//  return function(a, b) {
//    var fna = fn(a);
//    var fnb = fn(b);
//    if (fna < fnb || fna === undefined) return -1;
//    if (fna > fnb || fnb === undefined) return 1;
//    return 0;
//  }
//};

<commit_msg>some fn helpers<commit_after>
identity = function(x) { return x; };

acc = function(key) {
  if (!key) {
    return identity;
  }
  if (typeof key == 'string') {
    return acc(key.split('.'));
  }
  return key.reduce(function(soFar, next) {
    return function(x) {
      var sf = soFar(x);
      return sf ? sf[next] : undefined;
    };
  }, function(x) { return x; });
};

function getKeys(o) {
  var keys = [];
  for (var k in o) keys.push(k);
  return keys;
}

function arrEq(a1, a2) {
  if (a1.length != a2.length) return false;
  for (var i = 0; i < a1.length; i++) {
    if (a1[i] != a2[i]) return false;
  }
  return true;
}

function sameKeys(o1, o2) {
  if (!o1 && !o2) return true;
  if (!o1 || !o2) return false;
  return arrEq(getKeys(o1), getKeys(o2));
}

<|endoftext|>


<commit_before>(function($) {

	$.fn.scrollPagination = function(options) {

		var settings = {
			per_page: 10, // The number of posts per scroll to be loaded
			page    : 1, // The page
			error   : 'No More Posts!', // When the user reaches the end this is the message that is
			                            // displayed. You can change this if you want.
			delay   : 500, // When you scroll down the posts will load after a delayed amount of time.
			               // This is mainly for usability concerns. You can alter this as you see fit
			scroll  : true // The main bit, if set to false posts will not load as the user scrolls.
			               // but will still load if the user clicks.
		};

		// Extend the options so they work with the plugin
		if(options) {
			$.extend(settings, options);
		}

		// For each so that we keep chainability.
		return this.each(function() {

			// Some variables
			$this = $(this);
			$settings = settings;
			var page = $settings.page;
			var busy = false; // Checks if the scroll action is happening
			                  // so we don't run it multiple times

            if(settings.scroll == true) initmessage = 'Cargando... Por favor, espera ';
            else initmessage = 'Click for more';

			function getData()
            {
                $('#loading-bar').remove();
                $this.append("
" +initmessage+'
');

                $.ajax({
                    url: '/comentarios/administracion',
                    method: 'GET',
                    data: $('#filtro_form').serialize() + '&por_pagina=' + $settings.per_page + '&pagina=' + (page + 1) + '&comentario[ajax]=1'

                }).done(function(data) {
                    // Change loading bar content (it may have been altered)
                    $('#loading-bar').html(initmessage);

                    // If there is no data returned, there are no more posts to be shown. Show error
                    if(data == "")
                        $('#loading-bar').html(settings.error);
                    else {

                        // page increases
                        page++;

                        // Append the data to the content div
                        $this.append(data);
                        $('#loading-bar').remove();

                        // No longer busy!
                        busy = false;
                    }
                });
			}

			// If scrolling is enabled
			if($settings.scroll == true) {
				// .. and the user is scrolling
				$(window).scroll(function() {

					// Check the user is at the bottom of the element
                    if($(window).scrollTop() + $(window).height() == $(document).height() && !settings.busy) {

						// Now we are working, so busy is true
						busy = true;

                        // Tell the user we're loading posts
                        $('#loading-bar').html('Cargando ...');

						// Run the function to fetch the data inside a delay
						// This is useful if you have content in a footer you
						// want the user to see.
						setTimeout(function() {

							getData();

						}, $settings.delay);

					}
				});
			}

			// Also content can be loaded by clicking the loading bar/
			$this.find('#loading-bar').click(function() {

				if(busy == false) {
					busy = true;
					getData();
				}

			});

		});
	}

})(jQuery);
<commit_msg>puede ser q el tamaño de la ventana devuelva flotante, entonces solicitamos el entero siguiente para q la condicional se cumpla y active el scrolling, sucede cuando hay zoom (en los comentarios)<commit_after>(function($) {

	$.fn.scrollPagination = function(options) {

		var settings = {
			per_page: 10, // The number of posts per scroll to be loaded
			page    : 1, // The page
			error   : 'No More Posts!', // When the user reaches the end this is the message that is
			                            // displayed. You can change this if you want.
			delay   : 500, // When you scroll down the posts will load after a delayed amount of time.
			               // This is mainly for usability concerns. You can alter this as you see fit
			scroll  : true // The main bit, if set to false posts will not load as the user scrolls.
			               // but will still load if the user clicks.
		};

		// Extend the options so they work with the plugin
		if(options) {
			$.extend(settings, options);
		}

		// For each so that we keep chainability.
		return this.each(function() {

			// Some variables
			$this = $(this);
			$settings = settings;
			var page = $settings.page;
			var busy = false; // Checks if the scroll action is happening
			                  // so we don't run it multiple times

            if(settings.scroll == true) initmessage = 'Cargando... Por favor, espera ';
            else initmessage = 'Click for more';

			function getData()
            {
                $('#loading-bar').remove();
                $this.append("
" +initmessage+'
');

                $.ajax({
                    url: '/comentarios/administracion',
                    method: 'GET',
                    data: $('#filtro_form').serialize() + '&por_pagina=' + $settings.per_page + '&pagina=' + (page + 1) + '&comentario[ajax]=1'

                }).done(function(data) {
                    // Change loading bar content (it may have been altered)
                    $('#loading-bar').html(initmessage);

                    // If there is no data returned, there are no more posts to be shown. Show error
                    if(data == "")
                        $('#loading-bar').html(settings.error);
                    else {

                        // page increases
                        page++;

                        // Append the data to the content div
                        $this.append(data);
                        $('#loading-bar').remove();

                        // No longer busy!
                        busy = false;
                    }
                });
			}

			// If scrolling is enabled
			if($settings.scroll == true) {
				// .. and the user is scrolling
				$(window).scroll(function() {

					// Check the user is at the bottom of the element
                    if(Math.ceil($(window).scrollTop()) + $(window).height() == $(document).height() && !settings.busy) {

						// Now we are working, so busy is true
						busy = true;

                        // Tell the user we're loading posts
                        $('#loading-bar').html('Cargando ...');

						// Run the function to fetch the data inside a delay
						// This is useful if you have content in a footer you
						// want the user to see.
						setTimeout(function() {

							getData();

						}, $settings.delay);

					}
				});
			}

			// Also content can be loaded by clicking the loading bar/
			$this.find('#loading-bar').click(function() {

				if(busy == false) {
					busy = true;
					getData();
				}

			});

		});
	}

})(jQuery);
<|endoftext|>


<commit_before>Teikei.module("Places", function(Places, App, Backbone, Marionette, $, _) {

  Places.MapView = Marionette.ItemView.extend({

    element: "#map",

    markers: [],

    initialize: function() {
      this.collection.once("reset", this.initMap, this);
      this.collection.bind("change", this.updateMap, this);
    },

    showTip: function(id) {
      var marker = _.find(this.markers, function(item){
        return Number(id) === item.model.id;
      });
      this.initTip(marker);
    },

    initTip: function(marker) {
      if (marker === undefined) {
        return;
      }
      var model = marker.model;
      var mapItemView = new Places.MapItemView({model: model});
      mapItemView.render();
      marker.bindPopup(mapItemView.el, {offset: L.point(0, -55)});
      marker.openPopup();

      this.listenTo(mapItemView, "select:details", function(){
        this.trigger("select:details", model.id, model.get("type"));
      }, this);

      this.listenTo(mapItemView, "select:network", function(){
        this.trigger("select:network", model.id, model.get("type"));
      }, this);
    },

    updateMap: function(model) {
      console.log("CHANGE", model)
      this.markerLayer.clearLayers();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map.addLayer(this.markerLayer);
    },

    hilightMarkers: function(places) {
      var bounds = [];
      _.each(this.markers, function(marker) {
        marker.setOpacity(0.3);
        _.each(places, function(place){
          if (place.id === marker.model.id) {
            marker.setOpacity(1);
            bounds.push(marker.getLatLng());
          }
        });
      });
      this.map.fitBounds(bounds);
    },

    drawNetwork: function(places) {
      var networkLayer = this.networkLayer;
      var farms = _.filter(places, function(item) {
        return item.type === "Farm";
      });
      var depots = _.filter(places, function(item) {
        return item.type === "Depot";
      });

      _.each(farms, function(farm) {
        _.each(depots, function(depot) {
          var latlngs = [
            new L.LatLng(farm.latitude, farm.longitude),
            new L.LatLng(depot.latitude, depot.longitude)
          ];
          var polyline = L.polyline(latlngs, {color: '#a00e46', weight: 2});
          polyline.addTo(networkLayer);
        });
      });
    },

    hilightNetwork: function(model) {
      var places = _.map(model.get("places"), function(item) {
        return item.place;
      });
      places.push(model.attributes);
      this.drawNetwork(places);
      this.hilightMarkers(places);
    },

    unHilightNetwork: function() {
      _.each(this.markers, function(marker) {
        _.defer(function(){
          marker.setOpacity(1);
        });
      });
      this.networkLayer.clearLayers();
      Backbone.history.navigate('/');
    },

    showArea: function(bounds) {
      this.map.fitBounds(bounds);
    },

    initMap: function() {
      this.tileLayer = this.initTileLayer();
      this.networkLayer = L.layerGroup();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map = L.map("map").setView([52.52, 13.39], 10);
      this.map.addLayer(this.tileLayer);
      this.map.addLayer(this.networkLayer);
      this.map.addLayer(this.markerLayer);
      this.map.on("popupclose", _.bind(this.unHilightNetwork, this));
    },

    initMarkerLayer: function(collection) {
      var markers = this.markers = [];
      collection.each(function(model){
        var marker = this.initMarker(model);
        if (marker) markers.push(marker);
      }, this);
      return L.layerGroup(markers);
    },

    initMarker: function(model) {
      var lat = model.get("latitude");
      var lng = model.get("longitude");
      var type = model.get("type");
      var icon = new Places.MarkerIcon[type]();

      if (lat && lng) {
        var location = new L.LatLng(lat, lng);
        var marker = L.marker(location, {icon: icon});
        marker.model = model;
        marker.on("click", _.bind(function () {
          Backbone.history.navigate('places/' + model.id + '/tip');
          this.initTip(marker);
        }, this));
        return marker;
      }
    },

    initTileLayer: function() {
      return L.tileLayer("http://{s}.tiles.mapbox.com/v3/" + Places.MapConfig.APIKEY + "/{z}/{x}/{y}.png", {
        attribution: "Map data © OpenStreetMap contributors, CC-BY-SA"
      });
    }

  });
});
<commit_msg>Make sure the map is updated when an item is added.<commit_after>Teikei.module("Places", function(Places, App, Backbone, Marionette, $, _) {

  Places.MapView = Marionette.ItemView.extend({

    element: "#map",

    markers: [],

    initialize: function() {
      this.collection.once("reset", this.initMap, this);
      this.collection.bind("change", this.updateMap, this);
      this.collection.bind("add", this.updateMap, this);
    },

    showTip: function(id) {
      var marker = _.find(this.markers, function(item){
        return Number(id) === item.model.id;
      });
      this.initTip(marker);
    },

    initTip: function(marker) {
      if (marker === undefined) {
        return;
      }
      var model = marker.model;
      var mapItemView = new Places.MapItemView({model: model});
      mapItemView.render();
      marker.bindPopup(mapItemView.el, {offset: L.point(0, -55)});
      marker.openPopup();

      this.listenTo(mapItemView, "select:details", function(){
        this.trigger("select:details", model.id, model.get("type"));
      }, this);

      this.listenTo(mapItemView, "select:network", function(){
        this.trigger("select:network", model.id, model.get("type"));
      }, this);
    },

    updateMap: function(model) {
      console.log("CHANGE", model)
      this.markerLayer.clearLayers();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map.addLayer(this.markerLayer);
    },

    hilightMarkers: function(places) {
      var bounds = [];
      _.each(this.markers, function(marker) {
        marker.setOpacity(0.3);
        _.each(places, function(place){
          if (place.id === marker.model.id) {
            marker.setOpacity(1);
            bounds.push(marker.getLatLng());
          }
        });
      });
      this.map.fitBounds(bounds);
    },

    drawNetwork: function(places) {
      var networkLayer = this.networkLayer;
      var farms = _.filter(places, function(item) {
        return item.type === "Farm";
      });
      var depots = _.filter(places, function(item) {
        return item.type === "Depot";
      });

      _.each(farms, function(farm) {
        _.each(depots, function(depot) {
          var latlngs = [
            new L.LatLng(farm.latitude, farm.longitude),
            new L.LatLng(depot.latitude, depot.longitude)
          ];
          var polyline = L.polyline(latlngs, {color: '#a00e46', weight: 2});
          polyline.addTo(networkLayer);
        });
      });
    },

    hilightNetwork: function(model) {
      var places = _.map(model.get("places"), function(item) {
        return item.place;
      });
      places.push(model.attributes);
      this.drawNetwork(places);
      this.hilightMarkers(places);
    },

    unHilightNetwork: function() {
      _.each(this.markers, function(marker) {
        _.defer(function(){
          marker.setOpacity(1);
        });
      });
      this.networkLayer.clearLayers();
      Backbone.history.navigate('/');
    },

    showArea: function(bounds) {
      this.map.fitBounds(bounds);
    },

    initMap: function() {
      this.tileLayer = this.initTileLayer();
      this.networkLayer = L.layerGroup();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map = L.map("map").setView([52.52, 13.39], 10);
      this.map.addLayer(this.tileLayer);
      this.map.addLayer(this.networkLayer);
      this.map.addLayer(this.markerLayer);
      this.map.on("popupclose", _.bind(this.unHilightNetwork, this));
    },

    initMarkerLayer: function(collection) {
      var markers = this.markers = [];
      collection.each(function(model){
        var marker = this.initMarker(model);
        if (marker) markers.push(marker);
      }, this);
      return L.layerGroup(markers);
    },

    initMarker: function(model) {
      var lat = model.get("latitude");
      var lng = model.get("longitude");
      var type = model.get("type");
      var icon = new Places.MarkerIcon[type]();

      if (lat && lng) {
        var location = new L.LatLng(lat, lng);
        var marker = L.marker(location, {icon: icon});
        marker.model = model;
        marker.on("click", _.bind(function () {
          Backbone.history.navigate('places/' + model.id + '/tip');
          this.initTip(marker);
        }, this));
        return marker;
      }
    },

    initTileLayer: function() {
      return L.tileLayer("http://{s}.tiles.mapbox.com/v3/" + Places.MapConfig.APIKEY + "/{z}/{x}/{y}.png", {
        attribution: "Map data © OpenStreetMap contributors, CC-BY-SA"
      });
    }

  });
});
<|endoftext|>


<commit_before>import {proxy} from 'utils/queryUrlGenerator'
import {noop} from 'shared/actions/app'
import _ from 'lodash'

import {errorThrown} from 'shared/actions/errors'

export const handleLoading = (query, editQueryStatus) => {
  editQueryStatus(query.id, {loading: true})
}
// {results: [{}]}
export const handleSuccess = (data, query, editQueryStatus) => {
  const {results} = data
  const error = _.get(results, ['0', 'error'], false)
  const series = _.get(results, ['0', 'series'], false)
  // 200 from server and no results = warn
  if (!series && !error) {
    editQueryStatus(query.id, {
      warn: 'Your query is syntactically correct but returned no results',
    })
    return data
  }

  // 200 from chrono server but influx returns an "error" = warning
  if (error) {
    editQueryStatus(query.id, {warn: error})
    return data
  }

  // 200 from server and results contains data = success
  editQueryStatus(query.id, {success: 'Success!'})
  return data
}

export const handleError = (error, query, editQueryStatus) => {
  const message = _.get(error, ['data', 'message'], error)

  // 400 from chrono server = fail
  editQueryStatus(query.id, {error: message})
  console.error(error)
}

export const fetchTimeSeriesAsync = async (
  {source, db, rp, query, tempVars},
  editQueryStatus = noop
) => {
  handleLoading(query, editQueryStatus)
  try {
    const {data} = await proxy({
      source,
      db,
      rp,
      query: query.text,
      tempVars,
    })
    return handleSuccess(data, query, editQueryStatus)
  } catch (error) {
    errorThrown(error)
    handleError(error, query, editQueryStatus)
  }
}
<commit_msg>Fix queryEditor error handling to not allow objects.<commit_after>import {proxy} from 'utils/queryUrlGenerator'
import {noop} from 'shared/actions/app'
import _ from 'lodash'

import {errorThrown} from 'shared/actions/errors'

export const handleLoading = (query, editQueryStatus) => {
  editQueryStatus(query.id, {loading: true})
}
// {results: [{}]}
export const handleSuccess = (data, query, editQueryStatus) => {
  const {results} = data
  const error = _.get(results, ['0', 'error'], false)
  const series = _.get(results, ['0', 'series'], false)
  // 200 from server and no results = warn
  if (!series && !error) {
    editQueryStatus(query.id, {
      warn: 'Your query is syntactically correct but returned no results',
    })
    return data
  }

  // 200 from chrono server but influx returns an "error" = warning
  if (error) {
    editQueryStatus(query.id, {warn: error})
    return data
  }

  // 200 from server and results contains data = success
  editQueryStatus(query.id, {success: 'Success!'})
  return data
}

export const handleError = (error, query, editQueryStatus) => {
  const message = _.get(error, ['data', 'message'], error.toString())

  // 400 from chrono server = fail
  editQueryStatus(query.id, {error: message})
  console.error(error)
}

export const fetchTimeSeriesAsync = async (
  {source, db, rp, query, tempVars},
  editQueryStatus = noop
) => {
  handleLoading(query, editQueryStatus)
  try {
    const {data} = await proxy({
      source,
      db,
      rp,
      query: query.text,
      tempVars,
    })
    return handleSuccess(data, query, editQueryStatus)
  } catch (error) {
    errorThrown(error)
    handleError(error, query, editQueryStatus)
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 August Detlefsen. All rights reserved.
// Use of this source code is governed by an Apache-style license that can be
// found in the LICENSE file.

var urlsToGroup = [];
var alwaysGroup = true;

/**
 * Parses the domain name from the URL of the current tab.
 *
 * @param {function(string)} callback - called when the domain of the current tab
 *   is found.
 */
function getCurrentTabDomain(callback) {
  var queryInfo = {
    active: true,
    currentWindow: true
  };

  chrome.tabs.query(queryInfo, function(tabs) {
    // A window can only have one active tab at a time, so the array consists of
    // exactly one tab.
    var tab = tabs[0];

    // Get the tab URL
    var url = tab.url;

    //get the domain from the URL
    var domain = url.match(/^[\w-]+:\/{2,}\[?([\w\.:-]+)\]?(?::[0-9]*)?/)[1];

    callback(domain);
  });
}

/**
 * Groups all tabs with URLs matching a pattern into the same window
 */
function groupTabs(urlPattern) {
  console.log("groupTabs: " + urlPattern);

  //check if we already have a window for this pattern
  getTabWindow(urlPattern, function(tabWindow){
    console.log("groupTabs: tabWindow: " + JSON.stringify(tabWindow));

    //get the tabs that match the URL pattern
    chrome.tabs.query({url:urlPattern}, function(tabs) {
      if (tabWindow) {
        moveTabs(tabs, tabWindow);

        //focus the window
        chrome.windows.update(tabWindow.id,{focused:true});

      } else {
        //no existing window for this pattern so create a new window
        var tabId = (tabs.length > 0) ? tabs[0].id : null;
        chrome.windows.create({"tabId":tabId}, function(window){

          console.log("window: " + JSON.stringify(window));

          //remove the first element from the tabs array -it has already been added to the window
          //tabs.splice(0,1);
          console.log("tabs: " + JSON.stringify(tabs));

          moveTabs(tabs, window);
          console.log("moveTabs done");

          //focus the window
          chrome.windows.update(window.id,{focused:true});
          console.log("window focused");

          //remember the URL pattern and the new window it was grouped into
          chrome.storage.local.get({urlsToGroup: []}, function(items){
            items.urlsToGroup.push({"urlPattern":urlPattern,"window":window.id});
            console.log("NEW urlsToGroup: " + JSON.stringify(items.urlsToGroup));
            chrome.storage.local.set({"urlsToGroup":items.urlsToGroup});
          })
        });
      }

      console.log("urlsToGroup(2): " + JSON.stringify(urlsToGroup));  });
  });
}

function removeGroup(urlPattern) {
    chrome.storage.local.get({urlsToGroup: []}, function(items) {
      console.log("removeGroup(" + urlPattern + ")");
      var newUrls = items.urlsToGroup.filter(function(el) {
        console.log("el: " + JSON.stringify(el));
        return el.urlPattern != urlPattern;
      });

      chrome.storage.local.set({"urlsToGroup":newUrls});
      console.log("removeGroup(): " + JSON.stringify(newUrls));
    });
}

/**
 * Gets the window that a particular tab should be grouped into:
 *
 * 1. If a window exists for the passed match rule the callback is executed on that window
 * 2. If there is an existing match rule but the window no longer exists a new window will be created
 * 3. Otherwise return null
 */
function getTabWindow(tabUrl, callback) {
  console.log("getTabWindow: " + tabUrl);

  //are we dealing with a new regex?

  var match = false;
  for (var i = 0; i < urlsToGroup.length; i++) {
    var rule = urlsToGroup[i];
    console.log("rule: " + JSON.stringify(rule));
    if (matchRuleShort(tabUrl, rule.urlPattern)) {
      //the new tab URL matches an existing group.
      console.log("MATCH!");
      match = true;
      //check that the window still exists
      chrome.windows.get(rule.window, {populate:true}, function(foundWindow){
        if (foundWindow) {
          console.log("FOUND! " + foundWindow);
          callback(foundWindow);
        } else {
          //create a new window with the new tab
          chrome.windows.create({}, function(newWindow){ //"tabId":tab.id
            console.log("CREATED NEW! " + JSON.stringify(newWindow));

            //reassign the group pattern to the new window
            rule.window = newWindow.id
            chrome.storage.local.set({"urlsToGroup":urlsToGroup});

            callback(newWindow);
          });
        }
      });
    }
  }

  if (!match) {
    callback(null);
  }
}

/**
 * Move an array of tabs to a destination window
 */
function moveTabs(tabs, destination) {
  for (var i = 0; i < tabs.length; i++) {
    var tab = tabs[i];
    chrome.tabs.move(tab.id, {windowId:destination.id,index:-1});
  }
}

/**
 * Shorthand function to match a wildcard (*) string
 */
function matchRuleShort(str, rule) {
  return new RegExp("^" + rule.split("*").join(".*") + "$").test(str);
}

/**
 * Add a listener for tab update events
 */
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  console.log("chrome.tabs.onUpdated: status: " + changeInfo.status + " url: " + changeInfo.url);
  if (alwaysGroup && typeof changeInfo.url != 'undefined') {
    console.log("alwaysGroup");

    chrome.storage.local.get({urlsToGroup: []}, function(items) {

      let rules = items.urlsToGroup.filter(rule => matchRuleShort(changeInfo.url, rule.urlPattern));
      console.log("rules: " + JSON.stringify(rules));
      if (rules.length < 1) return; //no matching rule for this URL, nothing to do

      //TODO: How do we distinguish between multiple match rules on the same domain? find the longest match rule?
      var rule = rules[0];
      //the new tab URL matches an existing group.
      console.log("match!");

      //check that the window still exists
      chrome.windows.get(rule.window, {populate:true}, function(foundWindow){
        console.log("foundWindow: " + JSON.stringify(foundWindow));
        if (foundWindow) {
          //Check for whether the new URL matches an existing tab
          //separate fragment for proper search matching
          var searchUrl  = changeInfo.url.split('#')[0];
          var searchFrag = changeInfo.url.split('#')[1];
          console.log("searchFrag: " + searchFrag);

          //TODO: how do we handle GET query params on the same URL? For example, ?ts=78123768

          console.log("chrome.tabs.query() params: " + searchUrl);
          chrome.tabs.query({"url":searchUrl,"windowId":foundWindow.id},function(tabs){
            console.log("chrome.tabs.query() result: (" + tabs.length + ")" + JSON.stringify(tabs));
            tabs = tabs.filter(t => t.id != tab.id);

            if (tabs.length > 0 && tabs[0].status === "complete") {
              for (var t = 0; t < tabs.length; t++) {
                var foundTab = tabs[t];
                console.log("checking foundTab in tabs: " + JSON.stringify(foundTab));

                var tabFrag = foundTab.url.split('#')[1];
                console.log("tabFrag: " + tabFrag);

                if (searchFrag == tabFrag) {
                  console.log("searchFrag == tabFrag");

                  //focus the existing tab with the same URL
                  //TODO: Make this configurable
                  focusTab(foundWindow.id, foundTab.id); //tabs[0]);

                  //reload to pick up new changes
                  chrome.tabs.reload(foundTab.id); //tabs[0].id);

                  //no need for the new tab
                  chrome.tabs.remove(tab.id);
                }
              }
            } else {
              //open the new tab in the group window
              chrome.tabs.move(tab.id, {windowId:foundWindow.id,index:-1});

              //focus the newly created tab
              focusTab(foundWindow.id, tab.id);
            }
          });

        } else {
          console.log("NOT foundWindow");
          //create a new window with the new tab
          chrome.windows.create({"tabId":tab.id}, function(newWindow){
            console.log("New window created: " + newWindow.id + " rule: " + JSON.stringify(rule));

            //reassign the group pattern to the new window
            rule.window = newWindow.id

            console.log("NEW urlsToGroup: " + JSON.stringify(items.urlsToGroup));
            chrome.storage.local.set({"urlsToGroup":items.urlsToGroup});

            //focus the newly created tab
            focusTab(newWindow.id, tab.id);
          });
        }
      }); // END chrome.windows.get
    });
  }
});

/**
 * Give focus to a particular tab
 */
function focusTab(window, tab) {
  console.log("focusTab("+ JSON.stringify(window) +", " + JSON.stringify(tab) + ")");
  chrome.windows.update(window,{focused:true}, function(window) {
    chrome.tabs.update(tab, {selected:true});
  });
}

/**
 * Add context menus at startup:
 * - Allow selecting partial URLs with wildcard
 * - Checkbox to determine whether to always group new tabs that match
 */
chrome.runtime.onInstalled.addListener(function() {
  chrome.contextMenus.create({"title": "Specify Tab URLs to Group",
                              "contexts":["all"],
                              "id": "groupTabsContext"});
  chrome.contextMenus.create({"title": "Always Group New Tabs",
                              "contexts":["all"],
                              "id": "groupTabsAlways",
                              "type": "checkbox",
                              "checked": alwaysGroup});
});

/**
 * Click handler for context menu items.
 */
chrome.contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId === "groupTabsContext") {
      groupTabsContextOnClick(info.pageUrl, tab)
    } else if (info.menuItemId === "groupTabsAlways") {
      groupTabsAlwaysOnClick(info,tab);
    }
});

/**
 * Callback function activated when the context menu item is clicked
 */
function groupTabsContextOnClick(pageUrl, tab) {
  var regex = window.prompt('Enter URL regex to group (Use * for wildcard)', pageUrl);
  if (regex) groupTabs(regex);
}

/**
 * Callback function activated when the context menu item is clicked
 */
function groupTabsAlwaysOnClick(info, tab) {
  alwaysGroup = info.checked;
}
<commit_msg>Skip pinned tabs<commit_after>// Copyright (c) 2019 August Detlefsen. All rights reserved.
// Use of this source code is governed by an Apache-style license that can be
// found in the LICENSE file.

var urlsToGroup = [];
var alwaysGroup = true;

/**
 * Parses the domain name from the URL of the current tab.
 *
 * @param {function(string)} callback - called when the domain of the current tab
 *   is found.
 */
function getCurrentTabDomain(callback) {
  var queryInfo = {
    active: true,
    currentWindow: true
  };

  chrome.tabs.query(queryInfo, function(tabs) {
    // A window can only have one active tab at a time, so the array consists of
    // exactly one tab.
    var tab = tabs[0];

    // Get the tab URL
    var url = tab.url;

    //get the domain from the URL
    var domain = url.match(/^[\w-]+:\/{2,}\[?([\w\.:-]+)\]?(?::[0-9]*)?/)[1];

    callback(domain);
  });
}

/**
 * Groups all tabs with URLs matching a pattern into the same window
 */
function groupTabs(urlPattern) {
  console.log("groupTabs: " + urlPattern);

  //check if we already have a window for this pattern
  getTabWindow(urlPattern, function(tabWindow){
    console.log("groupTabs: tabWindow: " + JSON.stringify(tabWindow));

    //get the tabs that match the URL pattern
    chrome.tabs.query({url:urlPattern}, function(tabs) {
      if (tabWindow) {
        moveTabs(tabs, tabWindow);

        //focus the window
        chrome.windows.update(tabWindow.id,{focused:true});

      } else {
        //no existing window for this pattern so create a new window
        var tabId = (tabs.length > 0) ? tabs[0].id : null;
        chrome.windows.create({"tabId":tabId}, function(window){

          console.log("window: " + JSON.stringify(window));

          //remove the first element from the tabs array -it has already been added to the window
          //tabs.splice(0,1);
          console.log("tabs: " + JSON.stringify(tabs));

          moveTabs(tabs, window);
          console.log("moveTabs done");

          //focus the window
          chrome.windows.update(window.id,{focused:true});
          console.log("window focused");

          //remember the URL pattern and the new window it was grouped into
          chrome.storage.local.get({urlsToGroup: []}, function(items){
            items.urlsToGroup.push({"urlPattern":urlPattern,"window":window.id});
            console.log("NEW urlsToGroup: " + JSON.stringify(items.urlsToGroup));
            chrome.storage.local.set({"urlsToGroup":items.urlsToGroup});
          })
        });
      }

      console.log("urlsToGroup(2): " + JSON.stringify(urlsToGroup));  });
  });
}

function removeGroup(urlPattern) {
    chrome.storage.local.get({urlsToGroup: []}, function(items) {
      console.log("removeGroup(" + urlPattern + ")");
      var newUrls = items.urlsToGroup.filter(function(el) {
        console.log("el: " + JSON.stringify(el));
        return el.urlPattern != urlPattern;
      });

      chrome.storage.local.set({"urlsToGroup":newUrls});
      console.log("removeGroup(): " + JSON.stringify(newUrls));
    });
}

/**
 * Gets the window that a particular tab should be grouped into:
 *
 * 1. If a window exists for the passed match rule the callback is executed on that window
 * 2. If there is an existing match rule but the window no longer exists a new window will be created
 * 3. Otherwise return null
 */
function getTabWindow(tabUrl, callback) {
  console.log("getTabWindow: " + tabUrl);

  //are we dealing with a new regex?

  var match = false;
  for (var i = 0; i < urlsToGroup.length; i++) {
    var rule = urlsToGroup[i];
    console.log("rule: " + JSON.stringify(rule));
    if (matchRuleShort(tabUrl, rule.urlPattern)) {
      //the new tab URL matches an existing group.
      console.log("MATCH!");
      match = true;
      //check that the window still exists
      chrome.windows.get(rule.window, {populate:true}, function(foundWindow){
        if (foundWindow) {
          console.log("FOUND! " + foundWindow);
          callback(foundWindow);
        } else {
          //create a new window with the new tab
          chrome.windows.create({}, function(newWindow){ //"tabId":tab.id
            console.log("CREATED NEW! " + JSON.stringify(newWindow));

            //reassign the group pattern to the new window
            rule.window = newWindow.id
            chrome.storage.local.set({"urlsToGroup":urlsToGroup});

            callback(newWindow);
          });
        }
      });
    }
  }

  if (!match) {
    callback(null);
  }
}

/**
 * Move an array of tabs to a destination window
 */
function moveTabs(tabs, destination) {
  for (var i = 0; i < tabs.length; i++) {
    var tab = tabs[i];
    if (tab.pinned) {
      continue; //skip pinned tabs
    }
    chrome.tabs.move(tab.id, {windowId:destination.id,index:-1});
  }
}

/**
 * Shorthand function to match a wildcard (*) string
 */
function matchRuleShort(str, rule) {
  return new RegExp("^" + rule.split("*").join(".*") + "$").test(str);
}

/**
 * Add a listener for tab update events
 */
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  console.log("chrome.tabs.onUpdated: status: " + changeInfo.status + " url: " + changeInfo.url);
  if (alwaysGroup && typeof changeInfo.url != 'undefined') {
    console.log("alwaysGroup");

    chrome.storage.local.get({urlsToGroup: []}, function(items) {

      let rules = items.urlsToGroup.filter(rule => matchRuleShort(changeInfo.url, rule.urlPattern));
      console.log("rules: " + JSON.stringify(rules));
      if (rules.length < 1) return; //no matching rule for this URL, nothing to do

      //TODO: How do we distinguish between multiple match rules on the same domain? find the longest match rule?
      var rule = rules[0];
      //the new tab URL matches an existing group.
      console.log("match!");

      //check that the window still exists
      chrome.windows.get(rule.window, {populate:true}, function(foundWindow){
        console.log("foundWindow: " + JSON.stringify(foundWindow));
        if (foundWindow) {
          //Check for whether the new URL matches an existing tab
          //separate fragment for proper search matching
          var searchUrl  = changeInfo.url.split('#')[0];
          var searchFrag = changeInfo.url.split('#')[1];
          console.log("searchFrag: " + searchFrag);

          //TODO: how do we handle GET query params on the same URL? For example, ?ts=78123768

          console.log("chrome.tabs.query() params: " + searchUrl);
          chrome.tabs.query({"url":searchUrl,"windowId":foundWindow.id},function(tabs){
            console.log("chrome.tabs.query() result: (" + tabs.length + ")" + JSON.stringify(tabs));
            tabs = tabs.filter(t => t.id != tab.id);

            if (tabs.length > 0 && tabs[0].status === "complete") {
              for (var t = 0; t < tabs.length; t++) {
                var foundTab = tabs[t];
                console.log("checking foundTab in tabs: " + JSON.stringify(foundTab));

                var tabFrag = foundTab.url.split('#')[1];
                console.log("tabFrag: " + tabFrag);

                if (searchFrag == tabFrag) {
                  console.log("searchFrag == tabFrag");

                  //focus the existing tab with the same URL
                  //TODO: Make this configurable
                  focusTab(foundWindow.id, foundTab.id); //tabs[0]);

                  //reload to pick up new changes
                  chrome.tabs.reload(foundTab.id); //tabs[0].id);

                  //no need for the new tab
                  chrome.tabs.remove(tab.id);
                }
              }
            } else {
              //open the new tab in the group window
              chrome.tabs.move(tab.id, {windowId:foundWindow.id,index:-1});

              //focus the newly created tab
              focusTab(foundWindow.id, tab.id);
            }
          });

        } else {
          console.log("NOT foundWindow");
          //create a new window with the new tab
          chrome.windows.create({"tabId":tab.id}, function(newWindow){
            console.log("New window created: " + newWindow.id + " rule: " + JSON.stringify(rule));

            //reassign the group pattern to the new window
            rule.window = newWindow.id

            console.log("NEW urlsToGroup: " + JSON.stringify(items.urlsToGroup));
            chrome.storage.local.set({"urlsToGroup":items.urlsToGroup});

            //focus the newly created tab
            focusTab(newWindow.id, tab.id);
          });
        }
      }); // END chrome.windows.get
    });
  }
});

/**
 * Give focus to a particular tab
 */
function focusTab(window, tab) {
  console.log("focusTab("+ JSON.stringify(window) +", " + JSON.stringify(tab) + ")");
  chrome.windows.update(window,{focused:true}, function(window) {
    chrome.tabs.update(tab, {selected:true});
  });
}

/**
 * Add context menus at startup:
 * - Allow selecting partial URLs with wildcard
 * - Checkbox to determine whether to always group new tabs that match
 */
chrome.runtime.onInstalled.addListener(function() {
  chrome.contextMenus.create({"title": "Specify Tab URLs to Group",
                              "contexts":["all"],
                              "id": "groupTabsContext"});
  chrome.contextMenus.create({"title": "Always Group New Tabs",
                              "contexts":["all"],
                              "id": "groupTabsAlways",
                              "type": "checkbox",
                              "checked": alwaysGroup});
});

/**
 * Click handler for context menu items.
 */
chrome.contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId === "groupTabsContext") {
      groupTabsContextOnClick(info.pageUrl, tab)
    } else if (info.menuItemId === "groupTabsAlways") {
      groupTabsAlwaysOnClick(info,tab);
    }
});

/**
 * Callback function activated when the context menu item is clicked
 */
function groupTabsContextOnClick(pageUrl, tab) {
  var regex = window.prompt('Enter URL regex to group (Use * for wildcard)', pageUrl);
  if (regex) groupTabs(regex);
}

/**
 * Callback function activated when the context menu item is clicked
 */
function groupTabsAlwaysOnClick(info, tab) {
  alwaysGroup = info.checked;
}
<|endoftext|>


<commit_before>(function($)
{
    var Dragon = function(element, options)
    {
        this.element = element;
        this.options = options;
        this.active = false;

        // Allow dragging on a specific child selector
        if(this.options.handle)
        {
            this.handle = $(this.element).find(this.options.handle).el[0];
        }
        else
        {
            this.handle = this.element;
        }

        this.init();
        this.bind();
    }

    // Initialize element before being dragged
    Dragon.prototype.init = function()
    {
        $(this.element).addClass('dragon');
        $(this.element).style({position: 'absolute'});

        // Save the current element position
        this.pos =
        {
            x: this.element.offsetLeft,
            y: this.element.offsetTop
        };

        // Remove the element's original position
        $(this.element).style({top: 0, left: 0});

        // Update the element's position
        this.update();
    }

    // Helper function to get event position
    Dragon.prototype.position = function(event)
    {
        var output = {};

        // If this is a touch event
        if(event.type.indexOf('touch') > -1)
        {
            var touch = event.touches[0] || event.changedTouches[0];

            output.x = touch.clientX;
            output.y = touch.clientY;
        }

        // Mouse events are a bit simpler
        else
        {
            output.x = event.clientX;
            output.y = event.clientY;
        }

        return output;
    }

    // Helper function to update the dragon's position
    Dragon.prototype.update = function()
    {
        // If we're doing percent based positioning
        if(this.options.units == '%')
        {
            // This is probably inaccurate in a bunch of cases?
            var parent = $(window).size('both');
            var child = $(this.element).size('both');

            // Because CSS translations in percent are based on the element's size...
            // We have to multiply the distance we move by the ratio of the size of the parent to the child
            var ratio =
            {
                x: parent.width.inner / child.width.outer,
                y: parent.height.inner / child.height.outer
            }

            var percent =
            {
                x: (this.pos.x / parent.width.inner) * 100 * ratio.x,
                y: (this.pos.y / parent.height.inner) * 100 * ratio.y
            }

            $(this.element).transform('translate', percent.x+'%', percent.y+'%');
        }
        // Otherwise, default to unit based positioning
        else
        {
            $(this.element).transform('translate', parseInt(this.pos.x)+this.options.units, parseInt(this.pos.y)+this.options.units);
        }
    }

    // Bind mouse events
    Dragon.prototype.bind = function()
    {
        // Preserve scope inside event handlers
        var drag = this;

        $(drag.element).on('mousedown touchstart', function(event)
        {
            // Ignore events on specific elements
            if(drag.options.ignore.indexOf(event.target.tagName.toLowerCase()) > -1)
                return;

            // If a handle is being used, ignore all events except on that handle
            if(drag.options.handle)
            {
                if(event.target != drag.handle)
                    return;
            }

            event.preventDefault();

            // Prevent dropping onto other dragons
            $('.dragon').style({'pointer-events': 'none'});

            $(drag.element).addClass('dragging');
            drag.active = true;

            // Find the current position
            var position = drag.position(event);

            // Save it
            drag.lastX = position.x;
            drag.lastY = position.y;

            $(drag.element).trigger('dragstart', {pos: drag.pos});
        });

        $('html').on('mousemove touchmove', function(event)
        {
            if(drag.active)
            {
                event.preventDefault();

                // Find the current position
                var position = drag.position(event);

                // Find distance we've moved
                var delta =
                {
                    x: position.x - drag.lastX,
                    y: position.y - drag.lastY
                };

                if(drag.options.grid)
                {
                    // Only update the position if we've moved more than the grid
                    if(Math.abs(delta.x) < drag.options.grid && Math.abs(delta.y) < drag.options.grid)
                    {
                        return;
                    }

                    // If we've moved more than the grid, make sure we move along it
                    delta.x -= (delta.x % drag.options.grid);
                    delta.y -= (delta.y % drag.options.grid);
                }

                // Update the saved element position
                if(drag.options.axis == 'x' || drag.options.axis === undefined)
                {
                    drag.pos.x += delta.x;
                }

                if(drag.options.axis == 'y' || drag.options.axis === undefined)
                {
                    drag.pos.y += delta.y;
                }

                drag.update();

                // Save the current position
                drag.lastX = position.x;
                drag.lastY = position.y;

                $(drag.element).trigger('dragmove', {pos: drag.pos});
            }
        });

        $('html').on('mouseup touchend touchcancel', function(event)
        {
            if(drag.active)
            {
                // Find the current position
                var position = drag.position(event);

                // Touch events always return the original target, so we have to calculate where you moved to
                if(event.type.indexOf('touch') > -1)
                {
                    var target = document.elementFromPoint(position.x, position.y);
                }
                else
                {
                    var target = event.target;
                }

                // If we dropped into a droppable element
                if($(target).hasClass('droppable'))
                {
                    // And the target is somewhere new
                    if(drag.element.parentNode != target)
                    {
                        var from = drag.element.parentNode;

                        // Move the dragon into the droppable target
                        target.appendChild(drag.element);

                        // Recenter based on the current pointer position
                        var size = $(drag.element).size('outer');

                        drag.pos.x = position.x - size.width / 2;
                        drag.pos.y = position.y - size.height / 2;

                        drag.update();
                        $(drag.element).trigger('drop', {from: from, to: target, pos: drag.pos});
                    }
                }

                $(drag.element).removeClass('dragging');
                drag.active = false;

                $(drag.element).trigger('dragend', {pos: drag.pos});

                // Re-enable pointer-events
                $('.dragon').style({'pointer-events': 'auto'});
            }
        });

        // Event to allow 3rd party scripts to reset the dragon's position
        $(drag.element).on('dragreset', function(event)
        {
            drag.pos.x = 0;
            drag.pos.y = 0;
            drag.update();
        });
    }

    // Wetfish basic wrapper
    $.prototype.dragondrop = function(options)
    {
        // By default use these options
        var defaults =
        {
            // Ignore clicks on specific elements
            ignore: ['input', 'textarea', 'button', 'select', 'option'],
            units: 'px'
        };

        if(typeof options == "object")
        {
            // Merge user options into defaults
            for(var property in defaults)
            {
                if(options[property] === undefined)
                {
                    options[property] = defaults[property];
                }
            }
        }
        else
        {
            options = defaults;
        }

        this.forEach(this.elements, function(index, element)
        {
            new Dragon(element, options);
        });
    }
}(basic));
<commit_msg>Added static positioning option<commit_after>(function($)
{
    var Dragon = function(element, options)
    {
        this.element = element;
        this.options = options;
        this.active = false;

        // Allow dragging on a specific child selector
        if(this.options.handle)
        {
            this.handle = $(this.element).find(this.options.handle).el[0];
        }
        else
        {
            this.handle = this.element;
        }

        this.init();
        this.bind();
    }

    // Initialize element before being dragged
    Dragon.prototype.init = function()
    {
        $(this.element).addClass('dragon');

        // Create position object
        this.pos = {x: 0, y: 0};

        // If we're using absolute positioning
        if(this.options.position == 'absolute')
        {
            // Save the current element position
            this.pos.x = this.element.offsetLeft;
            this.pos.y = this.element.offsetTop;

            $(this.element).style({position: 'absolute'});

            // Remove the element's original position
            $(this.element).style({top: 0, left: 0});

            // Update the element's position
            this.update();
        }
    }

    // Helper function to get event position
    Dragon.prototype.position = function(event)
    {
        var output = {};

        // If this is a touch event
        if(event.type.indexOf('touch') > -1)
        {
            var touch = event.touches[0] || event.changedTouches[0];

            output.x = touch.clientX;
            output.y = touch.clientY;
        }

        // Mouse events are a bit simpler
        else
        {
            output.x = event.clientX;
            output.y = event.clientY;
        }

        return output;
    }

    // Helper function to update the dragon's position
    Dragon.prototype.update = function()
    {
        // If we're doing percent based positioning
        if(this.options.units == '%')
        {
            // This is probably inaccurate in a bunch of cases?
            var parent = $(window).size('both');
            var child = $(this.element).size('both');

            // Because CSS translations in percent are based on the element's size...
            // We have to multiply the distance we move by the ratio of the size of the parent to the child
            var ratio =
            {
                x: parent.width.inner / child.width.outer,
                y: parent.height.inner / child.height.outer
            }

            var percent =
            {
                x: (this.pos.x / parent.width.inner) * 100 * ratio.x,
                y: (this.pos.y / parent.height.inner) * 100 * ratio.y
            }

            $(this.element).transform('translate', percent.x+'%', percent.y+'%');
        }
        // Otherwise, default to unit based positioning
        else
        {
            $(this.element).transform('translate', parseInt(this.pos.x)+this.options.units, parseInt(this.pos.y)+this.options.units);
        }
    }

    // Bind mouse events
    Dragon.prototype.bind = function()
    {
        // Preserve scope inside event handlers
        var drag = this;

        $(drag.element).on('mousedown touchstart', function(event)
        {
            // Ignore events on specific elements
            if(drag.options.ignore.indexOf(event.target.tagName.toLowerCase()) > -1)
                return;

            // If a handle is being used, ignore all events except on that handle
            if(drag.options.handle)
            {
                if(event.target != drag.handle)
                    return;
            }

            event.preventDefault();

            // Prevent dropping onto other dragons
            $('.dragon').style({'pointer-events': 'none'});

            $(drag.element).addClass('dragging');
            drag.active = true;

            // Find the current position
            var position = drag.position(event);

            // Save it
            drag.lastX = position.x;
            drag.lastY = position.y;

            $(drag.element).trigger('dragstart', {pos: drag.pos});
        });

        $('html').on('mousemove touchmove', function(event)
        {
            if(drag.active)
            {
                event.preventDefault();

                // Find the current position
                var position = drag.position(event);

                // Find distance we've moved
                var delta =
                {
                    x: position.x - drag.lastX,
                    y: position.y - drag.lastY
                };

                if(drag.options.grid)
                {
                    // Only update the position if we've moved more than the grid
                    if(Math.abs(delta.x) < drag.options.grid && Math.abs(delta.y) < drag.options.grid)
                    {
                        return;
                    }

                    // If we've moved more than the grid, make sure we move along it
                    delta.x -= (delta.x % drag.options.grid);
                    delta.y -= (delta.y % drag.options.grid);
                }

                // Update the saved element position
                if(drag.options.axis == 'x' || drag.options.axis === undefined)
                {
                    drag.pos.x += delta.x;
                }

                if(drag.options.axis == 'y' || drag.options.axis === undefined)
                {
                    drag.pos.y += delta.y;
                }

                drag.update();

                // Save the current position
                drag.lastX = position.x;
                drag.lastY = position.y;

                $(drag.element).trigger('dragmove', {pos: drag.pos});
            }
        });

        $('html').on('mouseup touchend touchcancel', function(event)
        {
            if(drag.active)
            {
                // Find the current position
                var position = drag.position(event);

                // Touch events always return the original target, so we have to calculate where you moved to
                if(event.type.indexOf('touch') > -1)
                {
                    var target = document.elementFromPoint(position.x, position.y);
                }
                else
                {
                    var target = event.target;
                }

                // If we dropped into a droppable element
                if($(target).hasClass('droppable'))
                {
                    // And the target is somewhere new
                    if(drag.element.parentNode != target)
                    {
                        var from = drag.element.parentNode;

                        // Move the dragon into the droppable target
                        target.appendChild(drag.element);

                        // Recenter based on the current pointer position
                        var size = $(drag.element).size('outer');

                        drag.pos.x = position.x - size.width / 2;
                        drag.pos.y = position.y - size.height / 2;

                        drag.update();
                        $(drag.element).trigger('drop', {from: from, to: target, pos: drag.pos});
                    }
                }

                $(drag.element).removeClass('dragging');
                drag.active = false;

                $(drag.element).trigger('dragend', {pos: drag.pos});

                // Re-enable pointer-events
                $('.dragon').style({'pointer-events': 'auto'});
            }
        });

        // Event to allow 3rd party scripts to reset the dragon's position
        $(drag.element).on('dragreset', function(event)
        {
            drag.pos.x = 0;
            drag.pos.y = 0;
            drag.update();
        });
    }

    // Wetfish basic wrapper
    $.prototype.dragondrop = function(options)
    {
        // By default use these options
        var defaults =
        {
            // Ignore clicks on specific elements
            ignore: ['input', 'textarea', 'button', 'select', 'option'],
            position: 'absolute',
            units: 'px',
        };

        if(typeof options == "object")
        {
            // Merge user options into defaults
            for(var property in defaults)
            {
                if(options[property] === undefined)
                {
                    options[property] = defaults[property];
                }
            }
        }
        else
        {
            options = defaults;
        }

        this.forEach(this.elements, function(index, element)
        {
            new Dragon(element, options);
        });
    }
}(basic));
<|endoftext|>


<commit_before>/* Copyright (C) 2011  Lincoln de Sousa <lincoln@comum.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var navapi = null;

$(function () {
   $("#question-writer").ghost_typer({
     text:'Como podemos melhorar o atendimento na saúde pública?',
     speed: 80
   });

    var wizard = $('.wizard').data('isLoaded', false);

    $("ol.tabs", wizard).tabs(
        "div.panes > div", {
            effect: 'fade',
            lazy: true,
            onBeforeClick: function () {
                if (wizard.data('isLoaded')) {
                    $('html,body').animate({ scrollTop: 320 }, 150);
                }
            }
        });
    wizard.data('isLoaded', true);

    navapi = $("ol.tabs", wizard).data("tabs");

    // "next tab" button
    $(".next", wizard).click(function () {
        $('html,body').animate({ scrollTop: 320 }, 100);
	navapi.next();
    });

    // "previous tab" button
    $(".prev", wizard).click(function () {
        $('html,body').animate({ scrollTop: 320 }, 100);
	navapi.prev();
    });

    /* -- Setting up the per-theme description overlays --*/
    (function () {
        $('a.theme').overlay({
            top: '10%',
            speed: 'fast',
            fixed: false,
            oneInstance: false,
            mask: {
                color: '#111',
                opacity: 0.7
            }
        }).click(function () {
            themeapi.change(
                $(this).parent().attr('class'),
                $(this).attr('title')
            );
        });

        var $t1 = $('#themed');
        $('ul.internal', $t1).tabs(
            "div.ptpanes > div", {
                effect: 'fade', onBeforeClick: function (evt, idx) {
                    themeapi.update(idx);
                }
            });

        var api = $('ul.internal', $t1).data('tabs');
        $('.next', $t1).click(function () { api.next(); });
        $('.prev', $t1).click(function () { api.prev(); });
    })();
});

var themeapi = (function () {

    function ThemeApi() {
        this.current = '';
    }

    ThemeApi.prototype = {
        change: function(name, label) {
            $('#themed')
                .attr('class', '')
                .addClass('overlay')
                .addClass(name);

            $('#themed h1').html(label);
            $('#themed ul.allThemes li.' + name).hide();
            $('#themed ul.allThemes li[class~=' +
              this.current + ']').fadeIn();
            this.current = name;
            $('#themed ul.internal').data('tabs').click(0);
            this.update(0);
        },

        update: function (idx) {
            if (this.current === '')
                return null;

            var $el = $('a', $('ul.internal li').get(idx));
            var name = $el.attr('target');
            var $target =
                    $('div.' + name + ' .cont', $('.ptpanes')).html('');
            var url =
                    BASE_URL + 'pages/govpergunta/' +
                    themeapi.current + '/' + name + '.json';

            /* The user asked to go to the contribute form */
            if (name === 'contribua') {
                navapi.click(3);
                $('a.theme')
                    .data('overlay')
                    .close();
                return null;
            }

            $.getJSON(url, function (data) {
                /* Yes, if none is retrieved, we'll clean the
                 * element content. */
                var ct = (data !== null) ? data.content : '';
                $target.html(ct);
            });
            return $el;
        },

        goToContribForm: function () {
        }
    };

    /* -- Contribute page -- */

    $('.contribute label').click(function () {
        $('.contribute label').removeClass('selected');
        $(this).addClass('selected');
    });

    $('.contribute form').ajaxForm({
        beforeSubmit: function () {
            var form = $('.contribute form');
            form.find('input,textarea').removeClass('fielderror');
            form.find('.error').fadeOut();
            form.find('.errmsg').html('');

            if (!auth.isAuthenticated()) {
                auth.showLoginForm({
                    success: function () {
                        form.submit();
                    }
                });
                return false;
            }
            return true;
        },

        success: function (data) {
            var pData = $.parseJSON(data);
            if (pData.status === 'ok') {
                $('#form fieldset').fadeOut();
                return $('div.success').fadeIn();
            }

            /* Here we know that something is wrong */
            var form = $('.contribute form');
            var errors = pData.msg.data;
            var code = pData.code;
            var csrfToken = pData.msg.csrf;

            /* The first step now is to set the new csrf token to
             * our form. If we don't do it, we can't try to
             * register again. */
            form.find('[name=csrf]').val(csrfToken);

            /* The user made a mistake when filling the form */
            if (code === 'ValidationError') {
                for (var f in errors) {
                    form
                        .find('[name=' + f  + ']')
                        .addClass('fielderror');
                    form
                        .find('.'+ f + '-error')
                        .html(errors[f][0]);
                    form.find('div.error')
                        .html('Erros na validação do formulário')
                        .fadeIn('fast');
                }
            } else {
                form.find('div.error').html(pData.msg.data).fadeIn('fast');
            }

            console.debug(pData);
            // if () {
            // }
            return null;
        }
    });

    return new ThemeApi();
})();

function show_form_again() {
    $("#form .title").attr("value", "")
    $("#form textarea").val("")
    $('.contribute label').removeClass('selected');
    $("#form input[type=radio]").attr("checked",false)

    $('#form fieldset').fadeIn();
    $('div.success').fadeOut();
}<commit_msg>(govp) Resolvendo o problema do close de overlay do contribua (Closes: #241)<commit_after>/* Copyright (C) 2011  Lincoln de Sousa <lincoln@comum.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var navapi = null;

$(function () {
   $("#question-writer").ghost_typer({
     text:'Como podemos melhorar o atendimento na saúde pública?',
     speed: 80
   });

    var wizard = $('.wizard').data('isLoaded', false);

    $("ol.tabs", wizard).tabs(
        "div.panes > div", {
            effect: 'fade',
            lazy: true,
            onBeforeClick: function () {
                if (wizard.data('isLoaded')) {
                    $('html,body').animate({ scrollTop: 320 }, 150);
                }
            }
        });
    wizard.data('isLoaded', true);

    navapi = $("ol.tabs", wizard).data("tabs");

    // "next tab" button
    $(".next", wizard).click(function () {
        $('html,body').animate({ scrollTop: 320 }, 100);
	navapi.next();
    });

    // "previous tab" button
    $(".prev", wizard).click(function () {
        $('html,body').animate({ scrollTop: 320 }, 100);
	navapi.prev();
    });

    /* -- Setting up the per-theme description overlays --*/
    (function () {
        $('a.theme').overlay({
            top: '10%',
            speed: 'fast',
            fixed: false,
            oneInstance: false,
            mask: {
                color: '#111',
                opacity: 0.7
            }
        }).click(function () {
            themeapi.change(
                $(this).parent().attr('class'),
                $(this).attr('title')
            );
        });

        var $t1 = $('#themed');
        $('ul.internal', $t1).tabs(
            "div.ptpanes > div", {
                effect: 'fade', onBeforeClick: function (evt, idx) {
                    themeapi.update(idx);
                }
            });

        var api = $('ul.internal', $t1).data('tabs');
        $('.next', $t1).click(function () { api.next(); });
        $('.prev', $t1).click(function () { api.prev(); });
    })();
});

var themeapi = (function () {

    function ThemeApi() {
        this.current = '';
    }

    ThemeApi.prototype = {
        change: function(name, label) {
            $('#themed')
                .attr('class', '')
                .addClass('overlay')
                .addClass(name);

            $('#themed h1').html(label);
            $('#themed ul.allThemes li.' + name).hide();
            $('#themed ul.allThemes li[class~=' +
              this.current + ']').fadeIn();
            this.current = name;
            $('#themed ul.internal').data('tabs').click(0);
            this.update(0);
        },

        update: function (idx) {
            if (this.current === '')
                return null;

            var $el = $('a', $('ul.internal li').get(idx));
            var name = $el.attr('target');
            var $target =
                    $('div.' + name + ' .cont', $('.ptpanes')).html('');
            var url =
                    BASE_URL + 'pages/govpergunta/' +
                    themeapi.current + '/' + name + '.json';

            /* The user asked to go to the contribute form */
            if (name === 'contribua') {
                navapi.click(3);
                $('a.theme').each(function () {
                    $(this).data('overlay').close();
                });
                return null;
            }

            $.getJSON(url, function (data) {
                /* Yes, if none is retrieved, we'll clean the
                 * element content. */
                var ct = (data !== null) ? data.content : '';
                $target.html(ct);
            });
            return $el;
        },

        goToContribForm: function () {
        }
    };

    /* -- Contribute page -- */

    $('.contribute label').click(function () {
        $('.contribute label').removeClass('selected');
        $(this).addClass('selected');
    });

    $('.contribute form').ajaxForm({
        beforeSubmit: function () {
            var form = $('.contribute form');
            form.find('input,textarea').removeClass('fielderror');
            form.find('.error').fadeOut();
            form.find('.errmsg').html('');

            if (!auth.isAuthenticated()) {
                auth.showLoginForm({
                    success: function () {
                        form.submit();
                    }
                });
                return false;
            }
            return true;
        },

        success: function (data) {
            var pData = $.parseJSON(data);
            if (pData.status === 'ok') {
                $('#form fieldset').fadeOut();
                return $('div.success').fadeIn();
            }

            /* Here we know that something is wrong */
            var form = $('.contribute form');
            var errors = pData.msg.data;
            var code = pData.code;
            var csrfToken = pData.msg.csrf;

            /* The first step now is to set the new csrf token to
             * our form. If we don't do it, we can't try to
             * register again. */
            form.find('[name=csrf]').val(csrfToken);

            /* The user made a mistake when filling the form */
            if (code === 'ValidationError') {
                for (var f in errors) {
                    form
                        .find('[name=' + f  + ']')
                        .addClass('fielderror');
                    form
                        .find('.'+ f + '-error')
                        .html(errors[f][0]);
                    form.find('div.error')
                        .html('Erros na validação do formulário')
                        .fadeIn('fast');
                }
            } else {
                form.find('div.error').html(pData.msg.data).fadeIn('fast');
            }

            console.debug(pData);
            // if () {
            // }
            return null;
        }
    });

    return new ThemeApi();
})();

function show_form_again() {
    $("#form .title").attr("value", "")
    $("#form textarea").val("")
    $('.contribute label').removeClass('selected');
    $("#form input[type=radio]").attr("checked",false)

    $('#form fieldset').fadeIn();
    $('div.success').fadeOut();
}<|endoftext|>


<commit_before>(function(Strophe,$) {
	var DiscoNode = function(disco,cfg) {
		this.disco = disco;
		$.extend(this, cfg);
	};

	DiscoNode.prototype.parseRequest = function(iq) {
		if (iq.tree) { return $(Strophe.serialize(iq.tree()));  }
		return $(iq);
	};

	DiscoNode.prototype.fromTo= function(iq) {
		var to = iq.attr('from'), id = iq.attr('id'), res;
		return $iq({to: to, type: 'result', id: id});
	};

	DiscoNode.prototype.addFirstChild = function(req,res) {
		var child = req.find('> *:eq(0)'), childAttr = {};
		if (child.length === 0) { return ; }
		if (child.attr('xmlns')) { childAttr.xmlns = child.attr('xmlns'); }
		if (child.attr('node')) { childAttr.node = child.attr('node'); }
		if ($.isEmptyObject(childAttr)) { res.c(child[0].tagName); }
		else { res.c(child[0].tagName, childAttr); }
	};

	DiscoNode.prototype.reply = function(iq) {
		var req = this.parseRequest(iq);
		var res = this.fromTo(req);
		this.addFirstChild(req,res);
		this.addContent(req,res);
		return res;
	};

	/// DISCO_INFO
	DiscoInfoNode = function() { DiscoNode.apply(this,arguments); };
	DiscoInfoNode.prototype = new DiscoNode();
	DiscoInfoNode.prototype.addContent = function(req,res) {
		var nodes = this.features || this.disco.features;
		var identity = this.identity || this.disco.identity;
		res.c('identity', identity).up();
		$.each(nodes, function(node){
			res.c('feature', { 'var' : node}).up();
		});
	};

	/// DISCO_ITEMS
	DiscoItemsNode = function() { DiscoNode.apply(this,arguments); };
	DiscoItemsNode.prototype = new DiscoNode();
	DiscoItemsNode.prototype.addContent = function(req,res) {
		var items = this.items || this.disco.items;
		$.each(items, function(i,item){
			if(!item.jid) { item.jid = this.disco._conn.jid; }
			res.c('item', item).up();
		}.bind(this));

	};

	/// NODE_NOT_FOUND
	DiscoNodeNotFound = function() { DiscoNode.apply(this,arguments); };
	DiscoNodeNotFound.prototype = new DiscoNode();
	DiscoNodeNotFound.prototype.addContent = function(req,res) {
		res.c('error', { type: 'cancel'});
		res.c('item-not-found', { xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas' });
	};

	function noop(stanza) {
		if (console) { console.log(stanza); }
	}
	Strophe.Disco = {
		DiscoNode: DiscoNode,
		DiscoInfoNode: DiscoInfoNode,
		DiscoNodeNotFound: DiscoNodeNotFound,
		noop: noop
	};
})(Strophe, jQuery);

(function(Strophe,$) {
	var INFO = Strophe.NS.DISCO_INFO;
	var ITEMS = Strophe.NS.DISCO_ITEMS;

	var DiscoNode = Strophe.Disco.DiscoNode;
	var DiscoInfoNode = Strophe.Disco.DiscoInfoNode;
	var DiscoNodeNotFound = Strophe.Disco.DiscoNodeNotFound;
	var noop = Strophe.Disco.noop;

	function request(conn, type, args) {
		var to = args[0], node = args[1], cb = args[2], err = args[3],
			q = { xmlns: type };
		if(typeof node === 'function') { err = cb; cb = node; node = undefined; }
		if(node) { q.node = node; }
		var	iq = $iq({to: to, 'type': 'get'}).c('query',q);
		conn.sendIQ(iq, cb || noop, err || noop);
	}

	function reply(iq) {
		var node = $('query',iq).attr('node') || $('query',iq).attr('xmlns');
		var nodeImpl = this.features[node] || new DiscoNodeNotFound();
		if($.isPlainObject(nodeImpl)) {
			var xmlns = $('query',iq).attr('xmlns');
			var ctr = xmlns === INFO ? DiscoInfoNode : DiscoItemsNode;
			nodeImpl = new ctr(this,nodeImpl);
		}
		this._conn.send(nodeImpl.reply(iq));
		return true;
	}

	var disco = {
		_conn: null,
		init: function(conn) {
			this.jid = conn.jid;
			this.features = {};
			this.identity = { name: 'strophe' };
			this.features[INFO] = new DiscoInfoNode(this);
			this.features[ITEMS] = new DiscoItemsNode(this);
			this._conn = conn;
		},
		statusChanged: function(status) {
			if (status === Strophe.Status.CONNECTED) {
				this._conn.addHandler(reply.bind(this), INFO, 'iq', 'get');
				this._conn.addHandler(reply.bind(this), ITEMS, 'iq', 'get');
			}
		},
		info: function(to, node, callback) {
			request(this._conn, INFO, arguments);
		},
		items: function(to, node, callback) {
			request(this._conn, ITEMS, arguments);
		},
		addNode: function(node, args) {
			if(this.features[node]) { throw node + ' exists'; }
			this.features[node] = args;
		}

	};
	Strophe.addConnectionPlugin('disco', disco);
})(Strophe,jQuery);
<commit_msg>Removed trailing whitespace in disco plugin<commit_after>(function(Strophe,$) {
	var DiscoNode = function(disco,cfg) {
		this.disco = disco;
		$.extend(this, cfg);
	};

	DiscoNode.prototype.parseRequest = function(iq) {
		if (iq.tree) { return $(Strophe.serialize(iq.tree()));  }
		return $(iq);
	};

	DiscoNode.prototype.fromTo= function(iq) {
		var to = iq.attr('from'), id = iq.attr('id'), res;
		return $iq({to: to, type: 'result', id: id});
	};

	DiscoNode.prototype.addFirstChild = function(req,res) {
		var child = req.find('> *:eq(0)'), childAttr = {};
		if (child.length === 0) { return ; }
		if (child.attr('xmlns')) { childAttr.xmlns = child.attr('xmlns'); }
		if (child.attr('node')) { childAttr.node = child.attr('node'); }
		if ($.isEmptyObject(childAttr)) { res.c(child[0].tagName); }
		else { res.c(child[0].tagName, childAttr); }
	};

	DiscoNode.prototype.reply = function(iq) {
		var req = this.parseRequest(iq);
		var res = this.fromTo(req);
		this.addFirstChild(req,res);
		this.addContent(req,res);
		return res;
	};

	/// DISCO_INFO
	DiscoInfoNode = function() { DiscoNode.apply(this,arguments); };
	DiscoInfoNode.prototype = new DiscoNode();
	DiscoInfoNode.prototype.addContent = function(req,res) {
		var nodes = this.features || this.disco.features;
		var identity = this.identity || this.disco.identity;
		res.c('identity', identity).up();
		$.each(nodes, function(node){
			res.c('feature', { 'var' : node}).up();
		});
	};

	/// DISCO_ITEMS
	DiscoItemsNode = function() { DiscoNode.apply(this,arguments); };
	DiscoItemsNode.prototype = new DiscoNode();
	DiscoItemsNode.prototype.addContent = function(req,res) {
		var items = this.items || this.disco.items;
		$.each(items, function(i,item){
			if(!item.jid) { item.jid = this.disco._conn.jid; }
			res.c('item', item).up();
		}.bind(this));
	};

	/// NODE_NOT_FOUND
	DiscoNodeNotFound = function() { DiscoNode.apply(this,arguments); };
	DiscoNodeNotFound.prototype = new DiscoNode();
	DiscoNodeNotFound.prototype.addContent = function(req,res) {
		res.c('error', { type: 'cancel'});
		res.c('item-not-found', { xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas' });
	};

	function noop(stanza) {
		if (console) { console.log(stanza); }
	}
	Strophe.Disco = {
		DiscoNode: DiscoNode,
		DiscoInfoNode: DiscoInfoNode,
		DiscoNodeNotFound: DiscoNodeNotFound,
		noop: noop
	};
})(Strophe, jQuery);

(function(Strophe,$) {
	var INFO = Strophe.NS.DISCO_INFO;
	var ITEMS = Strophe.NS.DISCO_ITEMS;

	var DiscoNode = Strophe.Disco.DiscoNode;
	var DiscoInfoNode = Strophe.Disco.DiscoInfoNode;
	var DiscoNodeNotFound = Strophe.Disco.DiscoNodeNotFound;
	var noop = Strophe.Disco.noop;

	function request(conn, type, args) {
		var to = args[0], node = args[1], cb = args[2], err = args[3],
			q = { xmlns: type };
		if(typeof node === 'function') { err = cb; cb = node; node = undefined; }
		if(node) { q.node = node; }
		var	iq = $iq({to: to, 'type': 'get'}).c('query',q);
		conn.sendIQ(iq, cb || noop, err || noop);
	}

	function reply(iq) {
		var node = $('query',iq).attr('node') || $('query',iq).attr('xmlns');
		var nodeImpl = this.features[node] || new DiscoNodeNotFound();
		if($.isPlainObject(nodeImpl)) {
			var xmlns = $('query',iq).attr('xmlns');
			var ctr = xmlns === INFO ? DiscoInfoNode : DiscoItemsNode;
			nodeImpl = new ctr(this,nodeImpl);
		}
		this._conn.send(nodeImpl.reply(iq));
		return true;
	}

	var disco = {
		_conn: null,
		init: function(conn) {
			this.jid = conn.jid;
			this.features = {};
			this.identity = { name: 'strophe' };
			this.features[INFO] = new DiscoInfoNode(this);
			this.features[ITEMS] = new DiscoItemsNode(this);
			this._conn = conn;
		},
		statusChanged: function(status) {
			if (status === Strophe.Status.CONNECTED) {
				this._conn.addHandler(reply.bind(this), INFO, 'iq', 'get');
				this._conn.addHandler(reply.bind(this), ITEMS, 'iq', 'get');
			}
		},
		info: function(to, node, callback) {
			request(this._conn, INFO, arguments);
		},
		items: function(to, node, callback) {
			request(this._conn, ITEMS, arguments);
		},
		addNode: function(node, args) {
			if(this.features[node]) { throw node + ' exists'; }
			this.features[node] = args;
		}

	};
	Strophe.addConnectionPlugin('disco', disco);
})(Strophe,jQuery);
<|endoftext|>