<commit_before>/* Copyright 2015 Bloomberg Finance L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define(["d3", "./Mark"], function(d3, MarkViewModule) {
    "use strict";

    var Label = MarkViewModule.Mark.extend({
        render: function() {
            var base_render_promise = Label.__super__.render.apply(this);
            var that = this;

            //TODO: create_listeners is put inside the promise success handler
            //because some of the functions depend on child scales being
            //created. Make sure none of the event handler functions make that
            //assumption.
            this.drag_listener = d3.behavior.drag()
              //.origin(function() { return that.drag_origin(); })
              .on("dragstart", function() { return that.drag_start(); })
              .on("drag", function() { return that.on_drag(); })
              .on("dragend", function() { return that.drag_ended(); });
            return base_render_promise.then(function() {
                that.create_listeners();
                that.draw();
            });
        },
        set_ranges: function() {
            var x_scale = this.scales.x;
            if(x_scale) {
                x_scale.set_range(this.parent.padded_range("x", x_scale.model));
            }
            var y_scale = this.scales.y;
            if(y_scale) {
                y_scale.set_range(this.parent.padded_range("y", y_scale.model));
            }
        },
        set_positional_scales: function() {
            this.x_scale = this.scales.x;
            this.y_scale = this.scales.y;
            // If no scale for "x" or "y" is specified, figure scales are used.
            if(!this.x_scale) {
                this.x_scale = this.parent.scale_x;
            }
            if(!this.y_scale) {
                this.y_scale = this.parent.scale_y;
            }
            this.listenTo(this.x_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.draw(); }
            });
            this.listenTo(this.y_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.draw(); }
            });
        },
        create_listeners: function() {
            Label.__super__.create_listeners.apply(this);
            this.listenTo(this.model, "change:text", this.update_text, this);
            this.model.on_some_change(["font_weight", "font_size", "color",
                                       "align"], this.update_style, this);
            this.model.on_some_change(["x", "y", "x_offset", "y_offset",
                                       "rotate_angle"], this.update_position, this);
        },
        relayout: function() {
            this.set_ranges();
            this.update_position();
        },
        draw: function() {
            this.set_ranges();
            this.el.selectAll(".label")
                .remove();

            this.el.append("text")
                .text(this.model.get("text"))
                .classed("label", true)
                .call(this.drag_listener);
            this.update_style();
            this.update_position();
        },
        get_rotation: function() {
            var rotate_angle = this.model.get("rotate_angle");
            var transform = "";
            if(rotate_angle !== undefined) {
                transform += " rotate(" + rotate_angle + ")";
            }
            return transform;
        },
        update_position: function() {
            var x = (this.x_scale.model.type === "date") ?
                this.model.get_date_elem("x") : this.model.get("x");
            var y = (this.y_scale.model.type === "date") ?
                this.model.get_date_elem("y") : this.model.get("y");
            var x_offset = this.model.get("x_offset"),
                y_offset = this.model.get("y_offset");
            this.el.select(".label")
                .attr("transform", "translate(" +
                    (this.x_scale.scale(x) + this.x_scale.offset + x_offset) + "," +
                    (this.y_scale.scale(y) + this.y_scale.offset + y_offset) + ")" +
                    this.get_rotation());
        },
        update_text: function(model, value) {
            this.el.select(".label")
                .text(value);
        },
        update_style: function() {
            this.el.select(".label")
                .style("font-size", this.model.get("font_size"))
                .style("font-weight", this.model.get("font_weight"))
                .style("text-anchor", this.model.get("align"));

            var color = this.model.get("color");
            if(color !== undefined) {
                this.el.select(".label")
                    .style("fill", color);
            }
        },
        //drag_origin: function() {
          //  return;
        //},
        drag_start: function() {
            if (!this.model.get("enable_move")) {
                return;
            }
            this.drag_started = true;
            this.drag_start_position = d3.mouse(this.el.node());
        },

        on_drag: function() {
            if(!this.drag_started){
                return;
            }
            if(!this.model.get("enable_move")) {
                return;
            }
            //var label = this.el.select(".label");
            //label.attr("x", d3.event.x).attr("y", d3.event.y);
        },

        drag_ended: function() {
            if (!this.model.get("enable_move")) {
                return;
            }
            if (!this.drag_started) {
                return;
            }
            var move_x = d3.mouse(this.el.node())[0] - this.drag_start_position[0],
                move_y = d3.mouse(this.el.node())[1] - this.drag_start_position[1];

            var new_x = this.x_scale.invert(this.x_scale.scale(this.model.get("x")) + move_x),
                new_y = this.y_scale.invert(this.y_scale.scale(this.model.get("y")) + move_y);

            this.model.set("x", new_x);
            this.model.set("y", new_y);
            this.touch()
        },
    });

    return {
        Label: Label,
    };
});

<commit_msg>add listener for enable_move<commit_after>/* Copyright 2015 Bloomberg Finance L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define(["d3", "./Mark"], function(d3, MarkViewModule) {
    "use strict";

    var Label = MarkViewModule.Mark.extend({
        render: function() {
            var base_render_promise = Label.__super__.render.apply(this);
            var that = this;

            //TODO: create_listeners is put inside the promise success handler
            //because some of the functions depend on child scales being
            //created. Make sure none of the event handler functions make that
            //assumption.
            this.drag_listener = d3.behavior.drag()
              .origin(function() { return that.drag_origin(); })
              .on("drag", function() { return that.on_drag(); })
              .on("dragend", function() { return that.drag_ended(); });
            return base_render_promise.then(function() {
                that.create_listeners();
                that.draw();
            });
        },
        set_ranges: function() {
            var x_scale = this.scales.x;
            if(x_scale) {
                x_scale.set_range(this.parent.padded_range("x", x_scale.model));
            }
            var y_scale = this.scales.y;
            if(y_scale) {
                y_scale.set_range(this.parent.padded_range("y", y_scale.model));
            }
        },
        set_positional_scales: function() {
            this.x_scale = this.scales.x;
            this.y_scale = this.scales.y;
            // If no scale for "x" or "y" is specified, figure scales are used.
            if(!this.x_scale) {
                this.x_scale = this.parent.scale_x;
            }
            if(!this.y_scale) {
                this.y_scale = this.parent.scale_y;
            }
            this.listenTo(this.x_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.draw(); }
            });
            this.listenTo(this.y_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.draw(); }
            });
        },
        create_listeners: function() {
            Label.__super__.create_listeners.apply(this);
            this.listenTo(this.model, "change:text", this.update_text, this);
            this.listenTo(this.model, "change:enable_move", this.set_drag_behavior);
            this.model.on_some_change(["font_weight", "font_size", "color",
                                       "align"], this.update_style, this);
            this.model.on_some_change(["x", "y", "x_offset", "y_offset",
                                       "rotate_angle"], this.update_position, this);
        },
        relayout: function() {
            this.set_ranges();
            this.update_position();
        },
        draw: function() {
            this.set_ranges();
            this.el.selectAll(".label")
                .remove();

            this.el.append("text")
                .text(this.model.get("text"))
                .classed("label", true);

            this.set_drag_behavior();
            this.update_style();
            this.update_position();
        },
        get_rotation: function() {
            var rotate_angle = this.model.get("rotate_angle");
            var transform = "";
            if(rotate_angle !== undefined) {
                transform += " rotate(" + rotate_angle + ")";
            }
            return transform;
        },
        update_position: function() {
            var x = (this.x_scale.model.type === "date") ?
                this.model.get_date_elem("x") : this.model.get("x");
            var y = (this.y_scale.model.type === "date") ?
                this.model.get_date_elem("y") : this.model.get("y");
            var x_offset = this.model.get("x_offset"),
                y_offset = this.model.get("y_offset");
            this.el.select(".label")
                .attr("transform", "translate(" +
                    (this.x_scale.scale(x) + this.x_scale.offset + x_offset) + "," +
                    (this.y_scale.scale(y) + this.y_scale.offset + y_offset) + ")" +
                    this.get_rotation());
        },
        update_text: function(model, value) {
            this.el.select(".label")
                .text(value);
        },
        update_style: function() {
            this.el.select(".label")
                .style("font-size", this.model.get("font_size"))
                .style("font-weight", this.model.get("font_weight"))
                .style("text-anchor", this.model.get("align"));

            var color = this.model.get("color");
            if(color !== undefined) {
                this.el.select(".label")
                    .style("fill", color);
            }
        },
        set_drag_behavior: function() {
            var label = this.el.select(".label");
            if (this.model.get("enable_move")) {
                label.call(this.drag_listener)
                    .style("cursor", "move");
            }
            else {
                label.on(".drag", null).style("cursor", "default");
            }
        },
        drag_origin: function() {
            var transform = d3.transform(this.el.select(".label").attr("transform"));
            return {x: transform.translate[0], y: transform.translate[1]};
        },
        on_drag: function() {
            var transform = d3.transform(this.el.select(".label").attr("transform"));
            transform.translate = [d3.event.x, d3.event.y];
            this.el.select(".label")
                .attr("transform", transform.toString());
        },
        drag_ended: function() {
            var transform = d3.transform(this.el.select(".label").attr("transform"));
            var new_x = this.x_scale.invert(transform.translate[0] - this.model.get("x_offset")),
                new_y = this.y_scale.invert(transform.translate[1] - this.model.get("y_offset"));

            this.model.set("x", new_x);
            this.model.set("y", new_y);
            this.touch()
        },
    });

    return {
        Label: Label,
    };
});

<|endoftext|>


<commit_before>var mongo = require('mongodb');
var _ = require("underscore");

var Server = mongo.Server,
    Db = mongo.Db,
    BSON = mongo.BSONPure,
    BANDS = 'bands',
    MEMBERS = 'members',
    ALBUMS = 'albums';

var bandApp = {};

var server = new Server('localhost', 27017, {auto_reconnect: true});
db = new Db('banddb', server);

db.open(function(err, db) {
  if (!err) {
    console.log("Connected to 'banddb' database");
    db.collection(BANDS, {strict: true}, function(err, collection) {
      if (err) {
        console.log("The collection does not exist, creating a new one");
        populateDB();
      }
    });
  }
});

bandApp.findAll = function(collectionName, req, res) {
  console.log('Find all', collectionName);
  db.collection(collectionName, function(err, collection) {
    collection.find().toArray(function(err, items) {
      res.send(items);
    });
  });
};

bandApp.findById = function(collectionName, req, res) {
  var id = req.params.id;
  console.log('Find by id', collectionName, id);
  db.collection(collectionName, function(err, collection) {
    collection.findOne({'_id': new BSON.ObjectID(id)}, function(err, item) {
      res.send(item);
    });
  });
};

bandApp.createItem = function(collectionName, req, res) {
  var item = req.body;
  console.log('Adding item', collectionName, JSON.stringify(item));
  db.collection(collectionName, function(err, collection) {
    collection.insert(item, {safe: true}, function(err, result) {
      if (err) {
        res.send({'error': 'An error has occurred'});
      } else {
        console.log('Success: ' + JSON.stringify(result[0]));
        res.send(result[0]);
      }
    });
  });
};

bandApp.updateItem = function(collectionName, req, res) {
  var id = req.params.id;
  var item = req.body;
  console.log('Updating item', collectionName, id);
  console.log(JSON.stringify(item));
  db.collection(collectionName, function(err, collection) {
    collection.update({'_id': new BSON.ObjectID(id)}, item, {safe: true}, function(err, result) {
      if (err) {
        console.log('Error updating item: ' + err);
        res.send({'error': 'An error has occurred'});
      } else {
        console.log('' + result + ' document(s) updated');
        res.send(item);
      }
    });
  });
};

bandApp.deleteItem = function(collectionName, req, res) {
  var id = req.params.id;
  console.log('Deleting item', collectionName, id);
  db.collection(collectionName, function(err, collection) {
    collection.remove({'_id': new BSON.ObjectID(id)}, {safe: true}, function(err, result) {
      if (err) {
        res.send({'error': 'An error has occurred - ' + err});
      } else {
        console.log('' + result + ' document(s) deleted');
        res.send(req.body);
      }
    });
  });
};

// Find all.
exports.findAllBands = _.partial(bandApp.findAll, BANDS);
exports.findAllAlbums = _.partial(bandApp.findAll, ALBUMS);
exports.findAllMembers = _.partial(bandApp.findAll, MEMBERS);

// Find by id.
exports.findBandById = _.partial(bandApp.findById, BANDS);
exports.findAlbumById = _.partial(bandApp.findById, ALBUMS);
exports.findMemberById = _.partial(bandApp.findById, MEMBERS);

// Create
exports.createBand = _.partial(bandApp.createItem, BANDS);
exports.createAlbum = _.partial(bandApp.createItem, ALBUMS);
exports.createMember = _.partial(bandApp.createItem, MEMBERS);

// Update
exports.updateBand = _.partial(bandApp.updateItem, BANDS);
exports.updateAlbum = _.partial(bandApp.updateItem, ALBUMS);
exports.updateMember = _.partial(bandApp.updateItem, MEMBERS);

// Delete
exports.deleteBand = _.partial(bandApp.deleteItem, BANDS);
exports.deleteAlbum = _.partial(bandApp.deleteItem, ALBUMS);
exports.deleteMember = _.partial(bandApp.deleteItem, MEMBERS);

var populateDB = function() {
  var bands = [
    {
      name: 'Wu-Tang Clan',
      albums: [],
      members: []
    },
    {
      name: 'The Police',
      albums: [],
      members: []
    }
  ];

  var members = [
    {
      name: 'Sting'
    },
    {
      name: 'Method Man'
    },
    {
      name: 'Ghostface Killah'
    }
  ];

  var albums = [
      {
        name: 'Synchronicity'
      }
  ];

  db.collection(BANDS, function(err, collection) {
    collection.insert(bands, {safe:true}, function(err, result) {});
  });
  db.collection(ALBUMS, function(err, collection) {
    collection.insert(albums, {safe:true}, function(err, result) {});
  });
  db.collection(MEMBERS, function(err, collection) {
    collection.insert(members, {safe:true}, function(err, result) {});
  });
};<commit_msg>fewer default items<commit_after>var mongo = require('mongodb');
var _ = require("underscore");

var Server = mongo.Server,
    Db = mongo.Db,
    BSON = mongo.BSONPure,
    BANDS = 'bands',
    MEMBERS = 'members',
    ALBUMS = 'albums';

var bandApp = {};

var server = new Server('localhost', 27017, {auto_reconnect: true});
db = new Db('banddb', server);

db.open(function(err, db) {
  if (!err) {
    console.log("Connected to 'banddb' database");
    db.collection(BANDS, {strict: true}, function(err, collection) {
      if (err) {
        console.log("The collection does not exist, creating a new one");
        populateDB();
      }
    });
  }
});

bandApp.findAll = function(collectionName, req, res) {
  console.log('Find all', collectionName);
  db.collection(collectionName, function(err, collection) {
    collection.find().toArray(function(err, items) {
      res.send(items);
    });
  });
};

bandApp.findById = function(collectionName, req, res) {
  var id = req.params.id;
  console.log('Find by id', collectionName, id);
  db.collection(collectionName, function(err, collection) {
    collection.findOne({'_id': new BSON.ObjectID(id)}, function(err, item) {
      res.send(item);
    });
  });
};

bandApp.createItem = function(collectionName, req, res) {
  var item = req.body;
  console.log('Adding item', collectionName, JSON.stringify(item));
  db.collection(collectionName, function(err, collection) {
    collection.insert(item, {safe: true}, function(err, result) {
      if (err) {
        res.send({'error': 'An error has occurred'});
      } else {
        console.log('Success: ' + JSON.stringify(result[0]));
        res.send(result[0]);
      }
    });
  });
};

bandApp.updateItem = function(collectionName, req, res) {
  var id = req.params.id;
  var item = req.body;
  console.log('Updating item', collectionName, id);
  console.log(JSON.stringify(item));
  db.collection(collectionName, function(err, collection) {
    collection.update({'_id': new BSON.ObjectID(id)}, item, {safe: true}, function(err, result) {
      if (err) {
        console.log('Error updating item: ' + err);
        res.send({'error': 'An error has occurred'});
      } else {
        console.log('' + result + ' document(s) updated');
        res.send(item);
      }
    });
  });
};

bandApp.deleteItem = function(collectionName, req, res) {
  var id = req.params.id;
  console.log('Deleting item', collectionName, id);
  db.collection(collectionName, function(err, collection) {
    collection.remove({'_id': new BSON.ObjectID(id)}, {safe: true}, function(err, result) {
      if (err) {
        res.send({'error': 'An error has occurred - ' + err});
      } else {
        console.log('' + result + ' document(s) deleted');
        res.send(req.body);
      }
    });
  });
};

// Find all.
exports.findAllBands = _.partial(bandApp.findAll, BANDS);
exports.findAllAlbums = _.partial(bandApp.findAll, ALBUMS);
exports.findAllMembers = _.partial(bandApp.findAll, MEMBERS);

// Find by id.
exports.findBandById = _.partial(bandApp.findById, BANDS);
exports.findAlbumById = _.partial(bandApp.findById, ALBUMS);
exports.findMemberById = _.partial(bandApp.findById, MEMBERS);

// Create
exports.createBand = _.partial(bandApp.createItem, BANDS);
exports.createAlbum = _.partial(bandApp.createItem, ALBUMS);
exports.createMember = _.partial(bandApp.createItem, MEMBERS);

// Update
exports.updateBand = _.partial(bandApp.updateItem, BANDS);
exports.updateAlbum = _.partial(bandApp.updateItem, ALBUMS);
exports.updateMember = _.partial(bandApp.updateItem, MEMBERS);

// Delete
exports.deleteBand = _.partial(bandApp.deleteItem, BANDS);
exports.deleteAlbum = _.partial(bandApp.deleteItem, ALBUMS);
exports.deleteMember = _.partial(bandApp.deleteItem, MEMBERS);

var populateDB = function() {
  var bands = [
    {
      name: 'Wu-Tang Clan',
      albums: [],
      members: []
    }
  ];

  var members = [
    {
      name: 'Method Man'
    },
    {
      name: 'Ghostface Killah'
    }
  ];

  var albums = [
      {
        name: 'Synchronicity'
      }
  ];

  db.collection(BANDS, function(err, collection) {
    collection.insert(bands, {safe:true}, function(err, result) {});
  });
  db.collection(ALBUMS, function(err, collection) {
    collection.insert(albums, {safe:true}, function(err, result) {});
  });
  db.collection(MEMBERS, function(err, collection) {
    collection.insert(members, {safe:true}, function(err, result) {});
  });
};
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @ts-nocheck
// TODO(crbug.com/1011811): Enable TypeScript compiler checks

import * as Common from '../common/common.js';  // eslint-disable-line no-unused-vars
import * as UI from '../ui/ui.js';

/**
 * @enum {number}
 */
const MessageLevelBitfield = {
  Error: 0b0001,
  Warning: 0b0010,
  Info: 0b0100,
  Debug: 0b1000,

  Default: 0b0111,  // Error, Warning, Info
  All: 0b1111,      // Error, Warning, Info, Debug
  Custom: 0
};

/**
 * @typedef {{
 *     title: string,
 *     value: MessageLevelBitfield,
 *     stringValue: string,
 *     selectable: boolean
 * }}
 */
let SelectableLevel;  // eslint-disable-line no-unused-vars

/**
 * @implements {UI.SoftDropDown.Delegate<!SelectableLevel>}
 */
class MessageLevelSelector extends Common.ObjectWrapper.ObjectWrapper {
  constructor(items, view) {
    super();
    this._items = items;
    this._view = view;
    this._itemMap = new Map();
    this._hiddenLevels = [];

    this._bitFieldValue = MessageLevelBitfield.Default;
    this._savedBitFieldValue = MessageLevelBitfield.Default;

    this._defaultTitle = ls`Default`;
    this._customTitle = ls`Custom`;
    this._allTitle = ls`All`;
  }

  defaultTitle() {
    return this._defaultTitle;
  }

  // UI.SoftDropDown
  setDefault(dropdown) {
    dropdown.selectItem(this._items.at(0));
  }

  populate() {
    this._items.insert(
        this._items.length,
        {title: this._defaultTitle, overwrite: true, stringValue: '', value: MessageLevelBitfield.Default});

    this._items.insert(
        this._items.length, {title: this._allTitle, overwrite: true, stringValue: '', value: MessageLevelBitfield.All});

    this._items.insert(
        this._items.length,
        {title: ls`Error`, overwrite: false, stringValue: 'error', value: MessageLevelBitfield.Error});

    this._items.insert(
        this._items.length,
        {title: ls`Warning`, overwrite: false, stringValue: 'warning', value: MessageLevelBitfield.Warning});

    this._items.insert(
        this._items.length, {title: ls`Info`, overwrite: false, stringValue: 'info', value: MessageLevelBitfield.Info});

    this._items.insert(
        this._items.length,
        {title: ls`Debug`, overwrite: false, stringValue: 'debug', value: MessageLevelBitfield.Debug});
  }

  _updateCheckMarks() {
    this._hiddenLevels = [];
    for (const [key, item] of this._itemMap) {
      if (!item.overwrite) {
        if (item.element.firstChild) {
          item.element.firstChild.remove();
        }
        if (key & this._bitFieldValue) {
          item.element.createChild('div').createTextChild('✓');
        } else {
          this._hiddenLevels.push(item.stringValue);
        }
      }
    }
  }

  /**
   * @override
   * @param {!SelectableLevel} item
   * @return {string}
   */
  titleFor(item) {
    // This would make a lot more sense to have in |itemSelected|, but this
    // method gets called first.
    if (item.overwrite) {
      this._bitFieldValue = item.value;
    } else {
      this._bitFieldValue ^= item.value;
    }

    if (this._bitFieldValue === MessageLevelBitfield.Default) {
      return this._defaultTitle;
    }

    if (this._bitFieldValue === MessageLevelBitfield.All) {
      return this._allTitle;
    }

    const potentialMatch = this._itemMap.get(this._bitFieldValue);
    if (potentialMatch) {
      return potentialMatch.title;
    }

    return this._customTitle;
  }

  /**
   * @override
   * @param {!SelectableLevel} item
   * @return {!Element}
   */
  createElementForItem(item) {
    const element = document.createElementWithClass('div');
    const shadowRoot = UI.Utils.createShadowRootWithCoreStyles(element, 'media/playerMessagesView.css');
    const container = shadowRoot.createChild('div', 'media-messages-level-dropdown-element');
    const checkBox = container.createChild('div', 'media-messages-level-dropdown-checkbox');
    const text = container.createChild('span', 'media-messages-level-dropdown-text');
    text.createTextChild(item.title);
    item.element = checkBox;
    this._itemMap.set(item.value, item);
    this._updateCheckMarks();
    this._view.regenerateMessageDisplayCss(this._hiddenLevels);
    return element;
  }

  /**
   * @override
   * @param {!SelectableLevel} item
   * @return {boolean}
   */
  isItemSelectable(item) {
    return true;
  }

  /**
   * @override
   * @param {?SelectableLevel} item
   */
  itemSelected(item) {
    this._updateCheckMarks();
    this._view.regenerateMessageDisplayCss(this._hiddenLevels);
  }

  /**
   * @override
   * @param {?SelectableLevel} from
   * @param {?SelectableLevel} to
   * @param {?Element} fromElement
   * @param {?Element} toElement
   */
  highlightedItemChanged(from, to, fromElement, toElement) {
  }
}

export class PlayerMessagesView extends UI.Widget.VBox {
  constructor() {
    super();
    this.registerRequiredCSS('media/playerMessagesView.css');

    this._headerPanel = this.contentElement.createChild('div', 'media-messages-header');
    this._bodyPanel = this.contentElement.createChild('div', 'media-messages-body');

    this._buildToolbar();
  }

  _buildToolbar() {
    const toolbar = new UI.Toolbar.Toolbar('media-messages-toolbar', this._headerPanel);
    toolbar.appendText(ls`Log level:`);
    toolbar.appendToolbarItem(this._createDropdown());
    toolbar.appendSeparator();
    toolbar.appendToolbarItem(this._createFilterInput());
  }

  _createDropdown() {
    /** @type {!UI.ListModel.ListModel<!SelectableLevel>} */
    const items = new UI.ListModel.ListModel();
    /** @type {!MessageLevelSelector} **/
    this._messageLevelSelector = new MessageLevelSelector(items, this);
    /** @type {!UI.SoftDropDown.SoftDropDown<!SelectableLevel>} */
    const dropDown = new UI.SoftDropDown.SoftDropDown(items, this._messageLevelSelector);
    dropDown.setRowHeight(18);

    this._messageLevelSelector.populate();
    this._messageLevelSelector.setDefault(dropDown);

    const dropDownItem = new UI.Toolbar.ToolbarItem(dropDown.element);
    dropDownItem.element.classList.add('toolbar-has-dropdown');
    dropDownItem.setEnabled(true);
    dropDownItem.setTitle(this._messageLevelSelector.defaultTitle());
    return dropDownItem;
  }

  _createFilterInput() {
    const filterInput = new UI.Toolbar.ToolbarInput(ls`Filter log messages`);
    filterInput.addEventListener(UI.Toolbar.ToolbarInput.Event.TextChanged, this._filterByString, this);
    return filterInput;
  }

  regenerateMessageDisplayCss(hiddenLevels) {
    const messages = this._bodyPanel.getElementsByClassName('media-messages-message-container');
    for (const message of messages) {
      if (this._matchesHiddenLevels(message, hiddenLevels)) {
        message.classList.add('media-messages-message-unselected');
      } else {
        message.classList.remove('media-messages-message-unselected');
      }
    }
  }

  _matchesHiddenLevels(element, hiddenLevels) {
    for (const level of hiddenLevels) {
      if (element.classList.contains('media-message-' + level)) {
        return true;
      }
    }
    return false;
  }

  _filterByString(userStringData) {
    const userString = userStringData.data;
    const messages = this._bodyPanel.getElementsByClassName('media-messages-message-container');

    for (const message of messages) {
      if (userString === '') {
        message.classList.remove('media-messages-message-filtered');
      } else if (message.textContent.includes(userString)) {
        message.classList.remove('media-messages-message-filtered');
      } else {
        message.classList.add('media-messages-message-filtered');
      }
    }
  }

  addMessage(message) {
    const container =
        this._bodyPanel.createChild('div', 'media-messages-message-container media-message-' + message.level);
    container.createTextChild(message.message);
  }
}
<commit_msg>Migrate media/PlayerMessagesView to TS<commit_after>// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../common/common.js';  // eslint-disable-line no-unused-vars
import * as UI from '../ui/ui.js';

/**
 * @enum {number}
 */
const MessageLevelBitfield = {
  Error: 0b0001,
  Warning: 0b0010,
  Info: 0b0100,
  Debug: 0b1000,

  Default: 0b0111,  // Error, Warning, Info
  All: 0b1111,      // Error, Warning, Info, Debug
  Custom: 0
};

/**
 * @typedef {{
 * title: string,
 * value: MessageLevelBitfield,
 * stringValue: string,
 * selectable: (boolean|undefined),
 * overwrite: (boolean|undefined)
 * }}
 */
let SelectableLevel;  // eslint-disable-line no-unused-vars

/**
 * @implements {UI.SoftDropDown.Delegate<!SelectableLevel>}
 */
class MessageLevelSelector extends Common.ObjectWrapper.ObjectWrapper {
  /**
  * @param {!UI.ListModel.ListModel<!SelectableLevel>} items
  * @param {!PlayerMessagesView} view
  */
  constructor(items, view) {
    super();
    this._items = items;
    this._view = view;
    /** @type {!Map<number, !SelectableLevel>} */
    this._itemMap = new Map();

    /** @type {!Array<string>} */
    this._hiddenLevels = [];

    this._bitFieldValue = MessageLevelBitfield.Default;
    this._savedBitFieldValue = MessageLevelBitfield.Default;

    this._defaultTitle = ls`Default`;
    this._customTitle = ls`Custom`;
    this._allTitle = ls`All`;

    /**
     * @type {!WeakMap<!SelectableLevel, !HTMLElement>}
     */
    this.elementsForItems = new WeakMap();
  }

  defaultTitle() {
    return this._defaultTitle;
  }

  /**
   * @param {!UI.SoftDropDown.SoftDropDown<!SelectableLevel>} dropdown
   */
  setDefault(dropdown) {
    dropdown.selectItem(this._items.at(0));
  }

  populate() {
    this._items.insert(this._items.length, {
      title: this._defaultTitle,
      overwrite: true,
      stringValue: '',
      value: MessageLevelBitfield.Default,
      selectable: undefined
    });

    this._items.insert(this._items.length, {
      title: this._allTitle,
      overwrite: true,
      stringValue: '',
      value: MessageLevelBitfield.All,
      selectable: undefined
    });

    this._items.insert(this._items.length, {
      title: ls`Error`,
      overwrite: false,
      stringValue: 'error',
      value: MessageLevelBitfield.Error,
      selectable: undefined
    });

    this._items.insert(this._items.length, {
      title: ls`Warning`,
      overwrite: false,
      stringValue: 'warning',
      value: MessageLevelBitfield.Warning,
      selectable: undefined
    });

    this._items.insert(this._items.length, {
      title: ls`Info`,
      overwrite: false,
      stringValue: 'info',
      value: MessageLevelBitfield.Info,
      selectable: undefined
    });

    this._items.insert(this._items.length, {
      title: ls`Debug`,
      overwrite: false,
      stringValue: 'debug',
      value: MessageLevelBitfield.Debug,
      selectable: undefined
    });
  }

  _updateCheckMarks() {
    this._hiddenLevels = [];
    for (const [key, item] of this._itemMap) {
      if (!item.overwrite) {
        const elementForItem = this.elementsForItems.get(/** @type {!SelectableLevel} */ (item));
        if (elementForItem && elementForItem.firstChild) {
          elementForItem.firstChild.remove();
        }
        if (elementForItem && key & this._bitFieldValue) {
          elementForItem.createChild('div').createTextChild('✓');
        } else {
          this._hiddenLevels.push(item.stringValue);
        }
      }
    }
  }

  /**
   * @override
   * @param {!SelectableLevel} item
   * @return {string}
   */
  titleFor(item) {
    // This would make a lot more sense to have in |itemSelected|, but this
    // method gets called first.
    if (item.overwrite) {
      this._bitFieldValue = item.value;
    } else {
      this._bitFieldValue ^= item.value;
    }

    if (this._bitFieldValue === MessageLevelBitfield.Default) {
      return this._defaultTitle;
    }

    if (this._bitFieldValue === MessageLevelBitfield.All) {
      return this._allTitle;
    }

    const potentialMatch = this._itemMap.get(this._bitFieldValue);
    if (potentialMatch) {
      return potentialMatch.title;
    }

    return this._customTitle;
  }

  /**
   * @override
   * @param {!SelectableLevel} item
   * @return {!Element}
   */
  createElementForItem(item) {
    const element = document.createElement('div');
    const shadowRoot = UI.Utils.createShadowRootWithCoreStyles(element, 'media/playerMessagesView.css');
    const container = shadowRoot.createChild('div', 'media-messages-level-dropdown-element');
    const checkBox =
        /** @type {!HTMLElement} */ (container.createChild('div', 'media-messages-level-dropdown-checkbox'));
    const text = container.createChild('span', 'media-messages-level-dropdown-text');
    text.createTextChild(item.title);
    this.elementsForItems.set(item, checkBox);
    this._itemMap.set(item.value, item);
    this._updateCheckMarks();
    this._view.regenerateMessageDisplayCss(this._hiddenLevels);
    return element;
  }

  /**
   * @override
   * @param {!SelectableLevel} item
   * @return {boolean}
   */
  isItemSelectable(item) {
    return true;
  }

  /**
   * @override
   * @param {?SelectableLevel} item
   */
  itemSelected(item) {
    this._updateCheckMarks();
    this._view.regenerateMessageDisplayCss(this._hiddenLevels);
  }

  /**
   * @override
   * @param {?SelectableLevel} from
   * @param {?SelectableLevel} to
   * @param {?Element} fromElement
   * @param {?Element} toElement
   */
  highlightedItemChanged(from, to, fromElement, toElement) {
  }
}

export class PlayerMessagesView extends UI.Widget.VBox {
  constructor() {
    super();
    this.registerRequiredCSS('media/playerMessagesView.css');

    this._headerPanel = this.contentElement.createChild('div', 'media-messages-header');
    this._bodyPanel = this.contentElement.createChild('div', 'media-messages-body');

    this._buildToolbar();
  }

  _buildToolbar() {
    const toolbar = new UI.Toolbar.Toolbar('media-messages-toolbar', this._headerPanel);
    toolbar.appendText(ls`Log level:`);
    toolbar.appendToolbarItem(this._createDropdown());
    toolbar.appendSeparator();
    toolbar.appendToolbarItem(this._createFilterInput());
  }

  _createDropdown() {
    /** @type {!UI.ListModel.ListModel<!SelectableLevel>} */
    const items = new UI.ListModel.ListModel();
    /** @type {!MessageLevelSelector} **/
    this._messageLevelSelector = new MessageLevelSelector(items, this);
    /** @type {!UI.SoftDropDown.SoftDropDown<!SelectableLevel>} */
    const dropDown = new UI.SoftDropDown.SoftDropDown(items, this._messageLevelSelector);
    dropDown.setRowHeight(18);

    this._messageLevelSelector.populate();
    this._messageLevelSelector.setDefault(dropDown);

    const dropDownItem = new UI.Toolbar.ToolbarItem(dropDown.element);
    dropDownItem.element.classList.add('toolbar-has-dropdown');
    dropDownItem.setEnabled(true);
    dropDownItem.setTitle(this._messageLevelSelector.defaultTitle());
    return dropDownItem;
  }

  _createFilterInput() {
    const filterInput = new UI.Toolbar.ToolbarInput(ls`Filter log messages`);
    filterInput.addEventListener(
        UI.Toolbar.ToolbarInput.Event.TextChanged,
        /**
       * @param {!{data: *}} data
       */
        data => {
          this._filterByString(/** @type {!{data: string}} */ (data));
        },
        this);
    return filterInput;
  }

  /**
   *
   * @param {!Array<string>} hiddenLevels
   */
  regenerateMessageDisplayCss(hiddenLevels) {
    const messages = this._bodyPanel.getElementsByClassName('media-messages-message-container');
    for (const message of messages) {
      if (this._matchesHiddenLevels(message, hiddenLevels)) {
        message.classList.add('media-messages-message-unselected');
      } else {
        message.classList.remove('media-messages-message-unselected');
      }
    }
  }

  /**
   *
   * @param {!Element} element
   * @param {!Array<?>} hiddenLevels
   */
  _matchesHiddenLevels(element, hiddenLevels) {
    for (const level of hiddenLevels) {
      if (element.classList.contains('media-message-' + level)) {
        return true;
      }
    }
    return false;
  }

  /**
   * @param {!{data: string}} userStringData
   */
  _filterByString(userStringData) {
    const userString = userStringData.data;
    const messages = this._bodyPanel.getElementsByClassName('media-messages-message-container');

    for (const message of messages) {
      if (userString === '') {
        message.classList.remove('media-messages-message-filtered');
      } else if (message.textContent && message.textContent.includes(userString)) {
        message.classList.remove('media-messages-message-filtered');
      } else {
        message.classList.add('media-messages-message-filtered');
      }
    }
  }

  /**
   * @param {!Protocol.Media.PlayerMessage} message
   */
  addMessage(message) {
    const container =
        this._bodyPanel.createChild('div', 'media-messages-message-container media-message-' + message.level);
    container.createTextChild(message.message);
  }
}
<|endoftext|>


<commit_before>(function(window) {
	"use strict";

	var Fn     = window.Fn;
	var Sparky = window.Sparky;
	var DOM    = Sparky.dom;

	// We maintain a list of sparkies that are scheduled for destruction. This
	// time determines how long we wait during periods of inactivity before
	// destroying those sparkies.
	var destroyDelay = 8000;

	//function create(boss, node, scope, fn) {
	//	// Create a dependent sparky without delegating scope
	//	var sparky = Sparky(node, scope, fn, this);
	//
	//	function delegateDestroy() { sparky.destroy(); }
	//	function delegateRender(self) { sparky.render(); }
	//
	//	// Bind events
	//	boss
	//	.on('destroy', delegateDestroy)
	//	.on('render', delegateRender);
	//
	//	return sparky.on('destroy', function() {
	//		boss
	//		.off('destroy', delegateDestroy)
	//		.off('render', delegateRender);
	//	});
	//}

	function createPlaceholder(node) {
		if (!Sparky.debug) { return DOM.create('text', ''); }

		var attrScope = node.getAttribute('data-scope');
		var attrCtrl = node.getAttribute('data-fn');

		return DOM.create('comment',
			(attrScope ? ' data-scope="' + attrScope + '"' : '') +
			(attrCtrl ? ' data-fn="' + attrCtrl + '" ' : ''));
	}

	Sparky.fn.each = function setupCollection(node, scopes) {
		var sparky   = this;
		var data     = this.data;
		var sparkies = [];
		var cache    = [];

		// We cannot use a WeakMap here: WeakMaps do not accept primitives as
		// keys, and a Sparky scope may be a number or a string, although that
		// is unusual and perhaps we should ban it.
		var rejects  = new Map();
		var scheduled = [];
		var clone    = node.cloneNode(true);
		var fns      = this.interrupt();
		var placeholder = createPlaceholder(node);
		var collection;

		fns.unshift(function() {
			this.data = Object.create(data);
		});

		var throttle = Fn.Throttle(function update() {
			var n = -1;
			var l = cache.length;
			var map = {};
			var i, object, t;

			if (Sparky.debug) { t = window.performance.now(); }

			// Compare the cached version of the collection against the
			// collection and construct a map of found object positions.
			while (l--) {
				object = cache[l];
				i = collection.indexOf(object);

				if (i === -1) {
					DOM.remove(sparkies[l][0]);
					rejects.set(object, sparkies[l]);
					scheduled.push(object);
				}
				else {
					map[i] = sparkies[l];
				}
			}

			l = sparkies.length = cache.length = collection.length;

			// Ignore any objects at the start of the collection that have
			// not changed position. Optimises for case where we're pushing
			// things on the end.
			while(cache[++n] && cache[n] === collection[n]);
			--n;

			// Loop through the collection, recaching objects and creating
			// sparkies where needed.
			while(++n < l) {
				object = cache[n] = collection[n];
				removeScheduled(object);

				// KEEP AN EYE ON THIS!!!
				// It used to be that we created a standalone sparky, not a child
				// sparky. As in:
				//
				// create(sparky, clone.cloneNode(true), object, fns);
				//
				// This seems to have changed when we converted to streams.
				// I'm no longer clear why...

				sparkies[n] = map[n] || rejects.get(object) || sparky.create(clone.cloneNode(true), object, fns);

				// We are in an animation frame. Go ahead and manipulate the DOM.
				DOM.before(placeholder, sparkies[n][0]);
			}

			Sparky.log(
				'collection rendered (length: ' + collection.length +
				', time: ' + (window.performance.now() - t) + 'ms)'
			);

			reschedule();
		});

		var timer;

		function reschedule() {
			clearTimeout(timer);
			timer = setTimeout(function() {
				scheduled.forEach(function(object) {
					rejects.get(object).destroy();
					rejects.delete(object);
				});
				scheduled.length = 0;
			}, destroyDelay);
		}

		function removeScheduled(object) {
			var i = scheduled.indexOf(object);
			if (i === -1) { return; }
			scheduled.splice(i, 1);
		}

		function observeCollection() {
			if (collection.on) {
				collection.on('add remove sort', throttle);
				throttle();
			}
			else {
				Sparky.observe(collection, 'length', throttle);
			}
		}

		function unobserveCollection() {
			if (collection.on) {
				collection.off('add remove sort', throttle);
			}
			else {
				Sparky.unobserve(collection, 'length', throttle);
			}
		}

		// Stop Sparky trying to bind the same scope and ctrls again.
		clone.removeAttribute('data-scope');
		clone.removeAttribute('data-fn');

		// Put the placeholder in place and remove the node
		DOM.before(node, placeholder);
		DOM.remove(node);

		scopes
		.dedup()
		.each(function(scope) {
			if (collection) { unobserveCollection(); }
			collection = scope;
			if (collection) { observeCollection(); }
		});

		this
		.on('destroy', function destroy() {
			throttle.cancel();
			unobserveCollection();
		});
	};
})(this);
<commit_msg>No no no no no<commit_after>(function(window) {
	"use strict";

	var Fn     = window.Fn;
	var Sparky = window.Sparky;
	var DOM    = Sparky.dom;

	// We maintain a list of sparkies that are scheduled for destruction. This
	// time determines how long we wait during periods of inactivity before
	// destroying those sparkies.
	var destroyDelay = 8000;

	function createPlaceholder(node) {
		if (!Sparky.debug) { return DOM.create('text', ''); }

		var attrScope = node.getAttribute('data-scope');
		var attrCtrl = node.getAttribute('data-fn');

		return DOM.create('comment',
			(attrScope ? ' data-scope="' + attrScope + '"' : '') +
			(attrCtrl ? ' data-fn="' + attrCtrl + '" ' : ''));
	}

	Sparky.fn.each = function setupCollection(node, scopes) {
		var sparky   = this;
		var data     = this.data;
		var sparkies = [];
		var cache    = [];

		// We cannot use a WeakMap here: WeakMaps do not accept primitives as
		// keys, and a Sparky scope may be a number or a string - although that
		// is unusual and perhaps we should ban it.
		var rejects  = new Map();
		var scheduled = [];

		var clone    = node.cloneNode(true);
		var fns      = this.interrupt();
		var placeholder = createPlaceholder(node);
		var collection;

		fns.unshift(function() {
			this.data = Object.create(data);
		});

		var throttle = Fn.Throttle(function update() {
			var n = -1;
			var l = cache.length;
			var map = {};
			var i, object, t;

			if (Sparky.debug) { t = window.performance.now(); }

			// Compare the cached version of the collection against the
			// collection and construct a map of found object positions.
			while (l--) {
				object = cache[l];
				i = collection.indexOf(object);

				if (i === -1) {
					rejects.set(object, sparkies[l]);
					DOM.remove(sparkies[l][0]);
					scheduled.push(object);
				}
				else {
					map[i] = sparkies[l];
				}
			}

			l = sparkies.length = cache.length = collection.length;

			// Ignore any objects at the start of the collection that have
			// not changed position. Optimises for the common case where we're
			// pushing things on the end.
			while(cache[++n] && cache[n] === collection[n]);
			--n;

			var changed = false;

			// Loop through the collection, recaching objects and creating
			// sparkies where needed.
			while(++n < l) {
				// While nothing has changed, do nothing
				if (!changed && cache[n] === collection[n]) {
					continue;
				}
				else {
					changed = true;
				}

				object = cache[n] = collection[n];
				removeScheduled(object);

				sparkies[n] = rejects.get(object);

				Sparky.log('sparky for object');
				if (sparkies[n]) {
					Sparky.log('    ...found in rejects')
					rejects.delete(object);
				}
				else {
					sparkies[n] = map[n] || sparky.create(clone.cloneNode(true), object, fns);
				}

				// If node before placeholder is a leftover reject
				if (placeholder.previousSibling === sparkies[n][0]) {
					Sparky.log('    ...already in DOM position', sparkies[n][0]);
					continue;
				}

				// We are in an animation frame. Go ahead and manipulate the DOM.
				DOM.before(placeholder, sparkies[n][0]);
			}

			Sparky.log(
				'collection rendered (length: ' + collection.length +
				', time: ' + (window.performance.now() - t) + 'ms)'
			);

			reschedule();
		});

		var timer;

		function reschedule() {
			clearTimeout(timer);
			timer = setTimeout(function() {
				scheduled.forEach(function(object) {
					var sparky = rejects.get(object);
					// Todo: This should not occur. Object must be in rejects
					// at this point. but it is occurring. Find out what is
					// wrong.
					if (!sparky) { return; }
					sparky.destroy();
					rejects.delete(object);
				});
				scheduled.length = 0;
			}, destroyDelay);
		}

		function removeScheduled(object) {
			var i = scheduled.indexOf(object);
			if (i === -1) { return; }
			scheduled.splice(i, 1);
		}

		function observeCollection() {
			if (collection.on) {
				collection.on('add remove sort', throttle);
				throttle();
			}
			else {
				Sparky.observe(collection, 'length', throttle);
			}
		}

		function unobserveCollection() {
			if (collection.on) {
				collection.off('add remove sort', throttle);
			}
			else {
				Sparky.unobserve(collection, 'length', throttle);
			}
		}

		// Stop Sparky trying to bind the same scope and ctrls again.
		clone.removeAttribute('data-scope');
		clone.removeAttribute('data-fn');

		// Put the placeholder in place and remove the node
		DOM.before(node, placeholder);
		DOM.remove(node);

		scopes
		.dedup()
		.each(function(scope) {
			if (collection) { unobserveCollection(); }
			collection = scope;
			if (collection) { observeCollection(); }
		});

		this
		.on('destroy', function destroy() {
			throttle.cancel();
			unobserveCollection();
		});
	};
})(this);
<|endoftext|>


<commit_before>/* global $, Gallery */
/**
 * A thumbnail is the actual image attached to the GalleryImage object
 *
 * @param {number} fileId
 * @param {bool} square
 * @constructor
 */
function Thumbnail (fileId, square) {
	this.square = square;
	this.fileId = fileId;
	this.image = null;
	this.loadingDeferred = new $.Deferred();
	this.height = 200;
	this.width = 400;
	this.ratio = null;
	this.valid = true;
	this.status = 200;
}

(function ($, OC, Gallery) {
	"use strict";
	var Thumbnails = {
		map: {},
		squareMap: {},

		/**
		 * Retrieves the thumbnail linked to the given fileID
		 *
		 * @param {number} fileId
		 * @param {bool} square
		 *
		 * @returns {Thumbnail}
		 */
		get: function (fileId, square) {
			var map = {};
			if (square === true) {
				map = Thumbnails.squareMap;
				square = true;
			} else {
				map = Thumbnails.map;
				square = false;
			}
			if (!map[fileId]) {
				map[fileId] = new Thumbnail(fileId, square);
			}

			return map[fileId];
		},

		/**
		 * Returns an icon of a specific type
		 *
		 * -1 is for a folder
		 * -404 is for a broken file icon
		 * -500 is for a media type icon
		 *
		 * @param {number} type
		 *
		 * @returns {Thumbnail}
		 */
		getStandardIcon: function (type) {
			if (!Thumbnails.squareMap[type]) {
				var icon = '';
				// true means square
				var thumb = new Thumbnail(type, true);
				thumb.image = new Image();
				thumb.image.onload = function () {
					thumb.loadingDeferred.resolve(thumb.image);
				};

				if (type === -1) {
					icon = 'folder.svg';
				}
				thumb.image.src = OC.imagePath(Gallery.appName, icon);

				Thumbnails.squareMap[type] = thumb;
			}

			return Thumbnails.squareMap[type];
		},

		/**
		 * Loads thumbnails in batch, using EventSource
		 *
		 * @param {Array} ids
		 * @param {bool} square
		 *
		 * @returns {{}}
		 */
		loadBatch: function (ids, square) {
			var map = (square) ? Thumbnails.squareMap : Thumbnails.map;
			// Purely here as a precaution
			ids = ids.filter(function (id) {
				return !map[id];
			});
			var batch = {};
			var i, idsLength = ids.length;
			if (idsLength) {
				for (i = 0; i < idsLength; i++) {
					var thumb = new Thumbnail(ids[i], square);
					thumb.image = new Image();
					map[ids[i]] = batch[ids[i]] = thumb;

				}
				var params = {
					ids: ids.join(';'),
					scale: window.devicePixelRatio,
					square: (square) ? 1 : 0
				};
				var url = Gallery.utility.buildGalleryUrl('thumbnails', '', params);

				var eventSource = new Gallery.EventSource(url);
				eventSource.listen('preview',
					function (/**{path, status, mimetype, preview}*/ preview) {
						var id = preview.fileid;
						var thumb = batch[id];
						thumb.status = preview.status;
						if (thumb.status === 404) {
							thumb.valid = false;
							thumb.loadingDeferred.resolve(null);
						} else {
							thumb.image.onload = function () {
								// Fix for SVG files which can come in all sizes
								if (square) {
									thumb.image.width = 200;
									thumb.image.height = 200;
								}
								thumb.ratio = thumb.image.width / thumb.image.height;
								thumb.image.originalWidth = 200 * thumb.ratio;
								thumb.loadingDeferred.resolve(thumb.image);
							};
							thumb.image.onerror = function () {
								thumb.valid = false;
								thumb.loadingDeferred.resolve(null);
							};

							if (thumb.status === 200) {
								thumb.image.src =
									'data:' + preview.mimetype + ';base64,' + preview.preview;
							} else {
								thumb.valid = false;
								thumb.image.src = OC.MimeType.getIconUrl(preview.mimetype);
							}
						}
					});
			}

			return batch;
		}
	};

	window.Thumbnails = Thumbnails;
})(jQuery, OC, Gallery);
<commit_msg>IE family gets the ugly blown up PNG icons Fixes #334<commit_after>/* global $, Gallery */
/**
 * A thumbnail is the actual image attached to the GalleryImage object
 *
 * @param {number} fileId
 * @param {bool} square
 * @constructor
 */
function Thumbnail (fileId, square) {
	this.square = square;
	this.fileId = fileId;
	this.image = null;
	this.loadingDeferred = new $.Deferred();
	this.height = 200;
	this.width = 400;
	this.ratio = null;
	this.valid = true;
	this.status = 200;
}

(function ($, OC, Gallery) {
	"use strict";
	var Thumbnails = {
		map: {},
		squareMap: {},

		/**
		 * Retrieves the thumbnail linked to the given fileID
		 *
		 * @param {number} fileId
		 * @param {bool} square
		 *
		 * @returns {Thumbnail}
		 */
		get: function (fileId, square) {
			var map = {};
			if (square === true) {
				map = Thumbnails.squareMap;
				square = true;
			} else {
				map = Thumbnails.map;
				square = false;
			}
			if (!map[fileId]) {
				map[fileId] = new Thumbnail(fileId, square);
			}

			return map[fileId];
		},

		/**
		 * Returns an icon of a specific type
		 *
		 * -1 is for a folder
		 * -404 is for a broken file icon
		 * -500 is for a media type icon
		 *
		 * @param {number} type
		 *
		 * @returns {Thumbnail}
		 */
		getStandardIcon: function (type) {
			if (!Thumbnails.squareMap[type]) {
				var icon = '';
				// true means square
				var thumb = new Thumbnail(type, true);
				thumb.image = new Image();
				thumb.image.onload = function () {
					thumb.loadingDeferred.resolve(thumb.image);
				};

				if (type === -1) {
					icon = 'folder.svg';
				}
				thumb.image.src = OC.imagePath(Gallery.appName, icon);

				Thumbnails.squareMap[type] = thumb;
			}

			return Thumbnails.squareMap[type];
		},

		/**
		 * Loads thumbnails in batch, using EventSource
		 *
		 * @param {Array} ids
		 * @param {bool} square
		 *
		 * @returns {{}}
		 */
		loadBatch: function (ids, square) {
			var map = (square) ? Thumbnails.squareMap : Thumbnails.map;
			// Purely here as a precaution
			ids = ids.filter(function (id) {
				return !map[id];
			});
			var batch = {};
			var i, idsLength = ids.length;
			if (idsLength) {
				for (i = 0; i < idsLength; i++) {
					var thumb = new Thumbnail(ids[i], square);
					thumb.image = new Image();
					map[ids[i]] = batch[ids[i]] = thumb;

				}
				var params = {
					ids: ids.join(';'),
					scale: window.devicePixelRatio,
					square: (square) ? 1 : 0
				};
				var url = Gallery.utility.buildGalleryUrl('thumbnails', '', params);

				var eventSource = new Gallery.EventSource(url);
				eventSource.listen('preview',
					function (/**{path, status, mimetype, preview}*/ preview) {
						var id = preview.fileid;
						var thumb = batch[id];
						thumb.status = preview.status;
						if (thumb.status === 404) {
							thumb.valid = false;
							thumb.loadingDeferred.resolve(null);
						} else {
							thumb.image.onload = function () {
								// Fix for SVG files which can come in all sizes
								if (square) {
									thumb.image.width = 200;
									thumb.image.height = 200;
								}
								thumb.ratio = thumb.image.width / thumb.image.height;
								thumb.image.originalWidth = 200 * thumb.ratio;
								thumb.loadingDeferred.resolve(thumb.image);
							};
							thumb.image.onerror = function () {
								thumb.valid = false;
								thumb.loadingDeferred.resolve(null);
							};

							if (thumb.status === 200) {
								thumb.image.src =
									'data:' + preview.mimetype + ';base64,' + preview.preview;
							} else {
								thumb.valid = false;
								var icon = OC.MimeType.getIconUrl(preview.mimetype);
								if (Gallery.ieVersion !== false) {
									icon = icon.substr(0, icon.lastIndexOf(".")) + ".png";
								}
								thumb.image.src = icon;
							}
						}
					});
			}

			return batch;
		}
	};

	window.Thumbnails = Thumbnails;
})(jQuery, OC, Gallery);
<|endoftext|>


<commit_before>/*
 * Copyright 2013 pingworks - Alexander Birk und Christoph Lukas
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Ext.define('Dash.controller.Deployment', {
    extend: 'Dash.controller.Base',
    requires: ['Ext.form.field.ComboBox', 'Ext.form.field.Hidden'],
    stores: ['Environments', 'Contents'],
    refs: [
        {
            selector: 'bundlegrid',
            ref: 'bundleGrid'
        },
        {
            selector: 'deploymentwindow',
            ref: 'deploymentWindow'
        }
    ],
    init: function() {
        this.control({
            'bundlegrid': {
                showDeployWindow: this.onShowDeployWindow
            }
        });
        this.control({
            'toptoolbar': {
                hideDeployWindow: this.onHideDeployWindow
            }
        });
        this.control({
            'deploymentwindow': {
                deployment: this.onDeployment
            }
        });
        this.callParent(arguments);
    },
    deploymentAllowed: function(bundle) {
        if (bundle) {
          if (Dash.config.bundlegrid.triggerJenkinsJob.required) {
              var requiredFieldValue = bundle.get(Dash.config.bundlegrid.deployment.required.field);
              return ( Dash.config.bundlegrid.deployment.enabled
                  && Dash.config.bundlegrid.deployment.required.value == requiredFieldValue);
          }
          if (Dash.config.bundlegrid.deployment.conditions) {
              var conditionTrue = true;
              Ext.each(Dash.config.bundlegrid.deployment.conditions, function(condition) {
                  var field = condition.field;
                  var regex = condition.regex;
                  var fieldValue = '' + bundle.get(field);
                  conditionTrue &= ( Dash.config.bundlegrid.deployment.enabled
                      && fieldValue.match(regex) != null)
              });
              return conditionTrue;
          }
        }
        return false;
    },
    onShowDeployWindow: function(bundle) {
        if (bundle && this.deploymentAllowed(bundle)) {
            this.getEnvironmentsStore().reload();
            this.getEnvironmentsStore().clearFilter(true);
            this.getEnvironmentsStore().filter('deployable', true);
            if (Dash.config.deployment.features.content && Dash.config.deployment.features.content.enabled)
                this.getContentsStore().reload();
            var window = Ext.create('Dash.view.DeploymentWindow', {
                bundle: bundle
            }).show();
        }
    },
    onHideDeployWindow: function() {
        var win = this.getDeploymentWindow()
        win && win.destroy();
    },
    onDeployment: function(bundle, values) {
        if (!bundle || !values || !values.environment) {
            return false;
        }
        var environment = this.getEnvironmentsStore().findRecord('id', values.environment);
        environment.set('locked', true);
        var now = new Date();
        var lockUntil = new Date(now.getTime() + (values.lock * 3600 * 1000));
        var dateFormat = Dash.config.environment.dateformat;
        environment.set('until', Ext.util.Format.date(lockUntil, dateFormat));
        environment.set('by', values.name);
        environment.set('bundle', bundle.get('id'));
        environment.set('dbreset', values.dbreset);
        environment.set('content', values.content);
        environment.save({
            success: this.onLockSaved,
            failure: this.onError,
            scope: this
        });
    },
    onLockSaved: function(environment, operation, success) {
        Ext.Ajax.request({
            url: Dash.config.deployment.triggerUrl,
            params: {
                environment: environment.get('id'),
                content: environment.get('content'),
                dbreset: environment.get('dbreset'),
                bundle: environment.get('bundle'),
                user: environment.get('by')
            },
            success: this.onDeploymentTriggered,
            failure: this.onDeploymentError,
            scope: this
        });
    },
    onDeploymentTriggered: function(response, options) {
        this.getDeploymentWindow().destroy();
        var window = Ext.create('Ext.window.Window', {
            id: 'DeploymentResultWindow',
            html: '<iframe src="' + Dash.config.deployment.showUrl + '" width="800px", height="600px"/>'
        }).show();
    },
    onDeploymentError: function(response, options) {
        if (response.status == 302) {
            return this.onDeploymentTriggered(response, options);
        }
        if (response.status == 0) {
            return this.onDeploymentTriggered(response, options);
        }
        return this.onError(response, options);
    },
    onError: function(response, options) {
        this.onHideDeployWindow();
        this.callParent(arguments);
    }
});
<commit_msg>fixed c&p error<commit_after>/*
 * Copyright 2013 pingworks - Alexander Birk und Christoph Lukas
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Ext.define('Dash.controller.Deployment', {
    extend: 'Dash.controller.Base',
    requires: ['Ext.form.field.ComboBox', 'Ext.form.field.Hidden'],
    stores: ['Environments', 'Contents'],
    refs: [
        {
            selector: 'bundlegrid',
            ref: 'bundleGrid'
        },
        {
            selector: 'deploymentwindow',
            ref: 'deploymentWindow'
        }
    ],
    init: function() {
        this.control({
            'bundlegrid': {
                showDeployWindow: this.onShowDeployWindow
            }
        });
        this.control({
            'toptoolbar': {
                hideDeployWindow: this.onHideDeployWindow
            }
        });
        this.control({
            'deploymentwindow': {
                deployment: this.onDeployment
            }
        });
        this.callParent(arguments);
    },
    deploymentAllowed: function(bundle) {
        if (bundle) {
          if (Dash.config.bundlegrid.deployment.required) {
              var requiredFieldValue = bundle.get(Dash.config.bundlegrid.deployment.required.field);
              return ( Dash.config.bundlegrid.deployment.enabled
                  && Dash.config.bundlegrid.deployment.required.value == requiredFieldValue);
          }
          if (Dash.config.bundlegrid.deployment.conditions) {
              var conditionTrue = true;
              Ext.each(Dash.config.bundlegrid.deployment.conditions, function(condition) {
                  var field = condition.field;
                  var regex = condition.regex;
                  var fieldValue = '' + bundle.get(field);
                  conditionTrue &= ( Dash.config.bundlegrid.deployment.enabled
                      && fieldValue.match(regex) != null)
              });
              return conditionTrue;
          }
        }
        return false;
    },
    onShowDeployWindow: function(bundle) {
        if (bundle && this.deploymentAllowed(bundle)) {
            this.getEnvironmentsStore().reload();
            this.getEnvironmentsStore().clearFilter(true);
            this.getEnvironmentsStore().filter('deployable', true);
            if (Dash.config.deployment.features.content && Dash.config.deployment.features.content.enabled)
                this.getContentsStore().reload();
            var window = Ext.create('Dash.view.DeploymentWindow', {
                bundle: bundle
            }).show();
        }
    },
    onHideDeployWindow: function() {
        var win = this.getDeploymentWindow()
        win && win.destroy();
    },
    onDeployment: function(bundle, values) {
        if (!bundle || !values || !values.environment) {
            return false;
        }
        var environment = this.getEnvironmentsStore().findRecord('id', values.environment);
        environment.set('locked', true);
        var now = new Date();
        var lockUntil = new Date(now.getTime() + (values.lock * 3600 * 1000));
        var dateFormat = Dash.config.environment.dateformat;
        environment.set('until', Ext.util.Format.date(lockUntil, dateFormat));
        environment.set('by', values.name);
        environment.set('bundle', bundle.get('id'));
        environment.set('dbreset', values.dbreset);
        environment.set('content', values.content);
        environment.save({
            success: this.onLockSaved,
            failure: this.onError,
            scope: this
        });
    },
    onLockSaved: function(environment, operation, success) {
        Ext.Ajax.request({
            url: Dash.config.deployment.triggerUrl,
            params: {
                environment: environment.get('id'),
                content: environment.get('content'),
                dbreset: environment.get('dbreset'),
                bundle: environment.get('bundle'),
                user: environment.get('by')
            },
            success: this.onDeploymentTriggered,
            failure: this.onDeploymentError,
            scope: this
        });
    },
    onDeploymentTriggered: function(response, options) {
        this.getDeploymentWindow().destroy();
        var window = Ext.create('Ext.window.Window', {
            id: 'DeploymentResultWindow',
            html: '<iframe src="' + Dash.config.deployment.showUrl + '" width="800px", height="600px"/>'
        }).show();
    },
    onDeploymentError: function(response, options) {
        if (response.status == 302) {
            return this.onDeploymentTriggered(response, options);
        }
        if (response.status == 0) {
            return this.onDeploymentTriggered(response, options);
        }
        return this.onError(response, options);
    },
    onError: function(response, options) {
        this.onHideDeployWindow();
        this.callParent(arguments);
    }
});
<|endoftext|>


<commit_before>(function($) {
	$.UltC || ($.UltC = {});

	var helperDiv = document.createElement('div');
	$.UltC.unselectableSupport = helperDiv.hasOwnProperty && helperDiv.hasOwnProperty('unselectable');

	$.fn.disableSelection = function() {
		if ($.UltC.unselectableSupport) this.contents().andSelf().prop('unselectable', 'on'); //Opera
		return this
			.css('user-select', 'none') //FF, Chrome
			.on('selectstart', false); //IE
	};

	$.fn.ultButtonset = function() {
		this.buttonset.apply(this, arguments);
		this.find('label').disableSelection();
		return this;
	}
	$.fn.ultButton = function() {
		this.button.apply(this, arguments);
		return this.each(function() {
			$('label[for="' + this.id + '"]').disableSelection();
		});
	}

	$(document).mousedown(function(e) {
		if (e.which !== 1) return;
		$.UltC.mdtarg = e.target;
	}).on('mousedown', 'label.ui-button', function(e) {
		if (e.which !== 1) return;
		var $this = $(this);
		//using this selector to support eccentric ids, e.g. input[id="foo.bar"]
		//stores the checked state of the input during the mousedown event to check agaisnt on mouseup
		$this.data('checked', $('input[id="'+ $this.attr('for') + '"]').prop('checked'));
	}).on('mouseup', 'label.ui-button', function(e) {
		if (e.which !== 1) return;
		var $this = $(this),
			$ch = $('input[id="'+ $this.attr('for') + '"]'),
			ch = $ch[0];
		setTimeout(function() {
			if (ch.disabled) return;
			var targ = $.UltC.mdtarg;
			//usually, the click target is the span inside the label.ui-button hence the `$this.has(targ).length`. It also takes care of user-created elements inside the label e.g. images
			//but if the user manages to click in the default 1px border of the label, the target will be the label element itself: targ === $this[0]
			//if the ui button firing the mouseup handler is the same that triggered the last mousedown handler and the checked state didn't change after
			//the jQuery UI handled the events (hence the setTimeout), we do the magic
			if ($this.data('checked') === ch.checked && ($this.has(targ).length || targ === $this[0])) {
				if (ch.type === 'radio') {
					if (!ch.checked) {
						ch.checked = true;
						$('input[type="radio"][name="' + ch.name + '"]').not(ch).each(function() {
							$('label[for="' + this.id + '"]').removeClass('ui-state-active').attr('aria-pressed', false);
						});
						$this.addClass('ui-state-active').attr('aria-pressed', true);
						$ch.trigger('change');
					}
				} else {
					var inversechecked = !ch.checked;
					ch.checked = inversechecked;
					if (inversechecked) $this.addClass('ui-state-active');
					else $this.removeClass('ui-state-active');
					$this.attr('aria-pressed', inversechecked);
					$ch.trigger('change');
				}
			}
		}, 0);
	});
})(jQuery);
<commit_msg>setTimeout only when necessary<commit_after>(function($) {
	$.UltC || ($.UltC = {});

	var helperDiv = document.createElement('div');
	$.UltC.unselectableSupport = helperDiv.hasOwnProperty && helperDiv.hasOwnProperty('unselectable');

	$.fn.disableSelection = function() {
		if ($.UltC.unselectableSupport) this.contents().andSelf().prop('unselectable', 'on'); //Opera
		return this
			.css('user-select', 'none') //FF, Chrome
			.on('selectstart', false); //IE
	};

	$.fn.ultButtonset = function() {
		this.buttonset.apply(this, arguments);
		this.find('label').disableSelection();
		return this;
	}
	$.fn.ultButton = function() {
		this.button.apply(this, arguments);
		return this.each(function() {
			$('label[for="' + this.id + '"]').disableSelection();
		});
	}

	$(document).mousedown(function(e) {
		if (e.which !== 1) return;
		$.UltC.mdtarg = e.target;
	}).on('mousedown', 'label.ui-button', function(e) {
		if (e.which !== 1) return;
		var $this = $(this);
		//using this selector to support eccentric ids, e.g. input[id="foo.bar"]
		//stores the checked state of the input during the mousedown event to check agaisnt on mouseup
		$this.data('checked', $('input[id="'+ $this.attr('for') + '"]').prop('checked'));
	}).on('mouseup', 'label.ui-button', function(e) {
		if (e.which !== 1) return;
		var $this = $(this),
			$ch = $('input[id="'+ $this.attr('for') + '"]'),
			ch = $ch[0],
			targ = $.UltC.mdtarg;

		if (ch.disabled) return;

		//usually, the click target is the span inside the label.ui-button: `$this.has(targ).length`. It also takes care of user-created elements inside the label e.g. images
		//but if the user manages to click in the default 1px border of the label, the target will be the label element itself: `targ === $this[0]`
		if ($this.has(targ).length || targ === $this[0]) {
			setTimeout(function() {
				//if the ui button firing the mouseup handler is the same that triggered the last mousedown handler and the checked state didn't change after
				//the jQuery UI handled the events (hence the setTimeout), we do the magic
				if ($this.data('checked') === ch.checked) {
					if (ch.type === 'radio') {
						if (!ch.checked) {
							ch.checked = true;
							$('input[type="radio"][name="' + ch.name + '"]').not(ch).each(function() {
								$('label[for="' + this.id + '"]').removeClass('ui-state-active').attr('aria-pressed', false);
							});
							$this.addClass('ui-state-active').attr('aria-pressed', true);
							$ch.trigger('change');
						}
					} else {
						var inversechecked = !ch.checked;
						ch.checked = inversechecked;
						if (inversechecked) $this.addClass('ui-state-active');
						else $this.removeClass('ui-state-active');
						$this.attr('aria-pressed', inversechecked);
						$ch.trigger('change');
					}
				}
			}, 0);
		}
	});
})(jQuery);
<|endoftext|>


<commit_before>function random_range(lower, upper) {
	return lower + Math.floor((upper - lower) * Math.random());
}

function extract_random_element(array_) {
	index = random_range(0, array_.length);
	return array_.splice(index, 1)[0];
}

var VERSION = "v2";

onLoad = function() {
	cells = document.querySelectorAll("td");

	// Load and store state in local storage
	state = localStorage.getItem(VERSION);
	if (!state) {
		tropes = [];
		trope_indexes = [];
		all_tropes.forEach(function (_, i) {
			trope_indexes.push(i);
		});
		for (var i = 0; i < cells.length; i++) {
			// Randomize content
			tropes.push(extract_random_element(trope_indexes));
		}
		state = {
			"tropes": tropes,
			"checked": []
		}
		localStorage.setItem(VERSION, JSON.stringify(state));
	} else {
		state = JSON.parse(state);
		for (var i = 0; i < cells.length; i++) {
			if (state.checked[i]) {
				cells[i].classList.add("checked");
			}
		}
	}

	state.tropes.forEach(function(_, i) {
		cells[i].textContent = all_tropes[state.tropes[i]];
		// Set up click listener to toggle "checked" class on target element
		cells[i].addEventListener("click", function (event) {
			event.currentTarget.classList.toggle("checked");
			state.checked[i] = event.currentTarget.classList.contains("checked");
			localStorage.setItem(VERSION, JSON.stringify(state));
		});
	});

	document.querySelector("#reset").addEventListener("click", function(event) {
		localStorage.clear();
		location.reload();
	});
};

document.addEventListener('DOMContentLoaded', onLoad, false);

all_tropes = [
	"On-stage change of clothes",
	"Gimmicky instrument",
	"Key change, truck driver's or otherwise",
	"Rap",
	"Notably bad accent",
	"Wind machine",
	"Platforms on stage",
	"Trying for audience participation",
	"Pyrotechnics and/or confetti",
	"Ethnic influences",
	"References to European community",
	"Implied homosexuality",
	"Band name used in decoration",
	"Odd singing registers (falsetto, tuvan throat singing, yodeling, etc)",
	"Retro-famous dance move",
	"\"Hello Kiev!\"", // TODO: update next year
	"\"I love you Kiev!\"", // TODO: update next year
"Side step-dance",
	"GLITTER",
	"Tight overall (clothing)",
	"Song is not serious song",
	"Preposterous shoes",
	"Band name with pun",
	"\"Love\" in song title",
	"Eastern-bloc votes for eastern-bloc",
	"Scandinavia votes for Scandinavia",
	"Country sent their best singer to competition",
	"An actual famous band",
	"Technical failure",
	"Technical delay",
	"Boob shock",
	"Vocal microphone effects",
	"Obvious wailing",
	"Balloons",
	"Greeting from artist that was unable to make it",
	"Shoutout/wave to family member in the audience",
	"Overwhelming cringe",
	"Dancers' uniforms do not match artist and/or are irrelevant to song",
	"Artist < 18 years of age",
	"Artist > 18 years of age, acts like < 18",
	"Duet performers with socially unacceptable age span",
	"Unexpected techno segue",
	"Sunglasses",
	"Lasershow",
	"Audience aware of being filmed, points/stares at video screen",
	"Two hands gripping the microphone",
	"Foul language",
	"Facial paint",
	"Parody of real band",
	"Music medley",
	"Host/hostess dancing",
	"Pointing into camera",
	"Microphone between legs",
	"Visible camera",
	"Obvious local audience-pleaser",
	"Performers leaning back-to-back",
	"Smoke machine",
	"Backstage footage",
	"Live outdoors footage",
	"Sepia-filter",
	"Accordion, violin, flute, harmonica or harp",
	"Hand movement 5+ sec",
	"Questionable props",
	"Heavy breathing in microphone",
	"Lyrics other than English or native language",
	"Shocking nudity",
	"Patriotism",
	"Belly button showing",
	"\"Didn't Enya do this first?\"",
	"\"Is the UK/France/Germany taking this seriously?\"",
	"Interim entertainment would have easily won",
	"Artist of color",
	"Clicking one's heels",
	"Screaming fans up close",
	"Pun in song title",
	"Reference to ABBA",
	"Sign with name",
	"Comical sign",
	"Peace theme from war nation",
	"Walking in circles around each other",
	"Kissing on stage",
	"Song inappropriate for senior citizens",
	"Siblings on stage",
	"Pornstache",
	"Song sharing a title with one previously performed", //As made famous 2015
	"Violent disposal of footwear",
	// "Breaking the fourth wall", //Was added in 2015, can't remember why? Might cause confusion to user/not obvious.
	"Preposterous dress",
	"Shocking shoes",
	"Flying",
	"(Dis)apparation",
	"Demonic ritual",
	"Cape",
	"On-stage selfie",
	"Tinfoil hat",
	"Destroying equipment",
	"Winking to camera",
	"Selfie stick used by artist",
	"Bald person banging on drums" // Thanks Kathi
]
<commit_msg>Added gimmicky 'taller than they really are' raising platform<commit_after>function random_range(lower, upper) {
	return lower + Math.floor((upper - lower) * Math.random());
}

function extract_random_element(array_) {
	index = random_range(0, array_.length);
	return array_.splice(index, 1)[0];
}

var VERSION = "v2";

onLoad = function() {
	cells = document.querySelectorAll("td");

	// Load and store state in local storage
	state = localStorage.getItem(VERSION);
	if (!state) {
		tropes = [];
		trope_indexes = [];
		all_tropes.forEach(function (_, i) {
			trope_indexes.push(i);
		});
		for (var i = 0; i < cells.length; i++) {
			// Randomize content
			tropes.push(extract_random_element(trope_indexes));
		}
		state = {
			"tropes": tropes,
			"checked": []
		}
		localStorage.setItem(VERSION, JSON.stringify(state));
	} else {
		state = JSON.parse(state);
		for (var i = 0; i < cells.length; i++) {
			if (state.checked[i]) {
				cells[i].classList.add("checked");
			}
		}
	}

	state.tropes.forEach(function(_, i) {
		cells[i].textContent = all_tropes[state.tropes[i]];
		// Set up click listener to toggle "checked" class on target element
		cells[i].addEventListener("click", function (event) {
			event.currentTarget.classList.toggle("checked");
			state.checked[i] = event.currentTarget.classList.contains("checked");
			localStorage.setItem(VERSION, JSON.stringify(state));
		});
	});

	document.querySelector("#reset").addEventListener("click", function(event) {
		localStorage.clear();
		location.reload();
	});
};

document.addEventListener('DOMContentLoaded', onLoad, false);

all_tropes = [
	"On-stage change of clothes",
	"Gimmicky instrument",
	"Key change, truck driver's or otherwise",
	"Rap",
	"Notably bad accent",
	"Wind machine",
	"Platforms on stage",
	"Trying for audience participation",
	"Pyrotechnics and/or confetti",
	"Ethnic influences",
	"References to European community",
	"Implied homosexuality",
	"Band name used in decoration",
	"Odd singing registers (falsetto, tuvan throat singing, yodeling, etc)",
	"Retro-famous dance move",
	"\"Hello Kiev!\"", // TODO: update next year
	"\"I love you Kiev!\"", // TODO: update next year
"Side step-dance",
	"GLITTER",
	"Tight overall (clothing)",
	"Song is not serious song",
	"Preposterous shoes",
	"Band name with pun",
	"\"Love\" in song title",
	"Eastern-bloc votes for eastern-bloc",
	"Scandinavia votes for Scandinavia",
	"Country sent their best singer to competition",
	"An actual famous band",
	"Technical failure",
	"Technical delay",
	"Boob shock",
	"Vocal microphone effects",
	"Obvious wailing",
	"Balloons",
	"Greeting from artist that was unable to make it",
	"Shoutout/wave to family member in the audience",
	"Overwhelming cringe",
	"Dancers' uniforms do not match artist and/or are irrelevant to song",
	"Artist < 18 years of age",
	"Artist > 18 years of age, acts like < 18",
	"Duet performers with socially unacceptable age span",
	"Unexpected techno segue",
	"Sunglasses",
	"Lasershow",
	"Audience aware of being filmed, points/stares at video screen",
	"Two hands gripping the microphone",
	"Foul language",
	"Facial paint",
	"Parody of real band",
	"Music medley",
	"Host/hostess dancing",
	"Pointing into camera",
	"Microphone between legs",
	"Visible camera",
	"Obvious local audience-pleaser",
	"Performers leaning back-to-back",
	"Smoke machine",
	"Backstage footage",
	"Live outdoors footage",
	"Sepia-filter",
	"Accordion, violin, flute, harmonica or harp",
	"Hand movement 5+ sec",
	"Questionable props",
	"Heavy breathing in microphone",
	"Lyrics other than English or native language",
	"Shocking nudity",
	"Patriotism",
	"Belly button showing",
	"\"Didn't Enya do this first?\"",
	"\"Is the UK/France/Germany taking this seriously?\"",
	"Interim entertainment would have easily won",
	"Artist of color",
	"Clicking one's heels",
	"Screaming fans up close",
	"Pun in song title",
	"Reference to ABBA",
	"Sign with name",
	"Comical sign",
	"Peace theme from war nation",
	"Walking in circles around each other",
	"Kissing on stage",
	"Song inappropriate for senior citizens",
	"Siblings on stage",
	"Pornstache",
	"Song sharing a title with one previously performed", //As made famous 2015
	"Violent disposal of footwear",
	// "Breaking the fourth wall", //Was added in 2015, can't remember why? Might cause confusion to user/not obvious.
	"Preposterous dress",
	"Shocking shoes",
	"Flying",
	"(Dis)apparation",
	"Demonic ritual",
	"Cape",
	"On-stage selfie",
	"Tinfoil hat",
	"Destroying equipment",
	"Winking to camera",
	"Selfie stick used by artist",
	"Bald person banging on drums", // Thanks Kathi
	"Appearing taller than they really are"
]
<|endoftext|>


<commit_before>var Latexdown={
  delay: 150,        // delay after keystroke before updating

  previewid: null,
  eventtapid: null,
  preview: null,     // filled in by Init below

  timeout: null,     // store setTimout id
  mjRunning: false,  // true when MathJax is processing
  oldText: null,     // used to check if an update is needed

  Init: function (pid,eid) {
    this.previewid=pid;
    this.eventtabid=eid;
    this.preview=document.getElementById(this.previewid);
  },
  Update: function () {
    if (this.timeout) {clearTimeout(this.timeout)}
    this.timeout = setTimeout(this.callback,this.delay);
  },
  PreviewHtml: function () {
    this.mjRunning = false;
  },
  PreviewMark: function () {
    this.mjRunning = false;
    text = this.preview.innerHTML;
    //text = text.replace(/^>/mg, '>');
    this.preview.innerHTML = marked (text);
  },
  IsMarkdown: function(url){
    ext = url.split('.').pop().toLowerCase();
    if ($.inArray(ext, ['md', 'markdown', 'mdown', 'mkdn', 'mkd', 'mdtxt', 'mdtext']) == -1) {
        return false;
    }
    else{
        return true;
    }
  },
  UpdateTab: function(url , pane){
    var _this=this;
    $.get(url, function(data) {
        //this.timeout = null;
        if (_this.mjRunning) return;
        var text = data;
        if (text === _this.oldtext) return;
        _this.preview.innerHTML = _this.oldtext = text;
        _this.mjRunning = true;
        console.log(url);
        if(_this.IsMarkdown(url) &&false ){
            MathJax.Hub.Queue(["Typeset",MathJax.Hub,_this.preview],["PreviewMark",_this]);
        }
        else{
            MathJax.Hub.Queue(["Typeset",MathJax.Hub,_this.preview],["PreviewHTML",_this]);
        }
        makerbutton();
        pane.tab('show');
    });
  }
};

Latexdown.callback=MathJax.Callback(["UpdateTab",Latexdown]);
Latexdown.callback.autoReset = true;

<commit_msg>Update updatetab.js<commit_after>var Latexdown={
  delay: 150,        // delay after keystroke before updating

  previewid: null,
  eventtapid: null,
  preview: null,     // filled in by Init below

  timeout: null,     // store setTimout id
  mjRunning: false,  // true when MathJax is processing
  oldText: null,     // used to check if an update is needed

  Init: function (pid,eid) {
    this.previewid=pid;
    this.eventtabid=eid;
    this.preview=document.getElementById(this.previewid);
  },
  Update: function () {
    if (this.timeout) {clearTimeout(this.timeout)}
    this.timeout = setTimeout(this.callback,this.delay);
  },
  PreviewHtml: function () {
    this.mjRunning = false;
  },
  PreviewMark: function () {
    this.mjRunning = false;
    text = this.preview.innerHTML;
    //text = text.replace(/^>/mg, '>');
    this.preview.innerHTML = marked (text);
  },
  IsMarkdown: function(url){
    ext = url.split('.').pop().toLowerCase();
    if ($.inArray(ext, ['md', 'markdown', 'mdown', 'mkdn', 'mkd', 'mdtxt', 'mdtext']) == -1) {
        return false;
    }
    else{
        return true;
    }
  },
  UpdateTab: function(url , pane){
    var _this=this;
    $.get(url, function(data) {
        //this.timeout = null;
        if (_this.mjRunning) return;
        var text = data;
        if (text === _this.oldtext) return;
        _this.preview.innerHTML = _this.oldtext = text;
        _this.mjRunning = true;
        console.log(url);
        if(_this.IsMarkdown(url) &&false ){
            MathJax.Hub.Queue(["Typeset",MathJax.Hub,_this.preview],["PreviewMark",_this]);
        }
        else{
        //    MathJax.Hub.Queue(["Typeset",MathJax.Hub,_this.preview],["PreviewHTML",_this]);
        MathJax.Hub.Queue(["Typeset",MathJax.Hub,_this.preview]);
        }
        makerbutton();
        pane.tab('show');
    });
  }
};

Latexdown.callback=MathJax.Callback(["UpdateTab",Latexdown]);
Latexdown.callback.autoReset = true;

<|endoftext|>