<commit_before>/**
 * Springle Chat
 *
 * @author Saurabh aka JSX <saurabh@rebugged.com>
 * @copyright
 * @license GNU AFFERO GENERAL PUBLIC LICENSE v3
 */

var WebSocketServer = require('websocket').server;

// Check if SSL support is enabled
if (process.argv.indexOf('--enable-ssl') !== -1) {
    var https = require('https');
    var fs = require('fs');

    var options = {
        key: fs.readFileSync('/home/conf/ssl.key'),
        cert: fs.readFileSync('/home/conf/ssl.crt')
    };

    var server = https.createServer(options, function(request, response) {
        response.writeHead(404);
        response.end();
    });

    var port = 8805;
    var server_start_message = (new Date()) + ' Springle server with SSL is listening on port ' + port;
} else {
    var http = require('http');

    var server = http.createServer(function(request, response) {
        response.writeHead(404);
        response.end();
    });

    var port = 8804;
    var server_start_message = (new Date()) + ' Springle server is listening on port ' + port;
}

var clients = [];
var chat_rooms = {};

var allowed_origins = [
    'localhost',
    'springle.rebugged.com',
    'sky.rebugged.com',
    'mozilla.net'
];

var allowed_protocol = 'chat';

var connection_id = 0;

server.listen(port, function() {
    console.log(server_start_message);
});

wsServer = new WebSocketServer({
    httpServer: server,
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
    var origin_trimmed = origin.replace('http://', '')
                               .replace('https://', '');

    if (allowed_origins.indexOf(origin_trimmed) > -1) {
        return true;
    }

    return false;
}

wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      return;
    }

    if (request.requestedProtocols.indexOf(allowed_protocol) === -1) {
        request.reject();
        return false;
    }

    var connection = request.accept('chat', request.origin);
    connection.id = connection_id++;

    connection.on('message', function(message) {
        if (message.type === 'utf8') {
            var msgObj = JSON.parse(message.utf8Data);

            if (msgObj.type === 'intro') {
                connection.nickname = msgObj.nickname;
                connection.chatroom = msgObj.chatroom;

                if (chat_rooms[msgObj.chatroom] !== undefined) {
                    chat_rooms[msgObj.chatroom].push(connection);
                } else {
                    chat_rooms[msgObj.chatroom] = [connection];
                }

                connection.sendUTF(JSON.stringify({
                    type: 'welcome',
                    userId:connection.id
                }));

                broadcast_chatters_list(msgObj.chatroom);
            } else if (msgObj.type === 'message') {

                message_to_send = JSON.parse(message.utf8Data);
                message_to_send['sender'] = connection.id.toString();
                message_to_send = JSON.stringify(message_to_send);

                console.log(message_to_send)
                broadcast_message(message_to_send, msgObj.chatroom);
            } else if (msgObj.type.match(/^activity_/)) {
                // echo back any message type that start with activity_
                message_to_send = JSON.parse(message.utf8Data);
                message_to_send['sender'] = connection.id.toString();
                message_to_send = JSON.stringify(message_to_send);

                broadcast_message(message_to_send, msgObj.chatroom);
            }
        } else if (message.type === 'binary') {
            // At the moment, we are handling only text messages - no binary
            connection.sendUTF('Invalid message');
        }
    });

    connection.on('close', function(reasonCode, description) {
        var chatroom = connection.chatroom;
        var users = chat_rooms[chatroom];

        for (var i in users) {
            if (connection.id === users[i].id) {
                chat_rooms[chatroom].splice(i, 1);
                broadcast_chatters_list(connection.chatroom);
            }
        }
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    });

    function broadcast_message(message, chatroom) {
        var users = chat_rooms[chatroom];

        for (var i in users) {
            users[i].sendUTF(message);
        }
    }

    function broadcast_chatters_list(chatroom) {
        var nicklist = [];
        var msg_to_send;
        var users = chat_rooms[chatroom];

        for (var i in users) {
            nicklist.push(users[i].nickname);
        }

        msg_to_send = JSON.stringify({
            type: 'nicklist',
            nicklist: nicklist
        });

        broadcast_message(msg_to_send, chatroom);
    }

    function send_poke() {
        var msg = JSON.stringify({
            type: 'message',
            nickname: 'Bot',
            message: 'This is an automated message from the server.'
        });

        broadcast_message(msg);
    }

});
<commit_msg>Updated allowed client domain (origin) entry for mozilla.net to developer.cdn.mozilla.net<commit_after>/**
 * Springle Chat
 *
 * @author Saurabh aka JSX <saurabh@rebugged.com>
 * @copyright
 * @license GNU AFFERO GENERAL PUBLIC LICENSE v3
 */

var WebSocketServer = require('websocket').server;

// Check if SSL support is enabled
if (process.argv.indexOf('--enable-ssl') !== -1) {
    var https = require('https');
    var fs = require('fs');

    var options = {
        key: fs.readFileSync('/home/conf/ssl.key'),
        cert: fs.readFileSync('/home/conf/ssl.crt')
    };

    var server = https.createServer(options, function(request, response) {
        response.writeHead(404);
        response.end();
    });

    var port = 8805;
    var server_start_message = (new Date()) + ' Springle server with SSL is listening on port ' + port;
} else {
    var http = require('http');

    var server = http.createServer(function(request, response) {
        response.writeHead(404);
        response.end();
    });

    var port = 8804;
    var server_start_message = (new Date()) + ' Springle server is listening on port ' + port;
}

var clients = [];
var chat_rooms = {};

var allowed_origins = [
    'localhost',
    'springle.rebugged.com',
    'sky.rebugged.com',
    'developer.cdn.mozilla.net'
];

var allowed_protocol = 'chat';

var connection_id = 0;

server.listen(port, function() {
    console.log(server_start_message);
});

wsServer = new WebSocketServer({
    httpServer: server,
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
    var origin_trimmed = origin.replace('http://', '')
                               .replace('https://', '');

    if (allowed_origins.indexOf(origin_trimmed) > -1) {
        return true;
    }

    return false;
}

wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      return;
    }

    if (request.requestedProtocols.indexOf(allowed_protocol) === -1) {
        request.reject();
        return false;
    }

    var connection = request.accept('chat', request.origin);
    connection.id = connection_id++;

    connection.on('message', function(message) {
        if (message.type === 'utf8') {
            var msgObj = JSON.parse(message.utf8Data);

            if (msgObj.type === 'intro') {
                connection.nickname = msgObj.nickname;
                connection.chatroom = msgObj.chatroom;

                if (chat_rooms[msgObj.chatroom] !== undefined) {
                    chat_rooms[msgObj.chatroom].push(connection);
                } else {
                    chat_rooms[msgObj.chatroom] = [connection];
                }

                connection.sendUTF(JSON.stringify({
                    type: 'welcome',
                    userId:connection.id
                }));

                broadcast_chatters_list(msgObj.chatroom);
            } else if (msgObj.type === 'message') {

                message_to_send = JSON.parse(message.utf8Data);
                message_to_send['sender'] = connection.id.toString();
                message_to_send = JSON.stringify(message_to_send);

                console.log(message_to_send)
                broadcast_message(message_to_send, msgObj.chatroom);
            } else if (msgObj.type.match(/^activity_/)) {
                // echo back any message type that start with activity_
                message_to_send = JSON.parse(message.utf8Data);
                message_to_send['sender'] = connection.id.toString();
                message_to_send = JSON.stringify(message_to_send);

                broadcast_message(message_to_send, msgObj.chatroom);
            }
        } else if (message.type === 'binary') {
            // At the moment, we are handling only text messages - no binary
            connection.sendUTF('Invalid message');
        }
    });

    connection.on('close', function(reasonCode, description) {
        var chatroom = connection.chatroom;
        var users = chat_rooms[chatroom];

        for (var i in users) {
            if (connection.id === users[i].id) {
                chat_rooms[chatroom].splice(i, 1);
                broadcast_chatters_list(connection.chatroom);
            }
        }
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    });

    function broadcast_message(message, chatroom) {
        var users = chat_rooms[chatroom];

        for (var i in users) {
            users[i].sendUTF(message);
        }
    }

    function broadcast_chatters_list(chatroom) {
        var nicklist = [];
        var msg_to_send;
        var users = chat_rooms[chatroom];

        for (var i in users) {
            nicklist.push(users[i].nickname);
        }

        msg_to_send = JSON.stringify({
            type: 'nicklist',
            nicklist: nicklist
        });

        broadcast_message(msg_to_send, chatroom);
    }

    function send_poke() {
        var msg = JSON.stringify({
            type: 'message',
            nickname: 'Bot',
            message: 'This is an automated message from the server.'
        });

        broadcast_message(msg);
    }

});
<|endoftext|>


<commit_before>// This server just broadcasts all messages to all clients.

const WebSocketServer = require("ws").Server

let wss = new WebSocketServer({port: 9090})

class Connection {
  constructor(ws) {
    this.ws = ws

    console.log(`hello ${this.clientName()}`)

    // Connection.all maps client names to connected clients
    if (Connection.all === undefined) {
      Connection.all = {}
    }
    Connection.all[this.clientName()] = this
  }

  clientName() {
    return `${this.ws._socket.remoteAddress}:${this.ws._socket.remotePort}`
  }

  close() {
    console.log(`goodbye ${this.clientName()}`)
    delete Connection.all[this.clientName()]
  }
}

wss.on("connection", function(ws) {
  let connection = new Connection(ws)

  ws.on("message", function(message) {
    console.log("bouncing: %s", message)

    for (let client of wss.clients) {
      client.send(message)
    }
  })

  ws.on("close", () => connection.close())

  ws.send("hello")
})

console.log("server running...")
<commit_msg>server protocol to do matchmaking<commit_after>// This server just broadcasts all messages to all clients.

// Client protocol:
// To sign up for a game:
// { "op": "register", "me": "yourPlayerName"}

// Server protocol:
// The server bounces any client messages to all clients.
// When a client connects, the server sends it
// { "op": "hello" }
// When a game starts, the server sends out
// { "op": "start", "players": [...list of player names...]}

const WebSocketServer = require("ws").Server

let wss = new WebSocketServer({port: 9090})

class Connection {
  constructor(ws) {
    this.ws = ws
    this.name = null
    console.log(`hello ${this.address()}`)

    if (Connection.all === undefined) {
      // Connection.all maps client addresses to connected clients
      Connection.all = new Map()

      // Connection.waiting is a map of clients that have sent a
      // register operation, keyed by name.
      Connection.waiting = new Map()
    }
    Connection.all.set(this.address(), this)
  }

  address() {
    return `${this.ws._socket.remoteAddress}:${this.ws._socket.remotePort}`
  }

  // Message should be JSON
  broadcast(message) {

  }

  receive(messageData) {
    let message = JSON.parse(messageData)
    if (message.op == "register") {
      this.name = message.name
      Connection.waiting.set(this.name, this)
    }

    // Bounce it
    this.broadcast(message)

    // Consider starting a new game
    if (Connection.waiting.size == 2) {
      let start = { op: "start", players: Connection.waiting.keys() }
      this.broadcast(start)
      Connection.waiting.clear()
    }
  }

  close() {
    console.log(`goodbye ${this.address()}`)
    Connection.all.delete(this.address())
    if (this.name != null && Connection.waiting.has(this.name)) {
      Connection.waiting.delete(this.name)
    }
  }
}

wss.on("connection", function(ws) {
  let connection = new Connection(ws)

  ws.on("message", function(message) {
    connection.receive(message)
  })

  ws.on("close", () => connection.close())

  ws.send('{"op":"hello"}')
})

console.log("server running...")
<|endoftext|>


<commit_before><script>

$("#signup").submit( function() {

  $("#name").css("border", "black solid 1px");
  $("#name").css("background-color", "white");
  $("#email").css("border", "black solid 1px");
  $("#email").css("background-color", "white");
  $("#phone").css("border", "black solid 1px");
  $("#phone").css("background-color", "white");
  $("#reqs").css("background-color", "white");

  var name = $("#name").val();

  if (name.length < 2) {
    $("#name").css("border", "#B22B3B solid 1px");
    $("#name").css("background-color", "#F5E3E6");
    return false;
  }

  var email = $("#email").val();

  if (validateEmail(email) == false) {
    $("#email").css("border", "#B22B3B solid 1px");
    $("#email").css("background-color", "#F5E3E6");
    return false;
  }

  var phone = $("#phone").val().replace(/ /g, '');
  $("#phone").val(phone);

  if (phone != "") {
    if (validatePhone(phone) == false) {
      $("#phone").css("border", "#B22B3B solid 1px");
      $("#phone").css("background-color", "#F5E3E6");
      return false;
    }
  }

  var n = <?php echo $experiment->total_requirements; ?>;

  for (i=0; i<n; i++) {
    if ($("#require" + i).is(":checked") == false) {
      $("#reqs").css("background-color", "#F5E3E6");
      return false
    }
  }

  return true;

});

function validateEmail(email) {
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
}

function validatePhone(phone) {
    var re = /^07\d{9}$/;
    return re.test(phone);
}

</script>
<commit_msg>Revert "Don't auto place focus on name field"<commit_after><script>

$("#signup").submit( function() {

  $("#name").css("border", "black solid 1px");
  $("#name").css("background-color", "white");
  $("#email").css("border", "black solid 1px");
  $("#email").css("background-color", "white");
  $("#phone").css("border", "black solid 1px");
  $("#phone").css("background-color", "white");
  $("#reqs").css("background-color", "white");

  var name = $("#name").val();

  if (name.length < 2) {
    $("#name").css("border", "#B22B3B solid 1px");
    $("#name").css("background-color", "#F5E3E6");
    return false;
  }

  var email = $("#email").val();

  if (validateEmail(email) == false) {
    $("#email").css("border", "#B22B3B solid 1px");
    $("#email").css("background-color", "#F5E3E6");
    return false;
  }

  var phone = $("#phone").val().replace(/ /g, '');
  $("#phone").val(phone);

  if (phone != "") {
    if (validatePhone(phone) == false) {
      $("#phone").css("border", "#B22B3B solid 1px");
      $("#phone").css("background-color", "#F5E3E6");
      return false;
    }
  }

  var n = <?php echo $experiment->total_requirements; ?>;

  for (i=0; i<n; i++) {
    if ($("#require" + i).is(":checked") == false) {
      $("#reqs").css("background-color", "#F5E3E6");
      return false
    }
  }

  return true;

});

function validateEmail(email) {
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
}

function validatePhone(phone) {
    var re = /^07\d{9}$/;
    return re.test(phone);
}

$("#name").focus();

</script>
<|endoftext|>


<commit_before>$(function() {
  var CardSizes = {
                  XS : "xs",
                  S: "s",
                  M: "m",
                  L: "l",
                  XL: "xl",
                  TO_DO: "todo"
                  };

  var CARD_STORAGE = "sizeit.cards";
  var columns = [
                    '#column-xs',
                    '#column-s',
                    '#column-m',
                    '#column-l',
                    '#column-xl',
                    '#column-todo']

  $(document).ready(makeThingsGo);

  // ==========================
  // Event handlers etc
  // ==========================
  function makeThingsGo() {

    $('#new-card-box').hide();

    $('#add-new-card').click(function(){
      $("#new-card-box").show('fast');
      $('#card-text').val('');
      $("#card-text").focus();
    });

    $('#clear-cards').click(clearStorage);

    $('#cancel-card').click(function(){
      $("#new-card-box").hide('fast');
    });

    $('#save-card').click(addNewCard);

    // bind all the future added icons too
    $(document).on("click", "i.remove", function(){
      var jThis = $(this);
      var text = jThis.parent().text();
      var column = jThis.parent().parent().attr('id').substr(7);
      $(this).parent().remove();
      removeCard(text, column);
    });

    // ==========================
    // Drag and drop
    // ==========================

    $( "[id^='column-']" ).sortable({
        connectWith: ".draggable",
        items: 'li:not(.no-drag)',
        distance: 5,
        opacity: 0.6,
        placeholder: 'ghost',
        forcePlaceholderSize: true,
        start: function(event, ui) {
          // for some reason the placeholder style isn't actually applied
          ui.placeholder.css("background-color", "transparent");
          ui.placeholder.css("border-style", "dashed");
        },
        receive: function(event, ui) {
          var newColumn = ui.item.parent();
          var text = ui.item.text();
          var newSize = newColumn.attr('id').substr(7);
          updateCardSize(text, newSize);
        }
      });

    // for testing only
    if (localStorage[CARD_STORAGE] == undefined)
      knitFakeSocks();

    loadAllStorage();
  }

  // ==========================
  // Display cards
  // ==========================

  function addNewCard() {
    var contents = $('#card-text').val().replace("\n", "
");

    // todo: validations
    // no duplicate names, no empties
    putSockInDrawer(contents, CardSizes.TO_DO);
    $('#column-todo').append('
' +
        '' +
        contents + '
');
    $("#new-card-box").hide('fast');
  }

  function removeCard(name, size) {
    var cards = safeGetStorage();

    // todo: when moving is saved, also compare size matches
    var index = findCard(cards, name);
    if (index != -1) cards.remove(index);
    localStorage[CARD_STORAGE] = JSON.stringify(cards);
  }

  function updateCardSize(name, newSize) {
    var cards = safeGetStorage();
    var index = findCard(cards, name);
    cards[index].size = newSize;
    localStorage[CARD_STORAGE] = JSON.stringify(cards);
  }

  function findCard(cards, name) {
    for (var i = 0; i < cards.length; i++) {
      if (cards[i].text == name) return i;
    }
    return -1;
  }

  function displayCards(cards) {
    // first clear everything
    for (var i = 0; i < columns.length; i++) {
      var jCol = $(columns[i]);
      jCol.children().remove(".card");
    }

    if (cards == null) return;

    for (var i = 0; i < cards.length; i++) {
      var jCol = $('#column-' + cards[i].size);
      jCol.append('
' +
        '' +
        cards[i].text + '
');
    }
  }

  // ==========================
  // Save and load cards
  // ==========================

  function loadAllStorage() {
    var cards = safeGetStorage();
    displayCards(cards);
  }

  function clearStorage() {
    localStorage.removeItem(CARD_STORAGE);
    displayCards(null);
  }

  function putSockInDrawer(sock, size) {
    var cards = safeGetStorage();
    cards.push({text: sock, size: size});
    localStorage[CARD_STORAGE] = JSON.stringify(cards);
  }

  function hasStorageSkills() {
    try {
      return 'localStorage' in window && window['localStorage'] !== null;
    } catch (e) {
      return false;
    }
  }

  function safeGetStorage() {
    var stored = localStorage[CARD_STORAGE];
    var cards;
    if (stored == undefined) cards = []
    else                     cards = JSON.parse(stored);
    return cards;
  }

  // ==========================
  // Helper elves
  // ==========================

  function knitFakeSocks() {
    var socks = [];
    socks.push({text: "one", size: CardSizes.XS});
    socks.push({text: "two", size: CardSizes.TO_DO});
    socks.push({text: "three", size: CardSizes.TO_DO});
    socks.push({text: "four", size: CardSizes.TO_DO});

    localStorage.removeItem(CARD_STORAGE);
    localStorage[CARD_STORAGE] = JSON.stringify(socks);
  }

  // Array Remove - By John Resig (MIT Licensed)
  Array.prototype.remove = function(from, to) {
    var rest = this.slice((to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  };

});

<commit_msg>allow text copy<commit_after>$(function() {
  var CardSizes = {
                  XS : "xs",
                  S: "s",
                  M: "m",
                  L: "l",
                  XL: "xl",
                  TO_DO: "todo"
                  };

  var CARD_STORAGE = "sizeit.cards";
  var columns = [
                    '#column-xs',
                    '#column-s',
                    '#column-m',
                    '#column-l',
                    '#column-xl',
                    '#column-todo']

  $(document).ready(makeThingsGo);

  // ==========================
  // Event handlers etc
  // ==========================
  function makeThingsGo() {

    $('#new-card-box').hide();

    $('#add-new-card').click(function(){
      $("#new-card-box").show('fast');
      $('#card-text').val('');
      $("#card-text").focus();
    });

    $('#clear-cards').click(clearStorage);

    $('#cancel-card').click(function(){
      $("#new-card-box").hide('fast');
    });

    $('#save-card').click(addNewCard);

    // bind all the future added icons too
    $(document).on("click", "i.remove", function(){
      var jThis = $(this);
      var text = jThis.parent().text();
      var column = jThis.parent().parent().attr('id').substr(7);
      $(this).parent().remove();
      removeCard(text, column);
    });

    // ==========================
    // Drag and drop
    // ==========================

    $( "[id^='column-']" ).sortable({
        connectWith: ".draggable",
        items: 'li:not(.no-drag)',
        cancel: 'span',
        distance: 5,
        opacity: 0.6,
        placeholder: 'ghost',
        forcePlaceholderSize: true,
        start: function(event, ui) {
          // for some reason the placeholder style isn't actually applied
          ui.placeholder.css("background-color", "transparent");
          ui.placeholder.css("border-style", "dashed");
        },
        receive: function(event, ui) {
          var newColumn = ui.item.parent();
          var text = ui.item.text();
          var newSize = newColumn.attr('id').substr(7);
          updateCardSize(text, newSize);
        }
      });

    // for testing only
    if (localStorage[CARD_STORAGE] == undefined)
      knitFakeSocks();

    loadAllStorage();
  }

  // ==========================
  // Display cards
  // ==========================

  function addNewCard() {
    var contents = $('#card-text').val().replace("\n", "
");

    // todo: validations
    // no duplicate names, no empties
    putSockInDrawer(contents, CardSizes.TO_DO);
    $('#column-todo').append('
' +
        '' +
        contents + '
');
    $("#new-card-box").hide('fast');
  }

  function removeCard(name, size) {
    var cards = safeGetStorage();

    // todo: when moving is saved, also compare size matches
    var index = findCard(cards, name);
    if (index != -1) cards.remove(index);
    localStorage[CARD_STORAGE] = JSON.stringify(cards);
  }

  function updateCardSize(name, newSize) {
    var cards = safeGetStorage();
    var index = findCard(cards, name);
    cards[index].size = newSize;
    localStorage[CARD_STORAGE] = JSON.stringify(cards);
  }

  function findCard(cards, name) {
    for (var i = 0; i < cards.length; i++) {
      if (cards[i].text == name) return i;
    }
    return -1;
  }

  function displayCards(cards) {
    // first clear everything
    for (var i = 0; i < columns.length; i++) {
      var jCol = $(columns[i]);
      jCol.children().remove(".card");
    }

    if (cards == null) return;

    for (var i = 0; i < cards.length; i++) {
      var jCol = $('#column-' + cards[i].size);
      jCol.append('
' +
        '' +
        cards[i].text + '
');
    }
  }

  // ==========================
  // Save and load cards
  // ==========================

  function loadAllStorage() {
    var cards = safeGetStorage();
    displayCards(cards);
  }

  function clearStorage() {
    localStorage.removeItem(CARD_STORAGE);
    displayCards(null);
  }

  function putSockInDrawer(sock, size) {
    var cards = safeGetStorage();
    cards.push({text: sock, size: size});
    localStorage[CARD_STORAGE] = JSON.stringify(cards);
  }

  function hasStorageSkills() {
    try {
      return 'localStorage' in window && window['localStorage'] !== null;
    } catch (e) {
      return false;
    }
  }

  function safeGetStorage() {
    var stored = localStorage[CARD_STORAGE];
    var cards;
    if (stored == undefined) cards = []
    else                     cards = JSON.parse(stored);
    return cards;
  }

  // ==========================
  // Helper elves
  // ==========================

  function knitFakeSocks() {
    var socks = [];
    socks.push({text: "one", size: CardSizes.XS});
    socks.push({text: "two", size: CardSizes.TO_DO});
    socks.push({text: "three", size: CardSizes.TO_DO});
    socks.push({text: "four", size: CardSizes.TO_DO});

    localStorage.removeItem(CARD_STORAGE);
    localStorage[CARD_STORAGE] = JSON.stringify(socks);
  }

  // Array Remove - By John Resig (MIT Licensed)
  Array.prototype.remove = function(from, to) {
    var rest = this.slice((to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  };

});

<|endoftext|>


<commit_before>"use strict";

var $$ = require ("substance-application").$$;
var NodeView = require("../node/node_view");
var TextView = require("../text/text_view");

// Substance.Issue.View
// ==========================================================================

var IssueView = function(node, viewFactory) {
  NodeView.call(this, node, viewFactory);

  this.$el.addClass('issue');

  this.childViews = {
    "title": null,
    "description": null
  };
};

IssueView.Prototype = function() {

  // Rendering
  // =============================
  //

  this.render = function() {
    NodeView.prototype.render.call(this);

    var labelView = this.childViews["title"] = new TextView(this.node, this.viewFactory, {property: "title"});

    this.content.appendChild(labelView.render().el);

    // Delete Button
    // --------

    var deleteButton = $$('a.delete-issue', {
      href: '#',
      text: "Delete",
      contenteditable: false // Make sure this is not editable!
    });

    labelView.el.appendChild(deleteButton);

    // this.content.appendChild($$('.issue-description', {
    //   text: "HELLO I AM AN ISSUE"
    // }));

    var descriptionView = this.childViews["description"] = new TextView(this.node, this.viewFactory, {property: "description"});
    this.content.appendChild(descriptionView.render().el);

    // var caption = this.node.getCaption();
    // if (caption) {
    //   var captionView = this.childViews["caption"] = this.viewFactory.createView(caption);
    //   var captionEl = captionView.render().el;
    //   captionEl.classList.add('caption');
    //   this.content.appendChild(captionEl);
    // }

    return this;
  };
};

IssueView.Prototype.prototype = NodeView.prototype;
IssueView.prototype = new IssueView.Prototype();

module.exports = IssueView;
<commit_msg>Cleanup.<commit_after>"use strict";

var $$ = require ("substance-application").$$;
var NodeView = require("../node/node_view");
var TextView = require("../text/text_view");

// Substance.Issue.View
// ==========================================================================

var IssueView = function(node, viewFactory) {
  NodeView.call(this, node, viewFactory);

  this.$el.addClass('issue');

  this.childViews = {
    "title": null,
    "description": null
  };
};

IssueView.Prototype = function() {

  // Rendering
  // =============================
  //

  this.render = function() {
    NodeView.prototype.render.call(this);

    var labelView = this.childViews["title"] = new TextView(this.node, this.viewFactory, {property: "title"});

    this.content.appendChild(labelView.render().el);

    // Delete Button
    // --------

    var deleteButton = $$('a.delete-issue', {
      href: '#',
      text: "Delete",
      contenteditable: false // Make sure this is not editable!
    });

    labelView.el.appendChild(deleteButton);

    var descriptionView = this.childViews["description"] = new TextView(this.node, this.viewFactory, {property: "description"});
    this.content.appendChild(descriptionView.render().el);

    // var caption = this.node.getCaption();
    // if (caption) {
    //   var captionView = this.childViews["caption"] = this.viewFactory.createView(caption);
    //   var captionEl = captionView.render().el;
    //   captionEl.classList.add('caption');
    //   this.content.appendChild(captionEl);
    // }

    return this;
  };
};

IssueView.Prototype.prototype = NodeView.prototype;
IssueView.prototype = new IssueView.Prototype();

module.exports = IssueView;
<|endoftext|>


<commit_before>import {
  plusReady
} from 'uni-shared'
import emitter from './emitter'

/**
 * 保证iOS点击输入框外隐藏键盘
 */
function iosHideKeyboard () { }

function setSoftinputTemporary (vm, reset) {
  plusReady(() => {
    const MODE_ADJUSTRESIZE = 'adjustResize'
    const MODE_ADJUSTPAN = 'adjustPan'
    const MODE_NOTHING = 'nothing'
    const currentWebview = plus.webview.currentWebview()
    const style = currentWebview.getStyle() || {}
    const options = {
      mode: (reset || style.softinputMode === MODE_ADJUSTRESIZE) ? MODE_ADJUSTRESIZE : (vm.adjustPosition ? MODE_ADJUSTPAN : MODE_NOTHING),
      position: {
        top: 0,
        height: 0
      }
    }
    if (options.mode === MODE_ADJUSTPAN) {
      const rect = vm.$el.getBoundingClientRect()
      options.position.top = rect.top
      options.position.height = rect.height + (Number(vm.cursorSpacing) || 0)
    }
    currentWebview.setSoftinputTemporary(options)
  })
}

function setSoftinputNavBar (vm) {
  if (vm.showConfirmBar === 'auto') {
    delete vm.__softinputNavBar
    return
  }
  plusReady(() => {
    const currentWebview = plus.webview.currentWebview()
    const { softinputNavBar } = currentWebview.getStyle() || {}
    const showConfirmBar = softinputNavBar !== 'none'
    if (showConfirmBar !== vm.showConfirmBar) {
      vm.__softinputNavBar = softinputNavBar || 'auto'
      currentWebview.setStyle({
        softinputNavBar: vm.showConfirmBar ? 'auto' : 'none'
      })
    } else {
      delete vm.__softinputNavBar
    }
  })
}

function resetSoftinputNavBar (vm) {
  const softinputNavBar = vm.__softinputNavBar
  if (softinputNavBar) {
    plusReady(() => {
      const currentWebview = plus.webview.currentWebview()
      currentWebview.setStyle({
        softinputNavBar
      })
    })
  }
}

let resetTimer
let isAndroid
let osVersion
let keyboardHeight
let keyboardChangeCallback
if (__PLATFORM__ === 'app-plus') {
  plusReady(() => {
    isAndroid = plus.os.name.toLowerCase() === 'android'
    osVersion = plus.os.version
  })
  document.addEventListener('keyboardchange', function (event) {
    keyboardHeight = event.height
    keyboardChangeCallback && keyboardChangeCallback()
  }, false)
}

export default {
  name: 'Keyboard',
  mixins: [emitter],
  props: {
    cursorSpacing: {
      type: [Number, String],
      default: 0
    },
    showConfirmBar: {
      type: [Boolean, String],
      default: 'auto'
    },
    adjustPosition: {
      type: [Boolean, String],
      default: true
    },
    autoBlur: {
      type: [Boolean, String],
      default: false
    }
  },
  directives: {
    keyboard: {
      inserted (el, binding, vnode) {
        vnode.context.initKeyboard(el)
      }
    }
  },
  methods: {
    initKeyboard (el) {
      let focus

      const keyboardChange = () => {
        this.$trigger('keyboardheightchange', {}, {
          height: keyboardHeight,
          duration: 0.25
        })
        // 安卓切换不同键盘类型时会导致键盘收回，需重新设置
        if (focus && keyboardHeight === 0) {
          setSoftinputTemporary(this)
        }
        // 安卓/iOS13收起键盘时主动失去焦点
        if (this.autoBlur && focus && keyboardHeight === 0 && (isAndroid || parseInt(osVersion) >= 13)) {
          document.activeElement.blur()
        }
      }

      el.addEventListener('focus', () => {
        focus = true
        clearTimeout(resetTimer)
        document.addEventListener('click', iosHideKeyboard, false)

        if (__PLATFORM__ === 'app-plus') {
          keyboardChangeCallback = keyboardChange
          if (keyboardHeight) {
            this.$trigger('keyboardheightchange', {}, {
              height: keyboardHeight,
              duration: 0
            })
          }
          setSoftinputNavBar(this)
          setSoftinputTemporary(this)
        }
      })

      if (__PLATFORM__ === 'app-plus') {
        // 安卓单独隐藏键盘后点击输入框不会触发 focus 事件
        el.addEventListener('click', () => {
          if (!this.disabled && focus && keyboardHeight === 0) {
            setSoftinputTemporary(this)
          }
        })
        if (!isAndroid && parseInt(osVersion) < 12) {
          // iOS12 以下系统 focus 事件设置较迟，改在 touchstart 设置
          el.addEventListener('touchstart', () => {
            if (!this.disabled && !focus) {
              setSoftinputTemporary(this)
            }
          })
        }
      }

      const onKeyboardHide = () => {
        document.removeEventListener('click', iosHideKeyboard, false)

        if (__PLATFORM__ === 'app-plus') {
          keyboardChangeCallback = null
          if (keyboardHeight) {
            this.$trigger('keyboardheightchange', {}, {
              height: 0,
              duration: 0
            })
          }
          resetSoftinputNavBar(this)
          if (isAndroid) {
            // 还原安卓软键盘配置，避免影响 web-view 组件
            resetTimer = setTimeout(() => {
              setSoftinputTemporary(this, true)
            }, 300)
          }
        }

        // 修复ios端显示与点击位置错位的Bug by:wyq
        if (String(navigator.vendor).indexOf('Apple') === 0) {
          document.documentElement.scrollTo(document.documentElement.scrollLeft, document.documentElement.scrollTop)
        }
      }

      el.addEventListener('blur', () => {
        focus = false
        onKeyboardHide()
      })
    }
  }
}
<commit_msg>fix: 修复  在iOS设备上，手动调用uni.hideKeyboard()后如果再点击页面其他地方会重新聚焦 125233<commit_after>import {
  plusReady
} from 'uni-shared'
import emitter from './emitter'

/**
 * 保证iOS点击输入框外隐藏键盘
 */
function iosHideKeyboard () { }

function setSoftinputTemporary (vm, reset) {
  plusReady(() => {
    const MODE_ADJUSTRESIZE = 'adjustResize'
    const MODE_ADJUSTPAN = 'adjustPan'
    const MODE_NOTHING = 'nothing'
    const currentWebview = plus.webview.currentWebview()
    const style = currentWebview.getStyle() || {}
    const options = {
      mode: (reset || style.softinputMode === MODE_ADJUSTRESIZE) ? MODE_ADJUSTRESIZE : (vm.adjustPosition ? MODE_ADJUSTPAN : MODE_NOTHING),
      position: {
        top: 0,
        height: 0
      }
    }
    if (options.mode === MODE_ADJUSTPAN) {
      const rect = vm.$el.getBoundingClientRect()
      options.position.top = rect.top
      options.position.height = rect.height + (Number(vm.cursorSpacing) || 0)
    }
    currentWebview.setSoftinputTemporary(options)
  })
}

function setSoftinputNavBar (vm) {
  if (vm.showConfirmBar === 'auto') {
    delete vm.__softinputNavBar
    return
  }
  plusReady(() => {
    const currentWebview = plus.webview.currentWebview()
    const { softinputNavBar } = currentWebview.getStyle() || {}
    const showConfirmBar = softinputNavBar !== 'none'
    if (showConfirmBar !== vm.showConfirmBar) {
      vm.__softinputNavBar = softinputNavBar || 'auto'
      currentWebview.setStyle({
        softinputNavBar: vm.showConfirmBar ? 'auto' : 'none'
      })
    } else {
      delete vm.__softinputNavBar
    }
  })
}

function resetSoftinputNavBar (vm) {
  const softinputNavBar = vm.__softinputNavBar
  if (softinputNavBar) {
    plusReady(() => {
      const currentWebview = plus.webview.currentWebview()
      currentWebview.setStyle({
        softinputNavBar
      })
    })
  }
}

let resetTimer
let isAndroid
let osVersion
let keyboardHeight
let keyboardChangeCallback
if (__PLATFORM__ === 'app-plus') {
  plusReady(() => {
    isAndroid = plus.os.name.toLowerCase() === 'android'
    osVersion = plus.os.version
  })
  document.addEventListener('keyboardchange', function (event) {
    keyboardHeight = event.height
    keyboardChangeCallback && keyboardChangeCallback()
  }, false)
}

export default {
  name: 'Keyboard',
  mixins: [emitter],
  props: {
    cursorSpacing: {
      type: [Number, String],
      default: 0
    },
    showConfirmBar: {
      type: [Boolean, String],
      default: 'auto'
    },
    adjustPosition: {
      type: [Boolean, String],
      default: true
    },
    autoBlur: {
      type: [Boolean, String],
      default: false
    }
  },
  directives: {
    keyboard: {
      inserted (el, binding, vnode) {
        vnode.context.initKeyboard(el)
      }
    }
  },
  methods: {
    initKeyboard (el) {
      let focus

      const keyboardChange = () => {
        this.$trigger('keyboardheightchange', {}, {
          height: keyboardHeight,
          duration: 0.25
        })
        // 安卓切换不同键盘类型时会导致键盘收回，需重新设置
        if (focus && keyboardHeight === 0) {
          setSoftinputTemporary(this)
        }
        // 安卓/iOS13收起键盘时主动失去焦点
        if (this.autoBlur && focus && keyboardHeight === 0 && (isAndroid || parseInt(osVersion) >= 13)) {
          document.activeElement.blur()
        }
      }

      el.addEventListener('focus', () => {
        focus = true
        clearTimeout(resetTimer)
        document.addEventListener('click', iosHideKeyboard, false)

        if (__PLATFORM__ === 'app-plus') {
          keyboardChangeCallback = keyboardChange
          if (keyboardHeight) {
            this.$trigger('keyboardheightchange', {}, {
              height: keyboardHeight,
              duration: 0
            })
          }
          setSoftinputNavBar(this)
          setSoftinputTemporary(this)
        }
      })

      if (__PLATFORM__ === 'app-plus') {
        // 安卓单独隐藏键盘后点击输入框不会触发 focus 事件
        el.addEventListener('click', () => {
          if (!this.disabled && focus && keyboardHeight === 0) {
            setSoftinputTemporary(this)
          }
        })
        if (!isAndroid && parseInt(osVersion) < 12) {
          // iOS12 以下系统 focus 事件设置较迟，改在 touchstart 设置
          el.addEventListener('touchstart', () => {
            if (!this.disabled && !focus) {
              setSoftinputTemporary(this)
            }
          })
        }
      }

      const onKeyboardHide = () => {
        document.removeEventListener('click', iosHideKeyboard, false)

        if (__PLATFORM__ === 'app-plus') {
          keyboardChangeCallback = null
          if (keyboardHeight) {
            this.$trigger('keyboardheightchange', {}, {
              height: 0,
              duration: 0
            })
          }
          resetSoftinputNavBar(this)
          if (isAndroid) {
            // 还原安卓软键盘配置，避免影响 web-view 组件
            resetTimer = setTimeout(() => {
              setSoftinputTemporary(this, true)
            }, 300)
          }
        }

        // 修复ios端显示与点击位置错位的Bug by:wyq
        if (String(navigator.vendor).indexOf('Apple') === 0) {
          document.documentElement.scrollTo(document.documentElement.scrollLeft, document.documentElement.scrollTop)
        }
      }

      el.addEventListener('blur', () => {
        // 在iOS设备上，手动调用uni.hideKeyboard()，键盘收起并且触发blur，但实际并没有blur。
        // 此时如果再点击页面其他地方会重新聚焦，此处做处理
        el.blur()
        focus = false
        onKeyboardHide()
      })
    }
  }
}
<|endoftext|>


<commit_before>var public_spreadsheet_url =                'https://docs.google.com/spreadsheets/d/1QXOUoGM93i4dt5XH8QbfS7TG8A00v5b-18Few3KcqfM/pubhtml';

function InitializeTabletop()
{
    Tabletop.init( { key: public_spreadsheet_url,
                     callback: showInfo,
                     simpleSheet: true } )
}

function showInfo(data, tabletop)
{
    //alert("Successfully processed!")
    console.log(data);
    AddSkillsToPage(data);
    //alert(data[0].Skill);
}

function CreateModule (skill, iconLink, blurb)
{
    	return "

"+skill+"

"
}

function AddSkillsToPage(data)
{
    for(i = 0; i < data.length; i++)
    {
        $('#'+data[i].Category)
            .find('.autowide')
            .append(CreateModule(data[i].Skill, data[i].IconLink, data[i].Blurb))
            .on( "click",
                {
                    Skill: data[i].Skill,
                    IconLink: data[i].IconLink,
                    Blurb: data[i].Blurb
                }, ModuleClick );
    }
}

$( document ).ready(function()
{
    InitializeTabletop();

});

function ModuleClick(event)
{
        console.log('click');
        swal({
            title: "

"+event.data.Skill+"
",
            text: event.data.Blurb,
            html: true
        });
}
<commit_msg>fixed module click<commit_after>var public_spreadsheet_url =                'https://docs.google.com/spreadsheets/d/1QXOUoGM93i4dt5XH8QbfS7TG8A00v5b-18Few3KcqfM/pubhtml';

function InitializeTabletop()
{
    Tabletop.init( { key: public_spreadsheet_url,
                     callback: showInfo,
                     simpleSheet: true } )
}

function showInfo(data, tabletop)
{
    //alert("Successfully processed!")
    console.log(data);
    AddSkillsToPage(data);
    //alert(data[0].Skill);
}

function CreateModule (skill, iconLink, blurb)
{
    	return "

"+skill+"

"
}

function AddSkillsToPage(data)
{
    for(i = 0; i < data.length; i++)
    {
        var module = CreateModule(data[i].Skill, data[i].IconLink, data[i].Blurb);

        $('#'+data[i].Category)
            .find('.autowide')
            .append(module);

    }

    //Add clicks to all modules
    $('.module').click(ModuleClick);

}

$( document ).ready(function()
{
    InitializeTabletop();

});

function ModuleClick(event)
{
        console.log('click');
        swal({
            title: "

"+$(this).attr('data-skill')+"
",
            text: $(this).attr('data-blurb'),
            html: true
        });
}
<|endoftext|>


<commit_before>window.d3 = require('d3/d3');

import Marionette from 'backbone.marionette';

const TimeSlider = require('D3.TimeSlider/src/d3.timeslider.coffee');
const WMSSource = require('D3.TimeSlider/src/sources/wms.coffee');
const EOWCSSource = require('D3.TimeSlider/src/sources/eowcs.coffee');
const WPSSource = require('D3.TimeSlider/src/sources/eoxserver-wps.coffee');

import searchEOWCS from '../../search/eowcs';
import searchOpenSearch from '../../search/opensearch';
import FiltersModel from '../models/FiltersModel';

// require('D3.TimeSlider/build/d3.timeslider.plugins');
require('D3.TimeSlider/src/d3.timeslider.less');
require('./TimeSliderView.css');

const TimeSliderView = Marionette.ItemView.extend(/** @lends core/views.TimeSliderView# */{
  template: () => '',

  events: {
    selectionChanged: 'onSelectionChanged',
    recordClicked: 'onRecordClicked',
    recordMouseover: 'onRecordMouseover',
    recordMouseout: 'onRecordMouseout',
  },

  /**
    @constructs
    @param {Object} options
    @param {core/models.FiltersModel} options.filtersModel The filters model to store the filters
    @param {core/models.LayersCollection} options.layersCollection The layers to show
                                                                   on the time slider
    @param {core/models.MapModel} options.mapModel The map-model
    @param {Date[]} options.domain The maximum domain to allow panning of th time slider
  */
  initialize(options) {
    this.filtersModel = options.filtersModel;
    this.layersCollection = options.layersCollection;

    this.mapModel = options.mapModel;

    this.domain = options.domain;
  },

  onRender() {

  },

  onAttach() {
    const options = {
      domain: this.domain,
      debounce: 300,
      ticksize: 8,
      datasets: [],
      recordFilter: this.createRecordFilter(this.mapModel.get('bbox')),
    };
    const time = this.filtersModel.get('time');
    if (time !== null) {
      options.brush = {
        start: time[0],
        end: time[1],
      };
    }

    this.timeSlider = new TimeSlider(this.el, options);

    const visibleLayers = this.layersCollection.filter(
      layerModel => layerModel.get('display.visible')
    );

    if (visibleLayers.length > 0) {
      visibleLayers.forEach(layerModel => this.addLayer(layerModel));
    } else {
      this.$el.css('display', 'none');
    }

    this.listenTo(this.filtersModel, 'change:time', this.onModelSelectionChanged);
    this.listenTo(this.layersCollection, 'add', this.onLayerAdded);
    this.listenTo(this.layersCollection, 'remove', this.onLayerRemoved);
    this.listenTo(this.layersCollection, 'change', this.onLayerChanged);
    this.listenTo(this.mapModel, 'change:bbox', (mapModel) => {
      this.timeSlider.setRecordFilter(this.createRecordFilter(mapModel.get('bbox')));
    });
  },

  addLayer(layerModel) {
    this.$el.fadeIn();
    let source;
    switch (layerModel.get('search').protocol) {
      case 'EOxServer-WPS':
        source = new WPSSource({
          url: layerModel.get('search').url || layerModel.get('search').urls[0],
          eoid: layerModel.get('search').id,
        });
        break;
      case 'EO-WCS':
        source = (start, end, params, callback) => {
          const filtersModel = new FiltersModel({ time: [start, end] });
          searchEOWCS(layerModel, filtersModel).then(result => {
            callback(result.records.map(
              record => [record.properties.startTime, record.properties.endTime, record]
            ));
          });
        };
        break;
      case 'OpenSearch':
        source = (start, end, params, callback) => {
          const filtersModel = new FiltersModel({ time: [start, end] });
          searchOpenSearch(layerModel, filtersModel).then(result => {
            callback(result.records.map(record => {
              let time = null;
              const properties = record.properties;
              if (record.time) {
                time = record.time;
              } else if (properties) {
                // TODO: other property names than begin_time/end_time
                if (properties.begin_time && properties.end_time) {
                  time = [new Date(properties.begin_time), new Date(properties.end_time)];
                } else if (properties.time) {
                  if (Array.isArray(properties.time)) {
                    time = properties.time;
                  } else {
                    time = [properties.time];
                  }
                }
              }

              if (time === null) {
                return null;
              }

              return [...time, record];
            }).filter(item => item !== null));
          });
        };
        break;
      case 'WMS':
        source = new WMSSource({
          url: layerModel.get('search').url || layerModel.get('search').urls[0],
          layer: layerModel.get('search').id,
        });
        break;
      default:
        console.warn(`Unexpected search protocol ${layerModel.get('search').protocol}`);
        break;
    }

    this.timeSlider.addDataset({
      id: layerModel.get('id'),
      color: layerModel.get('displayColor'),
      source,
    });
  },

  removeLayer(layerModel) {
    this.timeSlider.removeDataset(layerModel.get('id'));
    const visibleLayers = this.layersCollection.filter(m => m.get('display.visible'));
    if (visibleLayers.length === 0) {
      this.$el.fadeOut();
    }
  },

  createRecordFilter(bbox) {
    return (record) => {
      const params = record[2];
      if (params && params.bbox) {
        const a = bbox;
        const b = params.bbox;
        // adapted from http://gamedev.stackexchange.com/a/913/50029
        return !(a[0] > b[2]
          || a[2] < b[0]
          || a[3] < b[1]
          || a[1] > b[3]
        );
      }
      return true;
    };
  },

  // two way binding of time selection

  onSelectionChanged(event) {
    const selection = event.originalEvent.detail;
    this.filtersModel.set('time', [selection.start, selection.end]);
  },

  onRecordClicked(event) {
    const record = event.originalEvent.detail;
    if (record.params.bbox) {
      this.mapModel.set('bbox', record.params.bbox);
    }
    this.filtersModel.set('time', [record.start, record.end]);
  },

  onRecordMouseover(event) {
    const record = event.originalEvent.detail;
    this.mapModel.highlight(record.params);
  },

  onRecordMouseout(event) {
    const record = event.originalEvent.detail;
    this.mapModel.unHighlight(record.params);
  },

  onModelSelectionChanged(filtersModel) {
    const selection = filtersModel.get('time');
    this.timeSlider.select(selection[0], selection[1]);
  },

  // collection events

  onLayerAdded(layerModel) {
    this.addLayer(layerModel);
  },

  onLayerRemoved(layerModel) {
    this.removeLayer(layerModel);
  },

  onLayerChanged(layerModel) {
    if (layerModel.hasChanged('display')) {
      if (layerModel.get('display.visible') && !this.timeSlider.hasDataset(layerModel.get('id'))) {
        this.addLayer(layerModel);
      } else {
        this.removeLayer(layerModel);
      }
    }
  },
});

export default TimeSliderView;
<commit_msg>Fixing BBox check. Using searchAllRecords.<commit_after>window.d3 = require('d3/d3');

import Marionette from 'backbone.marionette';

const TimeSlider = require('D3.TimeSlider/src/d3.timeslider.coffee');
const WMSSource = require('D3.TimeSlider/src/sources/wms.coffee');
const EOWCSSource = require('D3.TimeSlider/src/sources/eowcs.coffee');
const WPSSource = require('D3.TimeSlider/src/sources/eoxserver-wps.coffee');

import { searchAllRecords } from '../../search';
import FiltersModel from '../models/FiltersModel';

// require('D3.TimeSlider/build/d3.timeslider.plugins');
require('D3.TimeSlider/src/d3.timeslider.less');
require('./TimeSliderView.css');

function intersects(a, b) {
  // adapted from http://gamedev.stackexchange.com/a/913/50029
  return !(a[0] > b[2]
    || a[2] < b[0]
    || a[3] < b[1]
    || a[1] > b[3]
  );
}

const TimeSliderView = Marionette.ItemView.extend(/** @lends core/views.TimeSliderView# */{
  template: () => '',

  events: {
    selectionChanged: 'onSelectionChanged',
    recordClicked: 'onRecordClicked',
    recordMouseover: 'onRecordMouseover',
    recordMouseout: 'onRecordMouseout',
  },

  /**
    @constructs
    @param {Object} options
    @param {core/models.FiltersModel} options.filtersModel The filters model to store the filters
    @param {core/models.LayersCollection} options.layersCollection The layers to show
                                                                   on the time slider
    @param {core/models.MapModel} options.mapModel The map-model
    @param {Date[]} options.domain The maximum domain to allow panning of th time slider
  */
  initialize(options) {
    this.filtersModel = options.filtersModel;
    this.layersCollection = options.layersCollection;

    this.mapModel = options.mapModel;

    this.domain = options.domain;
  },

  onRender() {

  },

  onAttach() {
    const options = {
      domain: this.domain,
      debounce: 300,
      ticksize: 8,
      datasets: [],
      recordFilter: this.createRecordFilter(this.mapModel.get('bbox')),
    };
    const time = this.filtersModel.get('time');
    if (time !== null) {
      options.brush = {
        start: time[0],
        end: time[1],
      };
    }

    this.timeSlider = new TimeSlider(this.el, options);

    const visibleLayers = this.layersCollection.filter(
      layerModel => layerModel.get('display.visible')
    );

    if (visibleLayers.length > 0) {
      visibleLayers.forEach(layerModel => this.addLayer(layerModel));
    } else {
      this.$el.css('display', 'none');
    }

    this.listenTo(this.filtersModel, 'change:time', this.onModelSelectionChanged);
    this.listenTo(this.layersCollection, 'add', this.onLayerAdded);
    this.listenTo(this.layersCollection, 'remove', this.onLayerRemoved);
    this.listenTo(this.layersCollection, 'change', this.onLayerChanged);
    this.listenTo(this.mapModel, 'change:bbox', (mapModel) => {
      this.timeSlider.setRecordFilter(this.createRecordFilter(mapModel.get('bbox')));
    });
  },

  addLayer(layerModel) {
    this.$el.fadeIn();
    let source;
    switch (layerModel.get('search').protocol) {
      case 'EOxServer-WPS':
        source = new WPSSource({
          url: layerModel.get('search').url || layerModel.get('search').urls[0],
          eoid: layerModel.get('search').id,
        });
        break;
      case 'EO-WCS':
      case 'OpenSearch':
        source = (start, end, params, callback) => {
          const filtersModel = new FiltersModel({ time: [start, end] });
          searchAllRecords(layerModel, filtersModel, null, { mimeType: 'application/atom+xml' }).then(result => {
            callback(result.records.map(record => {
              let time = null;
              const properties = record.properties;
              if (record.time) {
                time = record.time;
              } else if (properties) {
                // TODO: other property names than begin_time/end_time
                if (properties.begin_time && properties.end_time) {
                  time = [new Date(properties.begin_time), new Date(properties.end_time)];
                } else if (properties.time) {
                  if (Array.isArray(properties.time)) {
                    time = properties.time;
                  } else {
                    time = [properties.time];
                  }
                }
              }

              if (time === null) {
                return null;
              }

              return [...time, record];
            }).filter(item => item !== null));
          });
        };
        break;
      case 'WMS':
        source = new WMSSource({
          url: layerModel.get('search').url || layerModel.get('search').urls[0],
          layer: layerModel.get('search').id,
        });
        break;
      default:
        console.warn(`Unexpected search protocol ${layerModel.get('search').protocol}`);
        break;
    }

    this.timeSlider.addDataset({
      id: layerModel.get('id'),
      color: layerModel.get('displayColor'),
      source,
    });
  },

  removeLayer(layerModel) {
    this.timeSlider.removeDataset(layerModel.get('id'));
    const visibleLayers = this.layersCollection.filter(m => m.get('display.visible'));
    if (visibleLayers.length === 0) {
      this.$el.fadeOut();
    }
  },

  createRecordFilter(bbox) {
    return (record) => {
      const params = record[2];
      if (params && params.bbox) {
        if (bbox[0] < bbox[2]) {
          return intersects(bbox, params.bbox);
        }
        return intersects([-180, bbox[1], bbox[2], bbox[2]], params.bbox)
          | intersects([bbox[0], bbox[1], 180, bbox[2]], params.bbox);
      }
      return true;
    };
  },

  // two way binding of time selection

  onSelectionChanged(event) {
    const selection = event.originalEvent.detail;
    this.filtersModel.set('time', [selection.start, selection.end]);
  },

  onRecordClicked(event) {
    const record = event.originalEvent.detail;
    if (record.params.bbox) {
      this.mapModel.set('bbox', record.params.bbox);
    }
    this.filtersModel.set('time', [record.start, record.end]);
  },

  onRecordMouseover(event) {
    const record = event.originalEvent.detail;
    this.mapModel.highlight(record.params);
  },

  onRecordMouseout(event) {
    const record = event.originalEvent.detail;
    this.mapModel.unHighlight(record.params);
  },

  onModelSelectionChanged(filtersModel) {
    const selection = filtersModel.get('time');
    this.timeSlider.select(selection[0], selection[1]);
  },

  // collection events

  onLayerAdded(layerModel) {
    this.addLayer(layerModel);
  },

  onLayerRemoved(layerModel) {
    this.removeLayer(layerModel);
  },

  onLayerChanged(layerModel) {
    if (layerModel.hasChanged('display')) {
      if (layerModel.get('display.visible') && !this.timeSlider.hasDataset(layerModel.get('id'))) {
        this.addLayer(layerModel);
      } else {
        this.removeLayer(layerModel);
      }
    }
  },
});

export default TimeSliderView;
<|endoftext|>


<commit_before>var firstnames = [], lastnames = [], states = [], messages = [];
var slideAuthor, slideText, slideContent;
var backwardsSlide, forwardSlide;
var nextMessageTimeout = null;
var current = -1;
var blocked = false;
var hovering = false;
var loaded = false;
var xmlResource = "https://www.staatsschutz.at/appsrv/messages";
var timeout = 15000;

$(function () {
    findElements();
})

function htmlColToArray(xml, tagName) {
    var i, x, xmlDoc, nodeArray = [];
    xmlDoc = xml.responseXML;
    x = xmlDoc.getElementsByTagName(tagName);
    for (i = 0; i < x.length; i++) {
        nodeArray = nodeArray.concat([$("<div/>").text(x[i].childNodes[0].nodeValue).html()]);
    }
    return nodeArray;
}

function findElements() {
    slideAuthor = document.getElementById("slideauthor");
    slideText = document.getElementById("slidetext");
    slideContent = document.getElementById("slideContent");
    backwardsSlide = document.getElementById("slideleft");
    forwardSlide = document.getElementById("slideright");
    quoteFadeout = document.getElementById("quoteFadeout");
}

function setSlideScreen(index) {
    slideAuthor.innerHTML = firstnames[index] + " " + lastnames[index] + ", " + states[index];
    slideText.innerHTML = messages[index];
}

function getElements(xml) {
    firstnames = firstnames.concat(htmlColToArray(xml, "firstname"));
    lastnames = lastnames.concat(htmlColToArray(xml, "lastname"));
    states = states.concat(htmlColToArray(xml, "state"));
    messages = messages.concat(htmlColToArray(xml, "message"));
}

function openXML() {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (xhttp.readyState === 4 && xhttp.status === 200) {
            getElements(xhttp);
            findElements();
            loaded = true;
            forwardSlide.classList.remove("slideUnselectable");
            autoSlide();
        }
    };
    xhttp.open("GET", xmlResource, true);
    xhttp.send();
}

function loadNext() {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (xhttp.readyState === 4 && xhttp.status === 200) {
            getElements(xhttp);
        }
    };
    xhttp.open("GET", xmlResource, true);
    xhttp.send();
}

function slideForwards() {

    if (blocked || ! loaded)
        return;

    blocked = true;

    if (current == -1) {
        backwardsSlide.classList.add("slideUnselectable");
    } else if (current == 0) {
        backwardsSlide.classList.remove("slideUnselectable");
    } else if (current + 3 >= firstnames.length) {
        loadNext();
    }

    nextMessageTimeout && clearTimeout(nextMessageTimeout);
    nextMessageTimeout = setTimeout(autoSlide, timeout);

    current++;

    slideContent.classList.remove("slideBackwards");
    slideContent.classList.remove("slideForwards");
    slideContent.offsetWidth = slideContent.offsetWidth;
    slideContent.classList.add("slideForwards");

    setTimeout(function () {
        setSlideScreen(current);
        blocked = false;
    }, 300);
}

function slideBackwards() {
    if (blocked || ! loaded)
        return;

    blocked = true;

    if (current == 0) {
        blocked = false;
        return;
    } else if (current <= 1) {
        backwardsSlide.classList.add("slideUnselectable");
    }

    nextMessageTimeout && clearTimeout(nextMessageTimeout);
    nextMessageTimeout = setTimeout(autoSlide, timeout);

    current--;

    slideContent.classList.remove("slideBackwards");
    slideContent.classList.remove("slideForwards");
    slideContent.offsetWidth = slideContent.offsetWidth;
    slideContent.classList.add("slideBackwards");

    setTimeout(function () {
        setSlideScreen(current);
        blocked = false;
    }, 300);
}

function autoSlide() {
    if (!hovering) {
        slideForwards();
    }
}

$(document).ready(function(){
    $("#slider").hover(function () {
        hovering = true;
        var sHeight = $('#slidetext')[0].scrollHeight;
        $('#slidetext').css('height', sHeight + 'px');
        $('#fadeout').css('opacity', 0);
    }, function () {
        hovering = false;
        $('#slidetext').css('height', '2.3em');
        $('#fadeout').css('opacity', 1);
    });
});

window.onload = function () {
    openXML();
};
<commit_msg>fix automatic slider<commit_after>var firstnames = [], lastnames = [], states = [], messages = [];
var slideAuthor, slideText, slideContent;
var backwardsSlide, forwardSlide;
var nextMessageTimeout = null;
var current = -1;
var blocked = false;
var hovering = false;
var loaded = false;
var xmlResource = "https://www.staatsschutz.at/appsrv/messages";
var timeout = 15000;

//for testing purposes use
//var xmlResource = "./appsrv/messages";

$(function () {
    findElements();
})

function htmlColToArray(xml, tagName) {
    var i, x, xmlDoc, nodeArray = [];
    xmlDoc = xml.responseXML;
    x = xmlDoc.getElementsByTagName(tagName);
    for (i = 0; i < x.length; i++) {
        nodeArray = nodeArray.concat([$("<div/>").text(x[i].childNodes[0].nodeValue).html()]);
    }
    return nodeArray;
}

function findElements() {
    slideAuthor = document.getElementById("slideauthor");
    slideText = document.getElementById("slidetext");
    slideContent = document.getElementById("slideContent");
    backwardsSlide = document.getElementById("slideleft");
    forwardSlide = document.getElementById("slideright");
    quoteFadeout = document.getElementById("quoteFadeout");
}

function setSlideScreen(index) {
    slideAuthor.innerHTML = firstnames[index] + " " + lastnames[index] + ", " + states[index];
    slideText.innerHTML = messages[index];
}

function getElements(xml) {
    firstnames = firstnames.concat(htmlColToArray(xml, "firstname"));
    lastnames = lastnames.concat(htmlColToArray(xml, "lastname"));
    states = states.concat(htmlColToArray(xml, "state"));
    messages = messages.concat(htmlColToArray(xml, "message"));
}

function loadXML() {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (xhttp.readyState === 4 && xhttp.status === 200) {
            getElements(xhttp);
            if(!loaded) {
                loaded = true;
                forwardSlide.classList.remove("slideUnselectable");
                setTimeout(autoSlide, timeout);
            }
        }
    };
    xhttp.open("GET", xmlResource, true);
    xhttp.send();
}

function slideForwards() {

    if (blocked || ! loaded)
        return;

    blocked = true;

    if (current == -1) {
        backwardsSlide.classList.add("slideUnselectable");
    } else if (current == 0) {
        backwardsSlide.classList.remove("slideUnselectable");
    } else if (current + 3 >= firstnames.length) {
        loadXML();
    }

    nextMessageTimeout && clearTimeout(nextMessageTimeout);
    nextMessageTimeout = setTimeout(autoSlide, timeout);

    current++;

    slideContent.classList.remove("slideBackwards");
    slideContent.classList.remove("slideForwards");
    slideContent.offsetWidth = slideContent.offsetWidth;
    slideContent.classList.add("slideForwards");

    setTimeout(function () {
        setSlideScreen(current);
        blocked = false;
    }, 300);
}

function slideBackwards() {
    if (blocked || ! loaded)
        return;

    blocked = true;

    if (current == 0) {
        blocked = false;
        return;
    } else if (current <= 1) {
        backwardsSlide.classList.add("slideUnselectable");
    }

    nextMessageTimeout && clearTimeout(nextMessageTimeout);
    nextMessageTimeout = setTimeout(autoSlide, timeout);

    current--;

    slideContent.classList.remove("slideBackwards");
    slideContent.classList.remove("slideForwards");
    slideContent.offsetWidth = slideContent.offsetWidth;
    slideContent.classList.add("slideBackwards");

    setTimeout(function () {
        setSlideScreen(current);
        blocked = false;
    }, 300);
}

function autoSlide() {
    if (!hovering) {
        slideForwards();
    }
}

$(document).ready(function(){
    $("#slider").hover(function () {
        hovering = true;
        var sHeight = $('#slidetext')[0].scrollHeight;
        $('#slidetext').css('height', sHeight + 'px');
        $('#fadeout').css('opacity', 0);
    }, function () {
        hovering = false;
        $('#slidetext').css('height', '2.3em');
        $('#fadeout').css('opacity', 1);
    });
});

window.onload = function () {
    loadXML();
};
<|endoftext|>


<commit_before>udefine(['mixedice', 'eventmap', 'performance'], function(mixedice, EventMap, performance) {

  var Timer = function(interval) {
    mixedice([this, Timer.prototype], new EventMap());

    var self = this;

    this.interval = interval || 1000;
    this.startTime = -1;

    this.active = false;
    this.paused = false;

    var oldTicks = 0;

    this.tick = function(currentTime) {
      if (!self.active || self.paused) {
        return;
      }

      if (interval <= 0) {
        return;
      }

      self.trigger('tick');

      if ((currentTime - self.startTime - self.interval) > oldTicks) {
        oldTicks = currentTime;
        self.trigger('interval');
      }
    };
  };

  Timer.prototype.start = function() {
    this.active = true;
    this.paused = false;

    this.startTime = performance.now();

    this.trigger('start');
  };

  Timer.prototype.pause = function() {
    this.paused = true;

    this.trigger('pause');
  };

  Timer.prototype.unpause = function() {
    this.paused = false;

    this.trigger('unpause');
  };

  Timer.prototype.stop = function() {
    this.paused = false;
    this.active = false;

    this.trigger('stop');
  };

  return Timer;

});
<commit_msg>Tick event emits the currentTime<commit_after>udefine(['mixedice', 'eventmap', 'performance'], function(mixedice, EventMap, performance) {

  var Timer = function(interval) {
    mixedice([this, Timer.prototype], new EventMap());

    var self = this;

    this.interval = interval || 1000;
    this.startTime = -1;

    this.active = false;
    this.paused = false;

    var oldTicks = 0;

    this.tick = function(currentTime) {
      if (!self.active || self.paused) {
        return;
      }

      if (interval <= 0) {
        return;
      }

      self.trigger('tick', currentTime);

      if ((currentTime - self.startTime - self.interval) > oldTicks) {
        oldTicks = currentTime;
        self.trigger('interval');
      }
    };
  };

  Timer.prototype.start = function() {
    this.active = true;
    this.paused = false;

    this.startTime = performance.now();

    this.trigger('start');
  };

  Timer.prototype.pause = function() {
    this.paused = true;

    this.trigger('pause');
  };

  Timer.prototype.unpause = function() {
    this.paused = false;

    this.trigger('unpause');
  };

  Timer.prototype.stop = function() {
    this.paused = false;
    this.active = false;

    this.trigger('stop');
  };

  return Timer;

});
<|endoftext|>


<commit_before>// app.js
//
// A simple app toolkit. No magic. Reads data attributes in
// the DOM to bind dynamic data to controllers.
//
// Views
//
//

//
Hello world

//

//
// Where 'name' is the key of a view function in app.controllers and
// path.to.data points to an object in app.data.
//
// Template
//
//

//
{{ prop }}

//

//
// The template is stored as a DOM node in app.templates[name],
// and can be rendered with app.render(name, context), where
// context is an object with properties that match template tags
// such as {{ prop }}.

(function(jQuery, ns, undefined){
	"use strict";

	var doc = jQuery(document);

	var map = Array.prototype.map,
	    reduce = Array.prototype.reduce,
	    slice = Array.prototype.slice;

	var rcomment = /\{\%\s*.+?\s*\%\}/g,
	    rtag = /\{\{\s*(\w+)\s*\}\}/g,
	    rbracket = /\]$/,
	    rpathsplitter = /\]?\.|\[/g;

	var debug       = false;
	var controllers = {};
	var templates   = {};
	var data        = {};
	var features    = {
	    	template: 'content' in document.createElement('template')
	    };

	function noop() {}

	// Pure functions

	function isDefined(val) {
		return val !== undefined && val !== null;
	}

	function isObject(obj) {
		return obj instanceof Object;
	}

	// Object helpers

	function extend(obj) {
		var i = 0,
		    length = arguments.length,
		    obj2, key;

		while (++i < length) {
			obj2 = arguments[i];

			for (key in obj2) {
				if (obj2.hasOwnProperty(key)) {
					obj[key] = obj2[key];
				}
			}
		}

		return obj;
	}

	// DOM helpers

	function trigger(target, type) {
		var e;

		if (document.createEventObject) {
			e = document.createEventObject(window.event);
			target.fireEvent('on' + type, e);
		}
		else {
			e = document.createEvent('Event');
			e.initEvent(type, true, true, null);
			target.dispatchEvent(e);
		}
	}

	function append(parent, child) {
		parent.appendChild(child);
		return parent;
	}

	function replace(parent, child) {
		// Remove all children.
		while (parent.lastChild) {
			parent.removeChild(parent.lastChild);
		}

		// Append the template fragment.
		parent.appendChild(child);
		return parent;
	}

	function fragmentFromChildren(template) {
		var children = slice.apply(template.childNodes);
		var fragment = document.createDocumentFragment();
		return reduce.call(children, append, fragment);
	}

	function getTemplate(id) {
		var node = document.getElementById(id);

		if (!node) { return; }

		// A template tag has a content property that gives us a document
		// fragment. If that doesn't exist we must make a document fragment.
		return node.content || fragmentFromChildren(node);
	}

	function fetchTemplate(id) {
		var template = templates[id] || (templates[id] = getTemplate(id));

		if (debug && !template) {
			console.warn('[sparky] template #' + id + ' not found.');
		}

		return template && template.cloneNode(true);
	}

	// App

	function objFrom(obj, array) {
		var val = obj[array[0]],
		    slice = array.slice(1);

		return isDefined(val) && slice.length ?
			objFrom(val, slice) :
			val ;
	}

	function objFromPath(obj, path) {
		return objFrom(obj, path.replace(rbracket, '').split(rpathsplitter));
	}

	function objTo(root, array, obj) {
		var key = array[0];

		return array.length > 1 ?
			objTo(isObject(root[key]) ? root[key] : (root[key] = {}), array.slice(1), obj) :
			(root[key] = obj) ;
	}

	function objToPath(root, path, obj) {
		return objTo(root, path.split('.'), obj);
	}

	function setupView(node) {
		var viewPath = node.getAttribute('data-ctrl');
		var dataPath = node.getAttribute('data-model');

		sparky(node, dataPath, viewPath);
	}

	function onFrame(fn) {
		var flag = false;
		var context, args;

		function update() {
			flag = false;
			fn.apply(context, args);
		}

		return function change() {
			context = this;
			args = arguments;
			if (flag) { return; }
			flag = true;
			window.requestAnimationFrame(update);
		}
	}

	function sparky(node, dataPath, viewPath) {
		var view = typeof viewPath === 'string' ? objFromPath(sparky.controllers, viewPath) : console.log('viewPath not a string') ;
		var data = isDefined(dataPath) ?
		    	typeof dataPath === 'string' ?
		    		dataPath === '' ?
		    			sparky.data :
		    			objFromPath(sparky.data, dataPath) :
		    		dataPath :
		    	undefined ;

		var templateId = node.getAttribute && node.getAttribute('data-template');
		var templateFragment = templateId && fetchTemplate(templateId);
		var context, untemplate;

		function insertTemplate() {
			// Wait until the data is rendered on the next animation frame
			requestAnimationFrame(function() {
				replace(node, templateFragment);
				trigger(node, 'sparkytemplated');
			});

			insertTemplate = noop;
		};

		function insert() {
			insertTemplate(node, templateFragment);
		}

		function observe(property, fn) {
			sparky.observe(context, property, onFrame(fn));

			// Start off with populated nodes
			fn();

			if (templateFragment) {
				sparky.observe(context, property, insert);
			}
		}

		function unobserve(property, fn) {
			sparky.unobserve(context, property, fn);
		}

		function get(property) {
			return sparky.get(context, property);
		}

		function destroy() {
			untemplate && untemplate();
			untemplate = false;
			trigger(node, 'sparkydestroyed');
		}

		//if (debug) console.log('[app] view: "' + viewPath + (dataPath ? '" data: "' + dataPath + '"' : ''));
		//if (!view) { throw new Error('\'' + viewPath + '\' not found in app.controllers'); }
		if (data === undefined) { throw new Error('\'' + dataPath + '\' not found in sparky.data'); }

		if (debug) {
			console.log('view:', viewPath);
			console.log('data:', dataPath, data);
		}

		// If a context object is returned by the view, we use that, otherwise
		// we use the data object as context.
		context = view && view(node, data, destroy) || data;

		if (debug) {
			console.log('context:', context);
			console.log('template:', templateId);
		}

		// If there's no data to bind, we need go no further.
		if (!context) { return; }

		// The template function returns an untemplate function.
		untemplate = sparky.bind(templateFragment || node, observe, unobserve, get);

		trigger(node, 'sparkyready');
	}

	doc.ready(function(){
		var start = Date.now();

		jQuery('[data-ctrl], [data-model]').each(function() {
			if (debug) { console.groupCollapsed('[sparky] template', this); }

			setupView(this);

			if (debug) { console.groupEnd(); }
		});

		console.log('[sparky] Initialised templates and controllers (' + (Date.now() - start) + 'ms)');
	});

	// Expose

	sparky.debug       = debug;
	sparky.data        = data;
	sparky.controllers = controllers;
	sparky.templates   = templates;
	sparky.features    = features;
	sparky.template    = fetchTemplate;
	sparky.extend      = extend;
	sparky.onFrame     = onFrame;

	sparky.observe     = observe;
	sparky.unobserve   = unobserve;
	sparky.get         = function(data, property) {
		return data[property];
	};

	ns.sparky = sparky;
})(jQuery, this);<commit_msg>sparky -> Sparky, refactors internals a little.<commit_after>// app.js
//
// A simple app toolkit. No magic. Reads data attributes in
// the DOM to bind dynamic data to controllers.
//
// Views
//
//

//
Hello world

//

//
// Where 'name' is the key of a view function in app.controllers and
// path.to.data points to an object in app.data.
//
// Template
//
//

//
{{ prop }}

//

//
// The template is stored as a DOM node in app.templates[name],
// and can be rendered with app.render(name, scope), where
// scope is an object with properties that match template tags
// such as {{ prop }}.

(function(jQuery, ns, undefined){
	"use strict";

	var doc = jQuery(document);

	var map = Array.prototype.map,
	    reduce = Array.prototype.reduce,
	    slice = Array.prototype.slice;

	var rcomment = /\{\%\s*.+?\s*\%\}/g,
	    rtag = /\{\{\s*(\w+)\s*\}\}/g,
	    rbracket = /\]$/,
	    rpathsplitter = /\]?\.|\[/g;

	var debug       = false;
	var controllers = {};
	var templates   = {};
	var data        = {};
	var features    = {
	    	template: 'content' in document.createElement('template')
	    };

	function noop() {}

	// Pure functions

	function isDefined(val) {
		return val !== undefined && val !== null;
	}

	function isObject(obj) {
		return obj instanceof Object;
	}

	// Object helpers

	function extend(obj) {
		var i = 0,
		    length = arguments.length,
		    obj2, key;

		while (++i < length) {
			obj2 = arguments[i];

			for (key in obj2) {
				if (obj2.hasOwnProperty(key)) {
					obj[key] = obj2[key];
				}
			}
		}

		return obj;
	}

	// DOM helpers

	function trigger(target, type) {
		var e;

		if (document.createEventObject) {
			e = document.createEventObject(window.event);
			target.fireEvent('on' + type, e);
		}
		else {
			e = document.createEvent('Event');
			e.initEvent(type, true, true, null);
			target.dispatchEvent(e);
		}
	}

	function append(parent, child) {
		parent.appendChild(child);
		return parent;
	}

	function replace(parent, child) {
		// Remove all children.
		while (parent.lastChild) {
			parent.removeChild(parent.lastChild);
		}

		// Append the template fragment.
		parent.appendChild(child);
		return parent;
	}

	function fragmentFromChildren(template) {
		var children = slice.apply(template.childNodes);
		var fragment = document.createDocumentFragment();
		return reduce.call(children, append, fragment);
	}

	function getTemplate(id) {
		var node = document.getElementById(id);

		if (!node) { return; }

		// A template tag has a content property that gives us a document
		// fragment. If that doesn't exist we must make a document fragment.
		return node.content || fragmentFromChildren(node);
	}

	function fetchTemplate(id) {
		var template = templates[id] || (templates[id] = getTemplate(id));

		if (debug && !template) {
			console.warn('[Sparky] template #' + id + ' not found.');
		}

		return template && template.cloneNode(true);
	}

	// App

	function defaultCtrl(node, model) {
		return model;
	}

	function objFrom(obj, array) {
		var val = obj[array[0]],
		    slice = array.slice(1);

		return isDefined(val) && slice.length ?
			objFrom(val, slice) :
			val ;
	}

	function objFromPath(obj, path) {
		return objFrom(obj, path.replace(rbracket, '').split(rpathsplitter));
	}

	function objTo(root, array, obj) {
		var key = array[0];

		return array.length > 1 ?
			objTo(isObject(root[key]) ? root[key] : (root[key] = {}), array.slice(1), obj) :
			(root[key] = obj) ;
	}

	function objToPath(root, path, obj) {
		return objTo(root, path.split('.'), obj);
	}

	function setupView(node) {
		var viewPath = node.getAttribute('data-ctrl');
		var dataPath = node.getAttribute('data-model');

		sparky(node, dataPath, viewPath);
	}

	function onFrame(fn) {
		var flag = false;
		var scope, args;

		function update() {
			flag = false;
			fn.apply(scope, args);
		}

		return function change() {
			scope = this;
			args = arguments;
			if (flag) { return; }
			flag = true;
			window.requestAnimationFrame(update);
		}
	}

	function findByPath(obj, path) {
		return path !== undefined && objFromPath(obj, path);
	}

	var prototype = extend({}, ns.mixin.events);

	function Sparky(node, model, ctrl) {
		if (!model) {
			model = findByPath(Sparky.data, node.getAttribute('data-model'));
		}

		if (!ctrl) {
			ctrl = findByPath(Sparky.controllers, node.getAttribute('data-ctrl')) || defaultCtrl;
		}

		var sparky = Object.create(prototype);

		setupSparky(sparky, node, model, ctrl);

		return sparky;
	}

	function setupSparky(sparky, node, model, ctrl) {
		var templateId = node.getAttribute && node.getAttribute('data-template');
		var templateFragment = templateId && fetchTemplate(templateId);
		var scope, untemplate;

		function insertTemplate() {
			// Wait until the scope is rendered on the next animation frame
			requestAnimationFrame(function() {
				replace(node, templateFragment);
				sparky(node, 'templated');
			});

			insertTemplate = noop;
		};

		function insert() {
			insertTemplate(node, templateFragment);
		}

		function observe(property, fn) {
			Sparky.observe(scope, property, onFrame(fn));

			// Start off with populated nodes
			fn();

			if (templateFragment) {
				Sparky.observe(scope, property, insert);
			}
		}

		function unobserve(property, fn) {
			Sparky.unobserve(scope, property, fn);
		}

		function get(property) {
			return Sparky.get(scope, property);
		}

		sparky.node = node;

		sparky.destroy = function destroy() {
			untemplate && untemplate();
			untemplate = false;
			sparky.trigger('destroy');
		};

		if (model === undefined) { throw new Error('[Sparky] model not found in Sparky.data'); }

		if (debug) {
			console.log('ctrl:', ctrl);
			console.log('model:', model);
		}

		// If a scope object is returned by the ctrl, we use that, otherwise
		// we use the model object as scope.
		scope = ctrl && ctrl(node, model, sparky) || model;

		if (debug) {
			console.log('scope:', scope);
			console.log('template:', templateId);
		}

		// If there's no model to bind, we need go no further.
		if (!scope) { return; }

		// The template function returns an untemplate function.
		untemplate = Sparky.bind(templateFragment || node, observe, unobserve, get);

		sparky.trigger('ready');
	}

	doc.ready(function(){
		var start = Date.now();

		jQuery('[data-ctrl], [data-model]').each(function() {
			if (debug) { console.groupCollapsed('[Sparky] template', this); }

			Sparky(this);

			if (debug) { console.groupEnd(); }
		});

		console.log('[Sparky] DOM initialised (' + (Date.now() - start) + 'ms)');
	});

	// Expose

	Sparky.mixin       = ns.mixin || (ns.mixin = {});
	Sparky.events      = ns.events || (ns.events = {});
	Sparky.observe     = ns.observe;
	Sparky.unobserve   = ns.unobserve;
	Sparky.get         = function(data, property) {
		return data[property];
	};

	Sparky.debug       = debug;
	Sparky.data        = data;
	Sparky.controllers = controllers;
	Sparky.templates   = templates;
	Sparky.features    = features;
	Sparky.template    = fetchTemplate;
	Sparky.extend      = extend;

	ns.sparky = Sparky;
})(jQuery, this);<|endoftext|>


<commit_before>export class Tools {

  /**
   * Tools for the riot-view-router mixin.
   * @param {Router} router - Router for utilities to reference
   */
  constructor (router) {
    this.$router = router
  }

  /**
   * Used to mount state.
   * @param {object} state - State object for mounting.
   * @param {array}
   */
  transition (state, opts) {
    const self = this.$router

    return new Promise((resolve) => {
      if (self.$state) {
        const removable = riot.util.vdom.find((tag) => tag.root.localName == self.$state.tag)
        if (!removable) {
          self.$logger.error('(transition) Could not find a matching tag to unmount')
          reject()
        }
        removable.unmount()
      }
      const node = document.createElement(state.tag)
      self.context.appendChild(node)

      if (opts) {
        const parsed_opts = { }
        opts.forEach((opt) => {
          parsed_opts[opt.name] = opt.value
        }) // # add props
        parsed_opts.qargs = opts._query
        var tag = self.$riot.mount(state.tag, parsed_opts)
        if (state.title) {
          let title = self.titleRoot ? `${self.titleRoot} - ${state.title}` : state.title
          opts.forEach((opt) => title = title.replace(`<${opt.name}>`, opt.value))
          document.title = title
        }
      }
      else
        var tag = self.$riot.mount(state.tag)

      tag[0].on('updated', () => {
        if (self.running) {
          document.querySelectorAll(`[${self.$constants.defaults.anchorMarker}]`).forEach((el) => {
            el.onclick = function () {
              self.navigate(el.getAttribute(self.$constants.defaults.anchorMarker))
            }
          })
        }
      }) // # observable for binding sref occurrences
      tag[0].trigger('updated') // # trigger sref binding
      self._dispatch('transition', { state }).then(resolve).catch(resolve)
    })
  }

}
<commit_msg>formatting<commit_after>export class Tools {

  /**
   * Tools for the riot-view-router mixin.
   * @param {Router} router - Router for utilities to reference
   */
  constructor (router) {
    this.$router = router
  }

  /**
   * Used to mount state.
   * @param {object} state - State object for mounting.
   * @param {array}
   */
  transition (state, opts) {
    const self = this.$router

    return new Promise((resolve) => {
      if (self.$state) {
        const removable = riot.util.vdom.find((tag) => tag.root.localName == self.$state.tag)
        if (!removable) {
          self.$logger.error('(transition) Could not find a matching tag to unmount')
          reject()
        }
        removable.unmount()
      }
      const node = document.createElement(state.tag)
      self.context.appendChild(node)

      if (opts) {
        const parsed_opts = { }
        opts.forEach((opt) => {
          parsed_opts[opt.name] = opt.value
        }) // # add props
        parsed_opts.qargs = opts._query
        var tag = self.$riot.mount(state.tag, parsed_opts)
        if (state.title) {
          let title = self.titleRoot ? `${self.titleRoot} - ${state.title}` : state.title
          opts.forEach((opt) => title = title.replace(`<${opt.name}>`, opt.value))
          document.title = title
        }
      }
      else
        var tag = self.$riot.mount(state.tag)

      tag[0].on('updated', () => {
        if (self.running) {
          document.querySelectorAll(`[${self.$constants.defaults.anchorMarker}]`).forEach((el) => {
            el.onclick = function () {
              self.navigate(el.getAttribute(self.$constants.defaults.anchorMarker))
            }
          })
        }
      }) // # observable for binding sref occurrences
      tag[0].trigger('updated') // # trigger sref binding

      self._dispatch('transition', { state }).then(resolve).catch(resolve)
    })
  }

}
<|endoftext|>


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

  canvas = document.getElementById('map-canvas');
  $layerControl = $('#layer-control');

  var map;
  var layersDrawn = [];

  function drawLayerControls (layersDrawn) {
    var $layerList = $('<ul>');

    $.each(layersDrawn, function (i, layer){
      i++;
      $layer = $('<li>');
      $layer.append(drawLayerCheckbox(i, layer));
      $layerList.append($layer);
    });

    $layerControl.append($layerList);
  }

  function drawLayerCheckbox (id, layer) {
    var $label = $('<label>');
    var $checkbox = $('<input type="checkbox" id="layer_'+ id +'">');

    $checkbox.attr("checked", true);

    $checkbox.click(function (){
      layer.setMap($(this).is(':checked') ? map : null);
    });

    $label
      .append($checkbox)
      .append(layer.layerOriginal.name);

    return $label;
  }

  function initializeMap() {
    var mapOptions = {
      // WA State
      // center: new google.maps.LatLng(-27.288135,121.972796),
      // Perth
      center: new google.maps.LatLng(-31.9528536,115.8573389),
      clickable: true,
      streetViewControl: false,
      // Only show default (road) map
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      zoom: 10,
      maxZoom: 0,
      minZoom: 10
    };

    map = new google.maps.Map(canvas, mapOptions);

    $.each(MapAllTheThings.slip_layers, function(i, layerObject) {
      var layer = new google.maps.visualization.MapsEngineLayer({
        layerId: layerObject.assetId,
        layerOriginal: layerObject,
        map: map
      });

      layersDrawn.push(layer);
    });

    drawLayerControls(layersDrawn);
  }

 if(canvas)  google.maps.event.addDomListener(window, 'load', initializeMap);

});
<commit_msg>fixed wizard<commit_after>$(document).ready(function () {

  canvas = document.getElementById('map-canvas');
  $layerControl = $('#layer-control');

  var map;
  var layersDrawn = [];

  function drawLayerControls (layersDrawn) {
    var $layerList = $('<ul>');

    $.each(layersDrawn, function (i, layer){
      i++;
      $layer = $('<li>');
      $layer.append(drawLayerCheckbox(i, layer));
      $layerList.append($layer);
    });

    $layerControl.append($layerList);
  }

  function drawLayerCheckbox (id, layer) {
    var $label = $('<label>');
    var $checkbox = $('<input type="checkbox" id="layer_'+ id +'">');

    $checkbox.attr("checked", true);

    $checkbox.click(function (){
      layer.setMap($(this).is(':checked') ? map : null);
    });

    $label
      .append($checkbox)
      .append(layer.layerOriginal.name);

    return $label;
  }

  function initializeMap() {
    var mapOptions = {
      // WA State
      // center: new google.maps.LatLng(-27.288135,121.972796),
      // Perth
      center: new google.maps.LatLng(-31.9528536,115.8573389),
      clickable: true,
      streetViewControl: false,
      // Only show default (road) map
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      zoom: 10,
      minZoom: 5,
      maxZoom: 18
    };

    map = new google.maps.Map(canvas, mapOptions);

    $.each(MapAllTheThings.slip_layers, function(i, layerObject) {
      var layer = new google.maps.visualization.MapsEngineLayer({
        layerId: layerObject.assetId,
        layerOriginal: layerObject,
        map: map
      });

      layersDrawn.push(layer);
    });

    drawLayerControls(layersDrawn);
  }

 if(canvas)  google.maps.event.addDomListener(window, 'load', initializeMap);

});
<|endoftext|>


<commit_before>splasha.innerHTML = "Pausa estiva Aggiunto un video sulla dislessia nella sezione DSA e PDP e materiali della prof.ssa Chiocca. Presto verrà assegnato un badge per chi prenderà visione del materiale.";
splashb.innerHTML = "Pausa estiva Aggiunto un video sulla dislessia nella sezione DSA e PDP e materiali della prof.ssa Chiocca. Presto verrà assegnato un badge per chi prenderà visione del materiale.";
splashc.innerHTML = "Pausa estiva Aggiunto un video sulla dislessia nella sezione DSA e PDP e materiali della prof.ssa Chiocca. Presto verrà assegnato un badge per prenderà visione del materiale.";
<commit_msg>Update splash.js<commit_after>var content = "New";
var content += "Un nuovo video sull'autismo (realizzato con la collaborazione del prof. Tony Attwood, esperto dell'autismo)"
var thumbup = ";

splasha.innerHTML = content + thumbup
splashb.innerHTML = content + thumbup
splashc.innerHTML = content + thumbup
<|endoftext|>