<commit_before>/**
 * get-tweets.js
 * http://github.com/kevindeleon/get-tweets
 *
 * Copyright 2013, Kevin deLeon
 * Licensed under the MIT license.
 * http://github.com/kevindeleon/get-tweets/blob/master/LICENSE
 *
 * Much of this logic was derrived from blogger.js from Twitter and converted to jQuery
 * The releative_time function was take directly from Twitter's blogger.js
 *
 * Author: Kevin deLeon (http://github.com/kevindeleon)
 */

// Receives JSON object returned by get_most_recent from get-tweets.php
function display_tweets(tweets) {
    var statusHTML = "";
	jQuery.each(tweets, function(i, tweet) {
	    //let's check to make sure we actually have a tweet
		if (tweet.text !== undefined) {
			var username = tweet.user.screen_name;
            var status = tweet.text.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
                return ''+url+'';
            }).replace(/\B@([_a-z0-9]+)/ig, function(reply) {
                return  reply.charAt(0)+''+reply.substring(1)+'';
            });
            statusHTML = '
'+status+' '+relative_time(tweet.created_at)+'
';
            jQuery('.tweet-loader').remove();
            jQuery('#twitter_update_list').append(statusHTML);
		}
	});
}

// taken from Twitter's blogger.js
// Makes our "x time ago" data prettier for display
function relative_time(time_value) {
  var values = time_value.split(" ");
  time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
  var parsed_date = Date.parse(time_value);
  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
  delta = delta + (relative_to.getTimezoneOffset() * 60);

  if (delta < 60) {
    return 'less than a minute ago';
  } else if(delta < 120) {
    return 'about a minute ago';
  } else if(delta < (60*60)) {
    return (parseInt(delta / 60)).toString() + ' minutes ago';
  } else if(delta < (120*60)) {
    return 'about an hour ago';
  } else if(delta < (24*60*60)) {
    return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
  } else if(delta < (48*60*60)) {
    return '1 day ago';
  } else {
    return (parseInt(delta / 86400)).toString() + ' days ago';
  }
}<commit_msg>adding some useful comments<commit_after>/**
 * get-tweets.js
 * http://github.com/kevindeleon/get-tweets
 *
 * Copyright 2013, Kevin deLeon
 * Licensed under the MIT license.
 * http://github.com/kevindeleon/get-tweets/blob/master/LICENSE
 *
 * Much of this logic was derrived from blogger.js from Twitter and converted to jQuery
 * The releative_time function was take directly from Twitter's blogger.js
 *
 * Author: Kevin deLeon (http://github.com/kevindeleon)
 */

// Receives JSON object returned by get_most_recent from get-tweets.php
function display_tweets(tweets) {
    var statusHTML = "";
	jQuery.each(tweets, function(i, tweet) {
	    //let's check to make sure we actually have a tweet
		if (tweet.text !== undefined) {
			var username = tweet.user.screen_name;
			//let's grab the tweet, and do some housekeeping to display it properly
            var status = tweet.text.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
                return ''+url+'';
            }).replace(/\B@([_a-z0-9]+)/ig, function(reply) {
                return  reply.charAt(0)+''+reply.substring(1)+'';
            });
            statusHTML = '
'+status+' '+relative_time(tweet.created_at)+'
';
            //remove the loader
            jQuery('.tweet-loader').remove();
            //display tweet(s)
            jQuery('#twitter_update_list').append(statusHTML);
		}
	});
}

// taken from Twitter's blogger.js
// Makes our "x time ago" data prettier for display
function relative_time(time_value) {
  var values = time_value.split(" ");
  time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
  var parsed_date = Date.parse(time_value);
  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
  delta = delta + (relative_to.getTimezoneOffset() * 60);

  if (delta < 60) {
    return 'less than a minute ago';
  } else if(delta < 120) {
    return 'about a minute ago';
  } else if(delta < (60*60)) {
    return (parseInt(delta / 60)).toString() + ' minutes ago';
  } else if(delta < (120*60)) {
    return 'about an hour ago';
  } else if(delta < (24*60*60)) {
    return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
  } else if(delta < (48*60*60)) {
    return '1 day ago';
  } else {
    return (parseInt(delta / 86400)).toString() + ' days ago';
  }
}<|endoftext|>


<commit_before>'use strict';

// NIVEL CRUD

var express = require('express');
var router = express.Router();

var Museo = require('../../models/model');

// Rutas que terminan en /adquisicion
// POST /adquisicion
router.post('/', function (req, res) {
  // bodyParser debe hacer la magia
  var tipoAdquisicion = req.body.tipoAdquisicion;
  var tipoCompra = req.body.tipoCompra;
  var fecha = req.body.fecha;

  var adquisicion = Museo.Adquisicion.build({
    tipoAdquisicion: tipoAdquisicion,
    tipoCompra: tipoCompra,
    fecha: fecha
  });

  adquisicion.add(function (success) {
    res.render( 'web/adquisicion/list',{ message: 'Adquisicion creada!' } );
  },
  function (err) {
    res.send(err);
  });
});
// (trae todas las adquisiciones)
// GET /adquisiciones
router.get('/', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();

  adquisicion.retrieveAll(function (adquisiciones) {
    if (adquisiciones) {
      res.render('web/adquisicion/list.ejs', { adquisiciones: adquisiciones});
    } else {
      res.send(401, 'No se encontraron Adquisiciones');
    }
  }, function (error) {
    res.send('Adquisicion no encontrada');
  });
});
// Rutas que terminan en /adquisicion/:adquisicionId
// PUT /adquisicion/:adquisicionId
// Actualiza adquisicion
router.put('/:adquisicionId', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();
  console.log('ingresa al put');

  adquisicion.id = req.body.id;
  adquisicion.tipoAdquisicion = req.body.tipoAdquisicion;
  adquisicion.tipoCompra = req.body.tipoCompra;
  adquisicion.fecha = req.body.fecha;

  console.log('ingresa al put: pre update');

  adquisicion.updateById(adquisicion.id, adquisicion.tipoAdquisicion, adquisicion.tipoCompra, adquisicion.fecha, function (success) {
    console.log(success);
    if (success) {
      res.redirect('/web/adquisicion');
    } else {
      console.log(success);
      res.send(401, 'Adquisicion no encontrada');
    }
  }, function (error) {
    console.log(error);
    res.send('Adquisicion no encontrada');
  });
});
// GET /adquisicion/:adquisicionId
// Toma una adquisicion por id
router.get('/:adquisicionId', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();

  adquisicion.retrieveById(req.params.adquisicionId, function (adquisicionq) {
    if (adquisicionq) {
      res.render('web/adquisicion/edit', {adquisicion:adquisicionq});
    } else {
      res.send(401, 'Adquisicion no encontrada');
    }
  }, function (error) {
    res.send('Adquisicion no encontrada');
  });
});
// DELETE /adquisicion/adquisicionId
// Borra el adquisicionId
router.delete('/:adquisicionId', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();

  adquisicion.removeById(req.params.adquisicionId, function (adquisicion) {
    if (adquisicion) {
      res.json({ message: 'Adquisicion borrada!' });
    } else {
      res.send(401, 'Adquisicion no encontrada');
    }
  }, function (error) {
    res.send('Adquisicion no encontrada');
  });
});

module.exports = router;
<commit_msg>put funcionando<commit_after>'use strict';

// NIVEL CRUD

var express = require('express');
var router = express.Router();

var Museo = require('../../models/model');

// Rutas que terminan en /adquisicion
// POST /adquisicion
router.post('/', function (req, res) {
  // bodyParser debe hacer la magia
  var tipoAdquisicion = req.body.tipoAdquisicion;
  var tipoCompra = req.body.tipoCompra;
  var fecha = req.body.fecha;

  var adquisicion = Museo.Adquisicion.build({
    tipoAdquisicion: tipoAdquisicion,
    tipoCompra: tipoCompra,
    fecha: fecha
  });

  adquisicion.add(function (success) {
    res.render( 'web/adquisicion/list',{ message: 'Adquisicion creada!' } );
  },
  function (err) {
    res.send(err);
  });
});
// (trae todas las adquisiciones)
// GET /adquisiciones
router.get('/', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();

  adquisicion.retrieveAll(function (adquisiciones) {
    if (adquisiciones) {
      res.render('web/adquisicion/list.ejs', { adquisiciones: adquisiciones});
    } else {
      res.send(401, 'No se encontraron Adquisiciones');
    }
  }, function (error) {
    res.send('Adquisicion no encontrada');
  });
});
// Rutas que terminan en /adquisicion/:adquisicionId
// PUT /adquisicion/:adquisicionId
// Actualiza adquisicion
router.put('/:adquisicionId', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();
  console.log('ingresa al put');
  adquisicion.id = req.body.id;
  adquisicion.tipoAdquisicion = req.body.tipoAdquisicion;
  adquisicion.tipoCompra = req.body.tipoCompra;
  adquisicion.fecha = req.body.fecha;

  console.log('ingresa al put: pre update');

  adquisicion.updateById(adquisicion.id, adquisicion.tipoAdquisicion, adquisicion.tipoCompra, adquisicion.fecha, function (success) {
    console.log(success);
    if (success) {
      res.redirect('/web/adquisicion');
    } else {
      console.log(success);
      res.send(401, 'Adquisicion no encontrada');
    }
  }, function (error) {
    console.log(error);
    res.send('Adquisicion no encontrada');
  });
});
// GET /adquisicion/:adquisicionId
// Toma una adquisicion por id
router.get('/:adquisicionId', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();

  adquisicion.retrieveById(req.params.adquisicionId, function (adquisicionq) {
    if (adquisicionq) {
      res.render('web/adquisicion/edit', {adquisicion:adquisicionq});
    } else {
      res.send(401, 'Adquisicion no encontrada');
    }
  }, function (error) {
    res.send('Adquisicion no encontrada');
  });
});
// DELETE /adquisicion/adquisicionId
// Borra el adquisicionId
router.delete('/:adquisicionId', function (req, res) {
  var adquisicion = Museo.Adquisicion.build();

  adquisicion.removeById(req.params.adquisicionId, function (adquisicion) {
    if (adquisicion) {
      res.json({ message: 'Adquisicion borrada!' });
    } else {
      res.send(401, 'Adquisicion no encontrada');
    }
  }, function (error) {
    res.send('Adquisicion no encontrada');
  });
});

module.exports = router;
<|endoftext|>


<commit_before>/*
**  BindingJS -- View Data Binding for JavaScript <http://bindingjs.com>
**  Copyright (c) 2014 Ralf S. Engelschall <http://engelschall.com>
**
**  This Source Code Form is subject to the terms of the Mozilla Public
**  License (MPL), version 2.0. If a copy of the MPL was not distributed
**  with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/*  provide a helper function for unrolling the parse stack  */
_api.unroll = (first, list, take) => {
    if (   typeof list !== "object"
        || !(list instanceof Array))
        throw "unroll: invalid list argument (expected Array)"
    if (typeof take !== "undefined") {
        if (typeof take === "number")
            take = [ take ]
        let result = []
        if (first !== null)
            result.push(first)
        for (let i = 0; i < list.length; i++) {
            for (let j = 0; j < take.length; j++)
                result.push(list[i][take[j]])
        }
        return result
    }
    else {
        if (first !== null)
            list.unshift(first)
        return list
    }
}

/*  include the generated PEG parser  */
_api.parser = (function () {
    let module = {}
    include("binding-3-dsl-2-grammar.js")
    return module.exports
})()

/*  utility function  */
let excerpt = (txt, o) => {
    let l = txt.length
    let b = o - 20; if (b < 0) b = 0
    let e = o + 20; if (e > l) e = l
    return {
        prolog: txt.substr(b, o - b).replace(/\r/g, "\\r").replace(/\n/g, "\\n"),
        token:  txt.substr(o, 1).replace(/\r/g, "\\r").replace(/\n/g, "\\n"),
        epilog: txt.substr(o + 1, e - (o + 1)).replace(/\r/g, "\\r").replace(/\n/g, "\\n")
    }
}

/*  provide top-level parsing functionality  */
$api.parse = (txt, rule) => {
    if (typeof rule === "undefined")
        rule = "spec"
    let result = { ast: null, error: null }
    try {
        result.ast = _api.parser.parse(txt, { startRule: rule })
    }
    catch (e) {
        result.error = {
            line:     e.line,
            column:   e.column,
            message:  e.message,
            found:    e.found,
            expected: e.expected,
            location: excerpt(txt, e.offset)
        }
    }
    return result
}

<commit_msg>factor out text extraction<commit_after>/*
**  BindingJS -- View Data Binding for JavaScript <http://bindingjs.com>
**  Copyright (c) 2014 Ralf S. Engelschall <http://engelschall.com>
**
**  This Source Code Form is subject to the terms of the Mozilla Public
**  License (MPL), version 2.0. If a copy of the MPL was not distributed
**  with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/*  provide a helper function for unrolling the parse stack  */
_api.unroll = (first, list, take) => {
    if (   typeof list !== "object"
        || !(list instanceof Array))
        throw "unroll: invalid list argument (expected Array)"
    if (typeof take !== "undefined") {
        if (typeof take === "number")
            take = [ take ]
        let result = []
        if (first !== null)
            result.push(first)
        for (let i = 0; i < list.length; i++) {
            for (let j = 0; j < take.length; j++)
                result.push(list[i][take[j]])
        }
        return result
    }
    else {
        if (first !== null)
            list.unshift(first)
        return list
    }
}

/*  include the generated PEG parser  */
_api.parser = (function () {
    let module = {}
    include("binding-3-dsl-2-grammar.js")
    return module.exports
})()

/*  utility function  */
let excerpt = (txt, o) => {
    let l = txt.length
    let b = o - 20; if (b < 0) b = 0
    let e = o + 20; if (e > l) e = l
    let extract = (txt, pos, len) =>
        txt.substr(pos, len).replace(/\r/g, "\\r").replace(/\n/g, "\\n")
    return {
        prolog: extract(txt, b, o - b),
        token:  extract(txt, o, 1),
        epilog: extract(txt, o + 1, e - (o + 1))
    }
}

/*  provide top-level parsing functionality  */
$api.parse = (txt, rule) => {
    if (typeof rule === "undefined")
        rule = "spec"
    let result = { ast: null, error: null }
    try {
        result.ast = _api.parser.parse(txt, { startRule: rule })
    }
    catch (e) {
        result.error = {
            line:     e.line,
            column:   e.column,
            message:  e.message,
            found:    e.found,
            expected: e.expected,
            location: excerpt(txt, e.offset)
        }
    }
    return result
}

<|endoftext|>


<commit_before>(function() {
  'use strict';

  var $mdUtil, $interpolate;

  var SUFFIXES = /(-gt)?-(sm|md|lg)/g;
  var WHITESPACE = /\s+/g;

  var FLEX_OPTIONS = ['grow', 'initial', 'auto', 'none'];
  var LAYOUT_OPTIONS = ['row', 'column'];
  var ALIGNMENT_OPTIONS = [
        "start start", "start center", "start end",
        "center", "center center", "center start", "center end",
        "end", "end center", "end start", "end end",
        "space-around", "space-around center", "space-around start", "space-around end",
        "space-between", "space-between center", "space-between start", "space-between end"
      ];

  var config = {
    /**
     * Enable directive attribute-to-class conversions
     */
    enabled: true,

    /**
     * After translation to classname equivalents, remove the
     * original Layout attribute
     */
    removeAttributes : true,

    /**
     * List of mediaQuery breakpoints and associated suffixes
     *
     *   [
     *    { suffix: "sm", mediaQuery: "screen and (max-width: 599px)" },
     *    { suffix: "md", mediaQuery: "screen and (min-width: 600px) and (max-width: 959px)" }
     *   ]
     */
    breakpoints: []
  };

  /**
   *   The original ngMaterial Layout solution used attribute selectors and CSS.
   *
   *  ```html
   *  <div layout="column"> My Content </div>
   *  ```
   *
   *  ```css
   *  [layout] {
     *    box-sizing: border-box;
     *    display:flex;
     *  }
   *  [layout=column] {
     *    flex-direction : column
     *  }
   *  ```
   *
   *  Use of attribute selectors creates significant performance impacts in some
   *  browsers... mainly IE.
   *
   *  This module registers directives that allow the same layout attributes to be
   *  interpreted and converted to class selectors. The directive will add equivalent classes to each element that
   *  contains a Layout directive.
   *
   * ```html
   *   <div layout="column" class="layout layout-column"> My Content </div>
   *```
   *
   *  ```css
   *  .layout {
     *    box-sizing: border-box;
     *    display:flex;
     *  }
   *  .layout-column {
     *    flex-direction : column
     *  }
   *  ```
   */
  angular.module('material.core.layout', ['ng'])

    .directive('mdLayoutCss', disableLayoutDirective )

    .directive('layout', attributeWithObserve('layout'))
    .directive('layoutSm', attributeWithObserve('layout-sm'))
    .directive('layoutGtSm', attributeWithObserve('layout-gt-sm'))
    .directive('layoutMd', attributeWithObserve('layout-md'))
    .directive('layoutGtMd', attributeWithObserve('layout-gt-md'))
    .directive('layoutLg', attributeWithObserve('layout-lg'))
    .directive('layoutGtLg', attributeWithObserve('layout-gt-lg'))

    .directive('flex', attributeWithObserve('flex'))
    .directive('flexSm', attributeWithObserve('flex-sm'))
    .directive('flexGtSm', attributeWithObserve('flex-gt-sm'))
    .directive('flexMd', attributeWithObserve('flex-md'))
    .directive('flexGtMd', attributeWithObserve('flex-gt-md'))
    .directive('flexLg', attributeWithObserve('flex-lg'))
    .directive('flexGtLg', attributeWithObserve('flex-gt-lg'))

    .directive('flexOrder', attributeWithObserve('flex-order'))
    .directive('flexOrderSm', attributeWithObserve('flex-order-sm'))
    .directive('flexOrderGtSm', attributeWithObserve('flex-order-gt-sm'))
    .directive('flexOrderMd', attributeWithObserve('flex-order-md'))
    .directive('flexOrderGtMd', attributeWithObserve('flex-order-gt-md'))
    .directive('flexOrderLg', attributeWithObserve('flex-order-lg'))
    .directive('flexOrderGtLg', attributeWithObserve('flex-order-gt-lg'))

    .directive('flexOffset', attributeWithObserve('flex-offset'))
    .directive('flexOffsetSm', attributeWithObserve('flex-offset-sm'))
    .directive('flexOffsetGtSm', attributeWithObserve('flex-offset-gt-sm'))
    .directive('flexOffsetMd', attributeWithObserve('flex-offset-md'))
    .directive('flexOffsetGtMd', attributeWithObserve('flex-offset-gt-md'))
    .directive('flexOffsetLg', attributeWithObserve('flex-offset-lg'))
    .directive('flexOffsetGtLg', attributeWithObserve('flex-offset-gt-lg'))

    .directive('layoutAlign', attributeWithObserve('layout-align'))
    .directive('layoutAlignSm', attributeWithObserve('layout-align-sm'))
    .directive('layoutAlignGtSm', attributeWithObserve('layout-align-gt-sm'))
    .directive('layoutAlignMd', attributeWithObserve('layout-align-md'))
    .directive('layoutAlignGtMd', attributeWithObserve('layout-align-gt-md'))
    .directive('layoutAlignLg', attributeWithObserve('layout-align-lg'))
    .directive('layoutAlignGtLg', attributeWithObserve('layout-align-gt-lg'))

    // Attribute directives with no value(s)

    .directive('hide', attributeWithoutValue('hide'))
    .directive('hideSm', attributeWithoutValue('hide-sm'))
    .directive('hideGtSm', attributeWithoutValue('hide-gt-sm'))
    .directive('hideMd', attributeWithoutValue('hide-md'))
    .directive('hideGtMd', attributeWithoutValue('hide-gt-md'))
    .directive('hideLg', attributeWithoutValue('hide-lg'))
    .directive('hideGtLg', attributeWithoutValue('hide-gt-lg'))
    .directive('show', attributeWithoutValue('show'))
    .directive('showSm', attributeWithoutValue('show-sm'))
    .directive('showGtSm', attributeWithoutValue('show-gt-sm'))
    .directive('showMd', attributeWithoutValue('show-md'))
    .directive('showGtMd', attributeWithoutValue('show-gt-md'))
    .directive('showLg', attributeWithoutValue('show-lg'))
    .directive('showGtLg', attributeWithoutValue('show-gt-lg'))

    // Attribute directives with no value(s) and NO breakpoints

    .directive('layoutPadding', attributeWithoutValue('layout-padding'))
    .directive('layoutPaddingSm', attributeWithoutValue('layout-padding-sm'))
    .directive('layoutPaddingGtSm', attributeWithoutValue('layout-padding-gt-sm'))
    .directive('layoutPaddingMd', attributeWithoutValue('layout-padding-md'))
    .directive('layoutPaddingGtMd', attributeWithoutValue('layout-padding-gt-md'))
    .directive('layoutPaddingLg', attributeWithoutValue('layout-padding-lg'))
    .directive('layoutPaddingGtLg', attributeWithoutValue('layout-padding-gt-lg'))

    .directive('layoutMargin', attributeWithoutValue('layout-margin'))
    .directive('layoutMarginSm', attributeWithoutValue('layout-margin-sm'))
    .directive('layoutMarginGtSm', attributeWithoutValue('layout-margin-gt-sm'))
    .directive('layoutMarginMd', attributeWithoutValue('layout-margin-md'))
    .directive('layoutMarginGtMd', attributeWithoutValue('layout-margin-gt-md'))
    .directive('layoutMarginLg', attributeWithoutValue('layout-margin-lg'))
    .directive('layoutMarginGtLg', attributeWithoutValue('layout-margin-gt-lg'))

    .directive('layoutWrap', attributeWithoutValue('layout-wrap'))
    .directive('layoutNoWrap', attributeWithoutValue('layout-no-wrap'))
    .directive('layoutFill', attributeWithoutValue('layout-fill'))

    // !! Deprecated attributes: use the `-lt` (aka less-than) notations

    .directive('layoutLtMd', warnAttrNotSupported('layout-lt-md', true))
    .directive('layoutLtLg', warnAttrNotSupported('layout-lt-lg', true))
    .directive('flexLtMd', warnAttrNotSupported('flex-lt-md', true))
    .directive('flexLtLg', warnAttrNotSupported('flex-lt-lg', true))

    .directive('layoutAlignLtMd', warnAttrNotSupported('layout-align-lt-md'))
    .directive('layoutAlignLtLg', warnAttrNotSupported('layout-align-lt-lg'))
    .directive('flexOrderLtMd', warnAttrNotSupported('flex-order-lt-md'))
    .directive('flexOrderLtLg', warnAttrNotSupported('flex-order-lt-lg'))
    .directive('offsetLtMd', warnAttrNotSupported('flex-offset-lt-md'))
    .directive('offsetLtLg', warnAttrNotSupported('flex-offset-lt-lg'))

    .directive('hideLtMd', warnAttrNotSupported('hide-lt-md'))
    .directive('hideLtLg', warnAttrNotSupported('hide-lt-lg'))
    .directive('showLtMd', warnAttrNotSupported('show-lt-md'))
    .directive('showLtLg', warnAttrNotSupported('show-lt-lg'));

  /**
   * Special directive that will disable ALL Layout conversions of layout
   * attribute(s) to classname(s).
   *
   * <link rel="stylesheet" href="angular-material.min.css">
   * <link rel="stylesheet" href="angular-material.layout.css">
   *
   * <body md-layout-css>
   *  ...
   * </body>
   *
   * Note: Using md-layout-css directive requires the developer to load the Material
   * Layout Attribute stylesheet (which only uses attribute selectors):
   *
   *       `angular-material.layout.css`
   *
   * Another option is to use the LayoutProvider to configure and disable the attribute
   * conversions; this would obviate the use of the `md-layout-css` directive
   *
   */
  function disableLayoutDirective() {
    return {
      restrict : 'A',
      priority : '900',
      compile  : function(element, attr) {
        config.enabled = false;
        return angular.noop;
      }
    };
  }

  // *********************************************************************************
  //
  // These functions create registration functions for ngMaterial Layout attribute directives
  // This provides easy translation to switch ngMaterial attribute selectors to
  // CLASS selectors and directives; which has huge performance implications
  // for IE Browsers
  //
  // *********************************************************************************

  /**
   * Creates a directive registration function where a possible dynamic attribute
   * value will be observed/watched.
   * @param {string} className attribute name; eg `layout-gt-md` with value ="row"
   */
  function attributeWithObserve(className) {

    return ['$mdUtil', '$interpolate', function(_$mdUtil_, _$interpolate_) {
      $mdUtil = _$mdUtil_;
      $interpolate = _$interpolate_;

      return {
        restrict: 'A',
        compile: function(element, attr) {
          var linkFn;
          if (config.enabled) {
            // immediately replace static (non-interpolated) invalid values...

            validateAttributeValue( className,
              getNormalizedAttrValue(className, attr, ""),
              buildUpdateFn(element, className, attr)
            );

            linkFn = translateWithValueToCssClass;
          }

          // Use for postLink to account for transforms after ng-transclude.
          return linkFn || angular.noop;
        }
      };
    }];

    /**
     * Add as transformed class selector(s), then
     * remove the deprecated attribute selector
     */
    function translateWithValueToCssClass(scope, element, attrs) {
      var updateFn = updateClassWithValue(element, className, attrs);
      var unwatch = attrs.$observe(attrs.$normalize(className), updateFn);

      updateFn(getNormalizedAttrValue(className, attrs, ""));
      scope.$on("$destroy", function() { unwatch() });

      if (config.removeAttributes) element.removeAttr(className);
    }
  }

  /**
   * Creates a registration function for ngMaterial Layout attribute directive.
   * This is a `simple` transpose of attribute usage to class usage; where we ignore
   * any attribute value
   */
  function attributeWithoutValue(className) {
    return ['$interpolate', function(_$interpolate_) {
      $interpolate = _$interpolate_;

      return {
        restrict: 'A',
        compile: function(element, attr) {
          var linkFn;
          if (config.enabled) {
            // immediately replace static (non-interpolated) invalid values...

            validateAttributeValue( className,
              getNormalizedAttrValue(className, attr, ""),
              buildUpdateFn(element, className, attr)
            );

            translateToCssClass(null, element);

            // Use for postLink to account for transforms after ng-transclude.
            linkFn = translateToCssClass;
          }

          return linkFn || angular.noop;
        }
      };
    }];

    /**
     * Add as transformed class selector, then
     * remove the deprecated attribute selector
     */
    function translateToCssClass(scope, element) {
      element.addClass(className);

      if (config.removeAttributes) {
        // After link-phase, remove deprecated layout attribute selector
        element.removeAttr(className);
      }
    }
  }

  /**
   * After link-phase, do NOT remove deprecated layout attribute selector.
   * Instead watch the attribute so interpolated data-bindings to layout
   * selectors will continue to be supported.
   *
   * $observe() the className and update with new class (after removing the last one)
   *
   * e.g. `layout="{{layoutDemo.direction}}"` will update...
   *
   * NOTE: The value must match one of the specified styles in the CSS.
   * For example `flex-gt-md="{{size}}`  where `scope.size == 47` will NOT work since
   * only breakpoints for 0, 5, 10, 15... 100, 33, 34, 66, 67 are defined.
   *
   */
  function updateClassWithValue(element, className) {
    var lastClass;

    return function updateClassFn(newValue) {
      var value = validateAttributeValue(className, newValue || "");
      if ( angular.isDefined(value) ) {
        if (lastClass) {
          element.removeClass(lastClass);
        }
        lastClass = !value ? className : className + "-" + value.replace(WHITESPACE, "-");
        element.addClass(lastClass);
      }
    };
  }

  /**
   * Provide console warning that this layout attribute has been deprecated
   *
   */
  function warnAttrNotSupported(className) {
    var parts = className.split("-");
    return ["$log", function($log) {
      $log.warn(className + "has been deprecated. Please use a `" + parts[0] + "-gt-<xxx>` variant.");
      return angular.noop;
    }];
  }

  /**
   * For the Layout attribute value, validate or replace with default
   * fallback value
   */
  function validateAttributeValue(className, value, updateFn) {
    var origValue = value;

    if (!needsInterpolation(value)) {
      switch (className.replace(SUFFIXES,"")) {
        case 'layout'        :
          if ( !findIn(value, LAYOUT_OPTIONS) ) {
            value = LAYOUT_OPTIONS[0];    // 'row';
          }
          break;

        case 'flex'          :
          if (!findIn(value, FLEX_OPTIONS)) {
            if (isNaN(value)) {
              value = '';
            }
          }
          break;

        case 'flex-offset' :
        case 'flex-order'    :
          if (!value || isNaN(+value)) {
            value = '0';
          }
          break;

        case 'layout-align'  :
          if (!findIn(value, ALIGNMENT_OPTIONS, "-")) {
            value = ALIGNMENT_OPTIONS[0];   // 'start-start';
          }
          break;

        case 'layout-padding' :
        case 'layout-margin'  :
        case 'layout-fill'    :
        case 'layout-wrap'    :
        case 'layout-no-wrap' :
          value = '';
          break;
      }

      if (value != origValue) {
        (updateFn || angular.noop)(value);
      }
    }

    return value;
  }

  /**
   * Replace current attribute value with fallback value
   */
  function buildUpdateFn(element, className, attrs) {
    return function updateAttrValue(fallback) {
      if (!needsInterpolation(fallback)) {
        element.attr(className, fallback);
        attrs[attrs.$normalize(className)] = fallback;
      }
    };
  }

  /**
   * See if the original value has interpolation symbols:
   * e.g.  flex-gt-md="{{triggerPoint}}"
   */
  function needsInterpolation(value) {
    return (value || "").indexOf($interpolate.startSymbol()) > -1;
  }

  function getNormalizedAttrValue(className, attrs, defaultVal) {
    var normalizedAttr = attrs.$normalize(className);
    return attrs[normalizedAttr] ? attrs[normalizedAttr].replace(WHITESPACE, "-") : defaultVal || null;
  }

  function findIn(item, list, replaceWith) {
    item = replaceWith && item ? item.replace(WHITESPACE, replaceWith) : item;

    var found = false;
    if (item) {
      list.forEach(function(it) {
        it = replaceWith ? it.replace(WHITESPACE, replaceWith) : it;
        found = found || (it === item);
      });
    }
    return found;
  }

})();
<commit_msg>fix(layouts): removeAttr RTE on comment nodes<commit_after>(function() {
  'use strict';

  var $mdUtil, $interpolate;

  var SUFFIXES = /(-gt)?-(sm|md|lg)/g;
  var WHITESPACE = /\s+/g;

  var FLEX_OPTIONS = ['grow', 'initial', 'auto', 'none'];
  var LAYOUT_OPTIONS = ['row', 'column'];
  var ALIGNMENT_OPTIONS = [
        "start start", "start center", "start end",
        "center", "center center", "center start", "center end",
        "end", "end center", "end start", "end end",
        "space-around", "space-around center", "space-around start", "space-around end",
        "space-between", "space-between center", "space-between start", "space-between end"
      ];

  var config = {
    /**
     * Enable directive attribute-to-class conversions
     */
    enabled: true,

    /**
     * After translation to classname equivalents, remove the
     * original Layout attribute
     */
    removeAttributes : true,

    /**
     * List of mediaQuery breakpoints and associated suffixes
     *
     *   [
     *    { suffix: "sm", mediaQuery: "screen and (max-width: 599px)" },
     *    { suffix: "md", mediaQuery: "screen and (min-width: 600px) and (max-width: 959px)" }
     *   ]
     */
    breakpoints: []
  };

  /**
   *   The original ngMaterial Layout solution used attribute selectors and CSS.
   *
   *  ```html
   *  <div layout="column"> My Content </div>
   *  ```
   *
   *  ```css
   *  [layout] {
     *    box-sizing: border-box;
     *    display:flex;
     *  }
   *  [layout=column] {
     *    flex-direction : column
     *  }
   *  ```
   *
   *  Use of attribute selectors creates significant performance impacts in some
   *  browsers... mainly IE.
   *
   *  This module registers directives that allow the same layout attributes to be
   *  interpreted and converted to class selectors. The directive will add equivalent classes to each element that
   *  contains a Layout directive.
   *
   * ```html
   *   <div layout="column" class="layout layout-column"> My Content </div>
   *```
   *
   *  ```css
   *  .layout {
     *    box-sizing: border-box;
     *    display:flex;
     *  }
   *  .layout-column {
     *    flex-direction : column
     *  }
   *  ```
   */
  angular.module('material.core.layout', ['ng'])

    .directive('mdLayoutCss', disableLayoutDirective )

    .directive('layout', attributeWithObserve('layout'))
    .directive('layoutSm', attributeWithObserve('layout-sm'))
    .directive('layoutGtSm', attributeWithObserve('layout-gt-sm'))
    .directive('layoutMd', attributeWithObserve('layout-md'))
    .directive('layoutGtMd', attributeWithObserve('layout-gt-md'))
    .directive('layoutLg', attributeWithObserve('layout-lg'))
    .directive('layoutGtLg', attributeWithObserve('layout-gt-lg'))

    .directive('flex', attributeWithObserve('flex'))
    .directive('flexSm', attributeWithObserve('flex-sm'))
    .directive('flexGtSm', attributeWithObserve('flex-gt-sm'))
    .directive('flexMd', attributeWithObserve('flex-md'))
    .directive('flexGtMd', attributeWithObserve('flex-gt-md'))
    .directive('flexLg', attributeWithObserve('flex-lg'))
    .directive('flexGtLg', attributeWithObserve('flex-gt-lg'))

    .directive('flexOrder', attributeWithObserve('flex-order'))
    .directive('flexOrderSm', attributeWithObserve('flex-order-sm'))
    .directive('flexOrderGtSm', attributeWithObserve('flex-order-gt-sm'))
    .directive('flexOrderMd', attributeWithObserve('flex-order-md'))
    .directive('flexOrderGtMd', attributeWithObserve('flex-order-gt-md'))
    .directive('flexOrderLg', attributeWithObserve('flex-order-lg'))
    .directive('flexOrderGtLg', attributeWithObserve('flex-order-gt-lg'))

    .directive('flexOffset', attributeWithObserve('flex-offset'))
    .directive('flexOffsetSm', attributeWithObserve('flex-offset-sm'))
    .directive('flexOffsetGtSm', attributeWithObserve('flex-offset-gt-sm'))
    .directive('flexOffsetMd', attributeWithObserve('flex-offset-md'))
    .directive('flexOffsetGtMd', attributeWithObserve('flex-offset-gt-md'))
    .directive('flexOffsetLg', attributeWithObserve('flex-offset-lg'))
    .directive('flexOffsetGtLg', attributeWithObserve('flex-offset-gt-lg'))

    .directive('layoutAlign', attributeWithObserve('layout-align'))
    .directive('layoutAlignSm', attributeWithObserve('layout-align-sm'))
    .directive('layoutAlignGtSm', attributeWithObserve('layout-align-gt-sm'))
    .directive('layoutAlignMd', attributeWithObserve('layout-align-md'))
    .directive('layoutAlignGtMd', attributeWithObserve('layout-align-gt-md'))
    .directive('layoutAlignLg', attributeWithObserve('layout-align-lg'))
    .directive('layoutAlignGtLg', attributeWithObserve('layout-align-gt-lg'))

    // Attribute directives with no value(s)

    .directive('hide', attributeWithoutValue('hide'))
    .directive('hideSm', attributeWithoutValue('hide-sm'))
    .directive('hideGtSm', attributeWithoutValue('hide-gt-sm'))
    .directive('hideMd', attributeWithoutValue('hide-md'))
    .directive('hideGtMd', attributeWithoutValue('hide-gt-md'))
    .directive('hideLg', attributeWithoutValue('hide-lg'))
    .directive('hideGtLg', attributeWithoutValue('hide-gt-lg'))
    .directive('show', attributeWithoutValue('show'))
    .directive('showSm', attributeWithoutValue('show-sm'))
    .directive('showGtSm', attributeWithoutValue('show-gt-sm'))
    .directive('showMd', attributeWithoutValue('show-md'))
    .directive('showGtMd', attributeWithoutValue('show-gt-md'))
    .directive('showLg', attributeWithoutValue('show-lg'))
    .directive('showGtLg', attributeWithoutValue('show-gt-lg'))

    // Attribute directives with no value(s) and NO breakpoints

    .directive('layoutPadding', attributeWithoutValue('layout-padding'))
    .directive('layoutPaddingSm', attributeWithoutValue('layout-padding-sm'))
    .directive('layoutPaddingGtSm', attributeWithoutValue('layout-padding-gt-sm'))
    .directive('layoutPaddingMd', attributeWithoutValue('layout-padding-md'))
    .directive('layoutPaddingGtMd', attributeWithoutValue('layout-padding-gt-md'))
    .directive('layoutPaddingLg', attributeWithoutValue('layout-padding-lg'))
    .directive('layoutPaddingGtLg', attributeWithoutValue('layout-padding-gt-lg'))

    .directive('layoutMargin', attributeWithoutValue('layout-margin'))
    .directive('layoutMarginSm', attributeWithoutValue('layout-margin-sm'))
    .directive('layoutMarginGtSm', attributeWithoutValue('layout-margin-gt-sm'))
    .directive('layoutMarginMd', attributeWithoutValue('layout-margin-md'))
    .directive('layoutMarginGtMd', attributeWithoutValue('layout-margin-gt-md'))
    .directive('layoutMarginLg', attributeWithoutValue('layout-margin-lg'))
    .directive('layoutMarginGtLg', attributeWithoutValue('layout-margin-gt-lg'))

    .directive('layoutWrap', attributeWithoutValue('layout-wrap'))
    .directive('layoutNoWrap', attributeWithoutValue('layout-no-wrap'))
    .directive('layoutFill', attributeWithoutValue('layout-fill'))

    // !! Deprecated attributes: use the `-lt` (aka less-than) notations

    .directive('layoutLtMd', warnAttrNotSupported('layout-lt-md', true))
    .directive('layoutLtLg', warnAttrNotSupported('layout-lt-lg', true))
    .directive('flexLtMd', warnAttrNotSupported('flex-lt-md', true))
    .directive('flexLtLg', warnAttrNotSupported('flex-lt-lg', true))

    .directive('layoutAlignLtMd', warnAttrNotSupported('layout-align-lt-md'))
    .directive('layoutAlignLtLg', warnAttrNotSupported('layout-align-lt-lg'))
    .directive('flexOrderLtMd', warnAttrNotSupported('flex-order-lt-md'))
    .directive('flexOrderLtLg', warnAttrNotSupported('flex-order-lt-lg'))
    .directive('offsetLtMd', warnAttrNotSupported('flex-offset-lt-md'))
    .directive('offsetLtLg', warnAttrNotSupported('flex-offset-lt-lg'))

    .directive('hideLtMd', warnAttrNotSupported('hide-lt-md'))
    .directive('hideLtLg', warnAttrNotSupported('hide-lt-lg'))
    .directive('showLtMd', warnAttrNotSupported('show-lt-md'))
    .directive('showLtLg', warnAttrNotSupported('show-lt-lg'));

  /**
   * Special directive that will disable ALL Layout conversions of layout
   * attribute(s) to classname(s).
   *
   * <link rel="stylesheet" href="angular-material.min.css">
   * <link rel="stylesheet" href="angular-material.layout.css">
   *
   * <body md-layout-css>
   *  ...
   * </body>
   *
   * Note: Using md-layout-css directive requires the developer to load the Material
   * Layout Attribute stylesheet (which only uses attribute selectors):
   *
   *       `angular-material.layout.css`
   *
   * Another option is to use the LayoutProvider to configure and disable the attribute
   * conversions; this would obviate the use of the `md-layout-css` directive
   *
   */
  function disableLayoutDirective() {
    return {
      restrict : 'A',
      priority : '900',
      compile  : function(element, attr) {
        config.enabled = false;
        return angular.noop;
      }
    };
  }

  // *********************************************************************************
  //
  // These functions create registration functions for ngMaterial Layout attribute directives
  // This provides easy translation to switch ngMaterial attribute selectors to
  // CLASS selectors and directives; which has huge performance implications
  // for IE Browsers
  //
  // *********************************************************************************

  /**
   * Creates a directive registration function where a possible dynamic attribute
   * value will be observed/watched.
   * @param {string} className attribute name; eg `layout-gt-md` with value ="row"
   */
  function attributeWithObserve(className) {

    return ['$mdUtil', '$interpolate', function(_$mdUtil_, _$interpolate_) {
      $mdUtil = _$mdUtil_;
      $interpolate = _$interpolate_;

      return {
        restrict: 'A',
        compile: function(element, attr) {
          var linkFn;
          if (config.enabled) {
            // immediately replace static (non-interpolated) invalid values...

            validateAttributeValue( className,
              getNormalizedAttrValue(className, attr, ""),
              buildUpdateFn(element, className, attr)
            );

            linkFn = translateWithValueToCssClass;
          }

          // Use for postLink to account for transforms after ng-transclude.
          return linkFn || angular.noop;
        }
      };
    }];

    /**
     * Add as transformed class selector(s), then
     * remove the deprecated attribute selector
     */
    function translateWithValueToCssClass(scope, element, attrs) {
      var updateFn = updateClassWithValue(element, className, attrs);
      var unwatch = attrs.$observe(attrs.$normalize(className), updateFn);

      updateFn(getNormalizedAttrValue(className, attrs, ""));
      scope.$on("$destroy", function() { unwatch() });

      if (config.removeAttributes && (element[0].nodeName != "#comment")) {
        element.removeAttr(className);
      }
    }
  }

  /**
   * Creates a registration function for ngMaterial Layout attribute directive.
   * This is a `simple` transpose of attribute usage to class usage; where we ignore
   * any attribute value
   */
  function attributeWithoutValue(className) {
    return ['$interpolate', function(_$interpolate_) {
      $interpolate = _$interpolate_;

      return {
        restrict: 'A',
        compile: function(element, attr) {
          var linkFn;
          if (config.enabled) {
            // immediately replace static (non-interpolated) invalid values...

            validateAttributeValue( className,
              getNormalizedAttrValue(className, attr, ""),
              buildUpdateFn(element, className, attr)
            );

            translateToCssClass(null, element);

            // Use for postLink to account for transforms after ng-transclude.
            linkFn = translateToCssClass;
          }

          return linkFn || angular.noop;
        }
      };
    }];

    /**
     * Add as transformed class selector, then
     * remove the deprecated attribute selector
     */
    function translateToCssClass(scope, element) {
      element.addClass(className);

      if (config.removeAttributes) {
        // After link-phase, remove deprecated layout attribute selector
        element.removeAttr(className);
      }
    }
  }

  /**
   * After link-phase, do NOT remove deprecated layout attribute selector.
   * Instead watch the attribute so interpolated data-bindings to layout
   * selectors will continue to be supported.
   *
   * $observe() the className and update with new class (after removing the last one)
   *
   * e.g. `layout="{{layoutDemo.direction}}"` will update...
   *
   * NOTE: The value must match one of the specified styles in the CSS.
   * For example `flex-gt-md="{{size}}`  where `scope.size == 47` will NOT work since
   * only breakpoints for 0, 5, 10, 15... 100, 33, 34, 66, 67 are defined.
   *
   */
  function updateClassWithValue(element, className) {
    var lastClass;

    return function updateClassFn(newValue) {
      var value = validateAttributeValue(className, newValue || "");
      if ( angular.isDefined(value) ) {
        if (lastClass) {
          element.removeClass(lastClass);
        }
        lastClass = !value ? className : className + "-" + value.replace(WHITESPACE, "-");
        element.addClass(lastClass);
      }
    };
  }

  /**
   * Provide console warning that this layout attribute has been deprecated
   *
   */
  function warnAttrNotSupported(className) {
    var parts = className.split("-");
    return ["$log", function($log) {
      $log.warn(className + "has been deprecated. Please use a `" + parts[0] + "-gt-<xxx>` variant.");
      return angular.noop;
    }];
  }

  /**
   * For the Layout attribute value, validate or replace with default
   * fallback value
   */
  function validateAttributeValue(className, value, updateFn) {
    var origValue = value;

    if (!needsInterpolation(value)) {
      switch (className.replace(SUFFIXES,"")) {
        case 'layout'        :
          if ( !findIn(value, LAYOUT_OPTIONS) ) {
            value = LAYOUT_OPTIONS[0];    // 'row';
          }
          break;

        case 'flex'          :
          if (!findIn(value, FLEX_OPTIONS)) {
            if (isNaN(value)) {
              value = '';
            }
          }
          break;

        case 'flex-offset' :
        case 'flex-order'    :
          if (!value || isNaN(+value)) {
            value = '0';
          }
          break;

        case 'layout-align'  :
          if (!findIn(value, ALIGNMENT_OPTIONS, "-")) {
            value = ALIGNMENT_OPTIONS[0];   // 'start-start';
          }
          break;

        case 'layout-padding' :
        case 'layout-margin'  :
        case 'layout-fill'    :
        case 'layout-wrap'    :
        case 'layout-no-wrap' :
          value = '';
          break;
      }

      if (value != origValue) {
        (updateFn || angular.noop)(value);
      }
    }

    return value;
  }

  /**
   * Replace current attribute value with fallback value
   */
  function buildUpdateFn(element, className, attrs) {
    return function updateAttrValue(fallback) {
      if (!needsInterpolation(fallback)) {
        element.attr(className, fallback);
        attrs[attrs.$normalize(className)] = fallback;
      }
    };
  }

  /**
   * See if the original value has interpolation symbols:
   * e.g.  flex-gt-md="{{triggerPoint}}"
   */
  function needsInterpolation(value) {
    return (value || "").indexOf($interpolate.startSymbol()) > -1;
  }

  function getNormalizedAttrValue(className, attrs, defaultVal) {
    var normalizedAttr = attrs.$normalize(className);
    return attrs[normalizedAttr] ? attrs[normalizedAttr].replace(WHITESPACE, "-") : defaultVal || null;
  }

  function findIn(item, list, replaceWith) {
    item = replaceWith && item ? item.replace(WHITESPACE, replaceWith) : item;

    var found = false;
    if (item) {
      list.forEach(function(it) {
        it = replaceWith ? it.replace(WHITESPACE, replaceWith) : it;
        found = found || (it === item);
      });
    }
    return found;
  }

})();
<|endoftext|>


<commit_before>
import Vue from 'vue';
import vuexI18n from 'vuex-i18n';

import store from '../store';
import locales from './locales';

import fallback from '../assets/i18n/en.json';

Vue.use(vuexI18n.plugin, store);

Vue.i18n.add('en', fallback);
Vue.i18n.set('en');
Vue.i18n.fallback('en');

export default {
    init() {
        let userLang = window.localStorage.getItem('contao_manager_locale');

        if (!userLang) {
            userLang = navigator.language || navigator.userLanguage;
        }

        return this.load(userLang);
    },

    load(locale) {
        window.localStorage.setItem('contao_manager_locale', locale);

        if (Vue.i18n.exists(locale)) {
            Vue.i18n.set(locale);
            return new Promise(resolve => resolve());
        }

        if (!locales[locale]) {
            if (locale.length === 5) {
                return this.load(locale.slice(0, 2));
            }

            return new Promise(resolve => resolve());
        }

        return Vue.http.get(`assets/i18n/${locale}.json`).then(
            response => response.json().then((json) => {
                console.log(json);
                Vue.i18n.add(locale, json);
                Vue.i18n.set(locale);
            }),
            () => {},
        );
    },
};
<commit_msg>Removed unwanted console.log statement<commit_after>
import Vue from 'vue';
import vuexI18n from 'vuex-i18n';

import store from '../store';
import locales from './locales';

import fallback from '../assets/i18n/en.json';

Vue.use(vuexI18n.plugin, store);

Vue.i18n.add('en', fallback);
Vue.i18n.set('en');
Vue.i18n.fallback('en');

export default {
    init() {
        let userLang = window.localStorage.getItem('contao_manager_locale');

        if (!userLang) {
            userLang = navigator.language || navigator.userLanguage;
        }

        return this.load(userLang);
    },

    load(locale) {
        window.localStorage.setItem('contao_manager_locale', locale);

        if (Vue.i18n.exists(locale)) {
            Vue.i18n.set(locale);
            return new Promise(resolve => resolve());
        }

        if (!locales[locale]) {
            if (locale.length === 5) {
                return this.load(locale.slice(0, 2));
            }

            return new Promise(resolve => resolve());
        }

        return Vue.http.get(`assets/i18n/${locale}.json`).then(
            response => response.json().then((json) => {
                Vue.i18n.add(locale, json);
                Vue.i18n.set(locale);
            }),
            () => {},
        );
    },
};
<|endoftext|>


<commit_before>/*!
 * URI.js - Mutating URLs
 * jQuery Plugin
 *
 * Version: [dev-version]
 *
 * Author: Rodney Rehm
 * Web: http://medialize.github.com/URI.js/jquery-uri-plugin.html
 *
 * Licensed under
 *   MIT License http://www.opensource.org/licenses/mit-license
 *   GPL v3 http://opensource.org/licenses/GPL-3.0
 *
 */

(function (root, factory) {
    // https://github.com/umdjs/umd/blob/master/returnExports.js
    if (typeof exports === 'object') {
        // Node
        module.exports = factory(require('jquery', './URI'));
    } else if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery', './URI'], factory);
    } else {
        // Browser globals (root is window)
        factory(root.jQuery, root.URI);
    }
}(this, function ($, URI) {
"use strict";

var comparable = {};
var compare = {
    // equals
    '=': function(value, target) {
        return value === target;
    },
    // ~= translates to value.match((?:^|\s)target(?:\s|$)) which is useless for URIs
    // |= translates to value.match((?:\b)target(?:-|\s|$)) which is useless for URIs
    // begins with
    '^=': function(value, target, property) {
        return !!(value + "").match(new RegExp('^' + escapeRegEx(target), 'i'));
    },
    // ends with
    '$=': function(value, target, property) {
        return !!(value + "").match(new RegExp(escapeRegEx(target) + '$', 'i'));
    },
    // contains
    '*=': function(value, target, property) {
        if (property == 'directory') {
            // add trailing slash so /dir/ will match the deep-end as well
            value += '/';
        }

        return !!(value + "").match(new RegExp(escapeRegEx(target), 'i'));
    },
    'equals:': function(uri, target) {
        return uri.equals(target);
    },
    'is:': function(uri, target) {
        return uri.is(target);
    }
};

function escapeRegEx(string) {
    // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
    return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}

function getUriProperty(elem) {
    var property;

    // Note: IE9 will report img.href, so check img.src first (Issue #48)
    $.each(['src', 'href', 'action'], function(k, v) {
        if (v in elem ) {
            property = v;
            return false;
        }

        return true;
    });

    // compensate ambiguous <input>
    if (elem.nodeName.toLowerCase() === 'input' && elem.type !== 'image') {
        return undefined;
    }

    if (!property) {
        // you can set any property you wish. So for elements that don't have
        // either of [src, href, action] we simply return src.
        // https://github.com/medialize/URI.js/issues/69
        return 'src';
    }

    return property;
}

function generateAccessor(property) {
    return {
        get: function(elem) {
            return $(elem).uri()[property]();
        },
        set: function(elem, value) {
            $(elem).uri()[property](value);
            return value;
        }
    };
};

// populate lookup table and register $.attr('uri:accessor') handlers
$.each('authority directory domain filename fragment hash host hostname href password path pathname port protocol query resource scheme search subdomain suffix tld username'.split(" "), function(k, v) {
    comparable[v] = true;
    $.attrHooks['uri:' + v] = generateAccessor(v);
});

// pipe $.attr('src') and $.attr('href') through URI.js
var _attrHooks = {
    get: function(elem) {
        return $(elem).uri();
    },
    set: function(elem, value) {
        return $(elem).uri().href(value).toString();
    }
};
$.each(['src', 'href', 'action', 'uri'], function(k, v) {
    $.attrHooks[v] = {
        set: _attrHooks.set
    };
});
$.attrHooks.uri.get = _attrHooks.get;

// general URI accessor
$.fn.uri = function(uri) {
    var $this = this.first();
    var elem = $this.get(0);
    var property = getUriProperty(elem);

    if (!property) {
        throw new Error('Element "' + elem.nodeName + '" does not have either property: href, src, action');
    }

    if (uri !== undefined) {
        var old = $this.data('uri');
        if (old) {
            return old.href(uri);
        }

        if (!(uri instanceof URI)) {
            uri = URI(uri || '');
        }
    } else {
        uri = $this.data('uri');
        if (uri) {
            return uri;
        } else {
    		uri = URI($this.attr(property) || '');
        }
    }

    uri._dom_element = elem;
    uri._dom_attribute = property;
    uri.normalize();
    $this.data('uri', uri);
    return uri;
};

// overwrite URI.build() to update associated DOM element if necessary
URI.prototype.build = function(deferBuild) {
    if (this._dom_element) {
        // cannot defer building when hooked into a DOM element
        this._string = URI.build(this._parts);
        this._deferred_build = false;
        this._dom_element.setAttribute(this._dom_attribute, this._string);
        this._dom_element[this._dom_attribute] = this._string;
    } else if (deferBuild === true) {
        this._deferred_build = true;
    } else if (deferBuild === undefined || this._deferred_build) {
        this._string = URI.build(this._parts);
        this._deferred_build = false;
    }

    return this;
};

// add :uri() pseudo class selector to sizzle
var uriSizzle;
var pseudoArgs = /^([a-zA-Z]+)\s*([\^\$*]?=|:)\s*(['"]?)(.+)\3|^\s*([a-zA-Z0-9]+)\s*$/;
function uriPseudo (elem, text) {
    var match, property, uri;

    // skip anything without src|href|action and bad :uri() syntax
    if (!getUriProperty(elem) || !text) {
        return false;
    }

    match = text.match(pseudoArgs);

    if (!match || (!match[5] && match[2] !== ':' && !compare[match[2]])) {
        // abort because the given selector cannot be executed
        // filers seem to fail silently
        return false;
    }

    uri = $(elem).uri();

    if (match[5]) {
        return uri.is(match[5]);
    } else if (match[2] === ':') {
        property = match[1].toLowerCase() + ':';
        if (!compare[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[property](uri, match[4]);
    } else {
        property = match[1].toLowerCase();
        if (!comparable[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[match[2]](uri[property](), match[4], property);
    }

    return false;
}

if ($.expr.createPseudo) {
    // jQuery >= 1.8
    uriSizzle = $.expr.createPseudo(function (text) {
        return function (elem) {
            return uriPseudo(elem, text);
        };
    });
} else {
    // jQuery < 1.8
    uriSizzle = function (elem, i, match) {
        return uriPseudo(elem, match[3]);
    };
}

$.expr[":"].uri = uriSizzle;

// extending existing object rather than defining something new
return {};
}));
<commit_msg>optimizing jquery.URI.js to use new DOM element mapping<commit_after>/*!
 * URI.js - Mutating URLs
 * jQuery Plugin
 *
 * Version: [dev-version]
 *
 * Author: Rodney Rehm
 * Web: http://medialize.github.com/URI.js/jquery-uri-plugin.html
 *
 * Licensed under
 *   MIT License http://www.opensource.org/licenses/mit-license
 *   GPL v3 http://opensource.org/licenses/GPL-3.0
 *
 */

(function (root, factory) {
    // https://github.com/umdjs/umd/blob/master/returnExports.js
    if (typeof exports === 'object') {
        // Node
        module.exports = factory(require('jquery', './URI'));
    } else if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery', './URI'], factory);
    } else {
        // Browser globals (root is window)
        factory(root.jQuery, root.URI);
    }
}(this, function ($, URI) {
"use strict";

var comparable = {};
var compare = {
    // equals
    '=': function(value, target) {
        return value === target;
    },
    // ~= translates to value.match((?:^|\s)target(?:\s|$)) which is useless for URIs
    // |= translates to value.match((?:\b)target(?:-|\s|$)) which is useless for URIs
    // begins with
    '^=': function(value, target, property) {
        return !!(value + "").match(new RegExp('^' + escapeRegEx(target), 'i'));
    },
    // ends with
    '$=': function(value, target, property) {
        return !!(value + "").match(new RegExp(escapeRegEx(target) + '$', 'i'));
    },
    // contains
    '*=': function(value, target, property) {
        if (property == 'directory') {
            // add trailing slash so /dir/ will match the deep-end as well
            value += '/';
        }

        return !!(value + "").match(new RegExp(escapeRegEx(target), 'i'));
    },
    'equals:': function(uri, target) {
        return uri.equals(target);
    },
    'is:': function(uri, target) {
        return uri.is(target);
    }
};

function escapeRegEx(string) {
    // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
    return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}

function getUriProperty(elem) {
    var nodeName = elem.nodeName.toLowerCase();
    var property = URI.domAttributes[nodeName];
    if (nodeName === 'input' && elem.type !== 'image') {
        // compensate ambiguous <input> that is not an image
        return undefined;
    }

    // NOTE: as we use a static mapping from element to attribute,
    // the HTML5 attribute issue should not come up again
    // https://github.com/medialize/URI.js/issues/69
    return property;
}

function generateAccessor(property) {
    return {
        get: function(elem) {
            return $(elem).uri()[property]();
        },
        set: function(elem, value) {
            $(elem).uri()[property](value);
            return value;
        }
    };
};

// populate lookup table and register $.attr('uri:accessor') handlers
$.each('authority directory domain filename fragment hash host hostname href password path pathname port protocol query resource scheme search subdomain suffix tld username'.split(" "), function(k, v) {
    comparable[v] = true;
    $.attrHooks['uri:' + v] = generateAccessor(v);
});

// pipe $.attr('src') and $.attr('href') through URI.js
var _attrHooks = {
    get: function(elem) {
        return $(elem).uri();
    },
    set: function(elem, value) {
        return $(elem).uri().href(value).toString();
    }
};
$.each(['src', 'href', 'action', 'uri', 'cite'], function(k, v) {
    $.attrHooks[v] = {
        set: _attrHooks.set
    };
});
$.attrHooks.uri.get = _attrHooks.get;

// general URI accessor
$.fn.uri = function(uri) {
    var $this = this.first();
    var elem = $this.get(0);
    var property = getUriProperty(elem);

    if (!property) {
        throw new Error('Element "' + elem.nodeName + '" does not have either property: href, src, action, cite');
    }

    if (uri !== undefined) {
        var old = $this.data('uri');
        if (old) {
            return old.href(uri);
        }

        if (!(uri instanceof URI)) {
            uri = URI(uri || '');
        }
    } else {
        uri = $this.data('uri');
        if (uri) {
            return uri;
        } else {
    		uri = URI($this.attr(property) || '');
        }
    }

    uri._dom_element = elem;
    uri._dom_attribute = property;
    uri.normalize();
    $this.data('uri', uri);
    return uri;
};

// overwrite URI.build() to update associated DOM element if necessary
URI.prototype.build = function(deferBuild) {
    if (this._dom_element) {
        // cannot defer building when hooked into a DOM element
        this._string = URI.build(this._parts);
        this._deferred_build = false;
        this._dom_element.setAttribute(this._dom_attribute, this._string);
        this._dom_element[this._dom_attribute] = this._string;
    } else if (deferBuild === true) {
        this._deferred_build = true;
    } else if (deferBuild === undefined || this._deferred_build) {
        this._string = URI.build(this._parts);
        this._deferred_build = false;
    }

    return this;
};

// add :uri() pseudo class selector to sizzle
var uriSizzle;
var pseudoArgs = /^([a-zA-Z]+)\s*([\^\$*]?=|:)\s*(['"]?)(.+)\3|^\s*([a-zA-Z0-9]+)\s*$/;
function uriPseudo (elem, text) {
    var match, property, uri;

    // skip anything without src|href|action and bad :uri() syntax
    if (!getUriProperty(elem) || !text) {
        return false;
    }

    match = text.match(pseudoArgs);

    if (!match || (!match[5] && match[2] !== ':' && !compare[match[2]])) {
        // abort because the given selector cannot be executed
        // filers seem to fail silently
        return false;
    }

    uri = $(elem).uri();

    if (match[5]) {
        return uri.is(match[5]);
    } else if (match[2] === ':') {
        property = match[1].toLowerCase() + ':';
        if (!compare[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[property](uri, match[4]);
    } else {
        property = match[1].toLowerCase();
        if (!comparable[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[match[2]](uri[property](), match[4], property);
    }

    return false;
}

if ($.expr.createPseudo) {
    // jQuery >= 1.8
    uriSizzle = $.expr.createPseudo(function (text) {
        return function (elem) {
            return uriPseudo(elem, text);
        };
    });
} else {
    // jQuery < 1.8
    uriSizzle = function (elem, i, match) {
        return uriPseudo(elem, match[3]);
    };
}

$.expr[":"].uri = uriSizzle;

// extending existing object rather than defining something new
return {};
}));
<|endoftext|>


<commit_before>tabs = {};
tabIds = [];

var tableTemplate = null;

var extractAttribute = function(tab, attribute) {
	switch (attribute) {
		case 'title':
			return tab.title;
		case 'domain':
			var uri = new URI(tab.url);
			return uri.domain();
	}
};

// TODO: This is a terrible implementation
var keyerParams = {};
var currentKeyer = function() {
	var keyer = $('#keying_function').val();
	keyerParams = {};
	switch (keyer) {
		case 'fingerprint':
			return new FingerprintKeyer();
		case 'ngram-fingerprint':
			keyerParams = { size: parseInt($('#ngram_size').val(), 10) };
			return new NGramFingerprintKeyer();
	}
};

// -----
// On load + clustering method/keying function change
// -----
// Get all tabs title
// Run clustering method
// Store results (if clustering is to be applied)
// Display results
var clusters = {};
var updateClustering = function() {
	clusters = {};
	var currentAttribute = $('#attribute').val();
	var tabsAttribute = {};
	chrome.windows.getAll({ populate: true }, function(windows) {
		_.forEach(windows, function(window) {
			_.forEach(window.tabs, function(tab) {
				// Collect all tabs
				// TODO: Put this somewhere else?
				tabs[tab.id] = tab;

				tabsAttribute[tab.id] = extractAttribute(tab, currentAttribute);
			});
		});

		var keyer = currentKeyer();
		_.forEach(tabsAttribute, function(attribute, tabId) {
			var cluster = keyer.key(attribute, keyerParams);
			if (!clusters[cluster]) {
				clusters[cluster] = [];
			}
			clusters[cluster].push(tabs[tabId]);
		});

		//console.dir(clusters);

		$('#data').html(tableTemplate({currentAttribute: currentAttribute}));

		$('.btn-cluster').click(function(e) {
			e.preventDefault();

			var $this = $(this);
			applyClustering($this.data('id'));
		});
	});
};

// -----
// Apply clustering
// -----
// Get cluster id
// Get all tabs
// Create new window
// Move all tabs to new window
var applyClustering = function(clusterId) {
	var tabs = clusters[clusterId];
	var tabsId = _.pluck(tabs, 'id');
	chrome.windows.create({ tabId: _.first(tabsId) }, function(window) {
		chrome.tabs.move(_.rest(tabsId), { windowId: window.id, index: -1 });
	});
};

var bootstrap = function() {
	restoreLastOptions();
	updateMenuVisibility();
	$.get('/views/table.html').done(function(data) {
		tableTemplate = _.template(data);
		updateClustering();
		$('#options select, #options input').change(function() {
			// Save option
			var $this = $(this);
			var id = $this.attr('id');
			localStorage[id] = $this.val();
			console.log('Saved '+id+' = '+$this.val());

			updateMenuVisibility();
			updateClustering();
		});
	});
};

var restoreLastOptions = function() {
	// Set last options
	var options = ['method', 'keying_function', 'attribute', 'ngram_size'];
	_.forEach(options, function(option) {
		if (localStorage[option]) {
			var value = localStorage[option];
			console.log('Restoring '+option+' = '+value);
			$('#'+option).val(value);
		}
	});
};

var updateMenuVisibility = function() {
	var method = $('#method').val();
	var keying_function = $('#keying_function').val();
	$('.key_collision').hide();
	$('.nearest_neighbor').hide();
	$('.ngram_fingerprint_params').hide();
	$('.'+method).show();
	if (keying_function === 'ngram-fingerprint') {
		$('.ngram_fingerprint_params').show();
	}
};

document.addEventListener('DOMContentLoaded', function() {
	bootstrap();
});
<commit_msg>Update clustering when tabs are created, updated or removed.<commit_after>tabs = {};
tabIds = [];

var tableTemplate = null;

var extractAttribute = function(tab, attribute) {
	switch (attribute) {
		case 'title':
			return tab.title;
		case 'domain':
			var uri = new URI(tab.url);
			return uri.domain();
	}
};

// TODO: This is a terrible implementation
var keyerParams = {};
var currentKeyer = function() {
	var keyer = $('#keying_function').val();
	keyerParams = {};
	switch (keyer) {
		case 'fingerprint':
			return new FingerprintKeyer();
		case 'ngram-fingerprint':
			keyerParams = { size: parseInt($('#ngram_size').val(), 10) };
			return new NGramFingerprintKeyer();
	}
};

// -----
// On load + clustering method/keying function change
// -----
// Get all tabs title
// Run clustering method
// Store results (if clustering is to be applied)
// Display results
var clusters = {};
var updateClustering = function() {
	clusters = {};
	var currentAttribute = $('#attribute').val();
	var tabsAttribute = {};
	chrome.windows.getAll({ populate: true }, function(windows) {
		_.forEach(windows, function(window) {
			_.forEach(window.tabs, function(tab) {
				// Collect all tabs
				// TODO: Put this somewhere else?
				tabs[tab.id] = tab;

				tabsAttribute[tab.id] = extractAttribute(tab, currentAttribute);
			});
		});

		var keyer = currentKeyer();
		_.forEach(tabsAttribute, function(attribute, tabId) {
			var cluster = keyer.key(attribute, keyerParams);
			if (!clusters[cluster]) {
				clusters[cluster] = [];
			}
			clusters[cluster].push(tabs[tabId]);
		});

		//console.dir(clusters);

		$('#data').html(tableTemplate({currentAttribute: currentAttribute}));

		$('.btn-cluster').click(function(e) {
			e.preventDefault();

			var $this = $(this);
			applyClustering($this.data('id'));
		});
	});
};

// -----
// Apply clustering
// -----
// Get cluster id
// Get all tabs
// Create new window
// Move all tabs to new window
var applyClustering = function(clusterId) {
	var tabs = clusters[clusterId];
	var tabsId = _.pluck(tabs, 'id');
	chrome.windows.create({ tabId: _.first(tabsId) }, function(window) {
		chrome.tabs.move(_.rest(tabsId), { windowId: window.id, index: -1 });
	});
};

var bootstrap = function() {
	restoreLastOptions();
	updateMenuVisibility();
	$.get('/views/table.html').done(function(data) {
		tableTemplate = _.template(data);
		updateClustering();
		$('#options select, #options input').change(function() {
			// Save option
			var $this = $(this);
			var id = $this.attr('id');
			localStorage[id] = $this.val();
			console.log('Saved '+id+' = '+$this.val());

			updateMenuVisibility();
			updateClustering();
		});
	});

	chrome.tabs.onCreated.addListener(updateClustering);
	chrome.tabs.onUpdated.addListener(updateClustering);
	chrome.tabs.onRemoved.addListener(updateClustering);
};

var restoreLastOptions = function() {
	// Set last options
	var options = ['method', 'keying_function', 'attribute', 'ngram_size'];
	_.forEach(options, function(option) {
		if (localStorage[option]) {
			var value = localStorage[option];
			console.log('Restoring '+option+' = '+value);
			$('#'+option).val(value);
		}
	});
};

var updateMenuVisibility = function() {
	var method = $('#method').val();
	var keying_function = $('#keying_function').val();
	$('.key_collision').hide();
	$('.nearest_neighbor').hide();
	$('.ngram_fingerprint_params').hide();
	$('.'+method).show();
	if (keying_function === 'ngram-fingerprint') {
		$('.ngram_fingerprint_params').show();
	}
};

document.addEventListener('DOMContentLoaded', function() {
	bootstrap();
});
<|endoftext|>


<commit_before>/* global window, document, chrome, location, history, top */

let collapserElements, jsonObject, jsonSelector, jsonPath, selectedListItem, hoveredListItem, originalBody;
chrome.runtime.onMessage.addListener(message => {
	if (message.copyText) {
		copyText(message.value);
	}
});
if (document.body && (document.body.childNodes[0] && document.body.childNodes[0].tagName == "PRE" || document.body.children.length == 0)) {
	const child = document.body.children.length ? document.body.childNodes[0] : document.body;
	const data = extractData(child.innerText);
	if (data) {
		originalBody = document.body.cloneNode(true);
		chrome.runtime.sendMessage({ init: true }, options => processData(data, options));
	}
}

function extractData(rawText) {
	const text = rawText.trim();
	let tokens;
	if (test(text)) {
		return {
			text: rawText,
			offset: 0
		};
	} else {
		tokens = text.match(/^([^\s(]*)\s*\(([\s\S]*)\)\s*;?$/);
		if (tokens && tokens[1] && tokens[2]) {
			if (test(tokens[2].trim())) {
				return {
					fnName: tokens[1],
					text: tokens[2],
					offset: rawText.indexOf(tokens[2])
				};
			}
		}
	}

	function test(text) {
		return ((text.charAt(0) == "[" && text.charAt(text.length - 1) == "]") || (text.charAt(0) == "{" && text.charAt(text.length - 1) == "}"));
	}
}

function processData(data, options) {
	if ((window == top || options.injectInFrame) && data && data.text) {
		const json = data.text;
		chrome.runtime.sendMessage({
			jsonToHTML: true,
			json,
			fnName: data.fnName,
			offset: data.offset
		}, result => {
			if (result.html) {
				displayUI(result.theme, result.html);
			}
			if (result.error) {
				displayError(result.error, result.loc, result.offset);
			}
		});
		try {
			jsonObject = JSON.parse(json);
		} catch (error) {
			// ignored
		}
	}
}

function displayError(error, loc, offset) {
	const link = document.createElement("link");
	const pre = document.body.firstChild.firstChild;
	const text = pre.textContent.substring(offset);
	const range = document.createRange();
	const imgError = document.createElement("img");
	const content = document.createElement("div");
	const errorPosition = document.createElement("span");
	const container = document.createElement("div");
	const closeButton = document.createElement("div");
	const ranges = [];
	let startRange = 0, indexRange = 0;
	link.rel = "stylesheet";
	link.type = "text/css";
	link.href = chrome.runtime.getURL("css/content-error.css");
	document.head.appendChild(link);
	while (indexRange != -1) {
		indexRange = text.indexOf("\n", startRange);
		ranges.push(startRange);
		startRange = indexRange + 1;
	}
	startRange = ranges[loc.first_line - 1] + loc.first_column + offset;
	const endRange = ranges[loc.last_line - 1] + loc.last_column + offset;
	range.setStart(pre, startRange);
	if (startRange == endRange - 1) {
		range.setEnd(pre, startRange);
	} else {
		range.setEnd(pre, endRange);
	}
	errorPosition.className = "error-position";
	errorPosition.id = "error-position";
	range.surroundContents(errorPosition);
	imgError.src = chrome.runtime.getURL("resources/error-icon.gif");
	errorPosition.insertBefore(imgError, errorPosition.firstChild);
	content.className = "content";
	closeButton.className = "close-error";
	closeButton.onclick = () => content.parentElement.removeChild(content);
	content.textContent = error;
	content.appendChild(closeButton);
	container.className = "container";
	container.appendChild(content);
	errorPosition.parentNode.insertBefore(container, errorPosition.nextSibling);
	location.hash = "error-position";
	history.replaceState({}, "", "#");
}

function displayUI(theme, html) {
	const baseStyleElement = document.createElement("link");
	const userStyleElement = document.createElement("style");
	const statusElement = document.createElement("div");
	const copyPathElement = document.createElement("div");
	const toolboxElement = document.createElement("div");
	const expandElement = document.createElement("span");
	const viewSourceElement = document.createElement("a");
	const reduceElement = document.createElement("span");
	baseStyleElement.rel = "stylesheet";
	baseStyleElement.type = "text/css";
	baseStyleElement.href = chrome.runtime.getURL("css/jsonvue-core.css");
	document.head.appendChild(baseStyleElement);
	userStyleElement.appendChild(document.createTextNode(theme));
	document.head.appendChild(userStyleElement);
	document.body.innerHTML = html;
	collapserElements = document.querySelectorAll("#json .collapsible .collapsible");
	statusElement.className = "status";
	copyPathElement.className = "copy-path";
	statusElement.appendChild(copyPathElement);
	document.body.appendChild(statusElement);
	toolboxElement.className = "toolbox";
	expandElement.title = "expand all";
	expandElement.innerText = "+";
	viewSourceElement.title = "view source";
	viewSourceElement.innerText = "view source";
	reduceElement.title = "reduce all";
	reduceElement.innerText = "-";
	toolboxElement.appendChild(expandElement);
	toolboxElement.appendChild(viewSourceElement);
	toolboxElement.appendChild(reduceElement);
	document.body.appendChild(toolboxElement);
	document.body.addEventListener("click", onToggle, false);
	document.body.addEventListener("mouseover", onMouseMove, false);
	document.body.addEventListener("click", onMouseClick, false);
	document.body.addEventListener("contextmenu", onContextMenu, false);
	expandElement.addEventListener("click", onExpandAll, false);
	viewSourceElement.addEventListener("click", onViewSource, false);
	reduceElement.addEventListener("click", onCollapseAll, false);
	copyPathElement.addEventListener("click", event => {
		if (event.isTrusted) {
			chrome.runtime.sendMessage({
				copyPropertyPath: true,
				path: statusElement.innerText
			});
		}
	}, false);
}

function onToggle(event) {
	const target = event.target;
	if (target.className == "collapser") {
		const collapsed = target.parentNode.getElementsByClassName("collapsible")[0];
		collapsed.parentNode.classList.toggle("collapsed");
	}
}

function onExpandAll() {
	collapserElements.forEach(collapsed => collapsed.parentNode.classList.remove("collapsed"));
}

function onCollapseAll() {
	collapserElements.forEach(collapsed => collapsed.parentNode.classList.add("collapsed"));
}

function onViewSource() {
	document.body.replaceWith(originalBody);
}

function onMouseMove(event) {
	if (event.isTrusted) {
		const statusElement = document.querySelector(".status");
		jsonPath = "";
		let element = getParentListItem(event.target);
		if (element) {
			jsonSelector = [];
			if (hoveredListItem) {
				hoveredListItem.firstChild.classList.remove("hovered");
			}
			hoveredListItem = element;
			element.firstChild.classList.add("hovered");
			do {
				if (element.parentNode.classList.contains("array")) {
					const index = [].indexOf.call(element.parentNode.children, element);
					jsonPath = "[" + index + "]" + jsonPath;
					jsonSelector.unshift(index);
				}
				if (element.parentNode.classList.contains("obj")) {
					const key = element.firstChild.firstChild.innerText;
					jsonPath = "." + key + jsonPath;
					jsonSelector.unshift(key);
				}
				element = element.parentNode.parentNode.parentNode;
			} while (element.tagName == "LI");
			if (jsonPath.charAt(0) == ".") {
				jsonPath = jsonPath.substring(1);
			}
			statusElement.innerText = jsonPath;
		} else if (hoveredListItem) {
			hoveredListItem.firstChild.classList.remove("hovered");
			hoveredListItem = null;
			statusElement.innerText = "";
			jsonSelector = [];
		}
	}
}

function onMouseClick(event) {
	if (selectedListItem) {
		selectedListItem.firstChild.classList.remove("selected");
	}
	selectedListItem = getParentListItem(event.target);
	if (selectedListItem) {
		selectedListItem.firstChild.classList.add("selected");
	}
}

function onContextMenu(event) {
	if (event.isTrusted) {
		const currentListItem = getParentListItem(event.target);
		if (currentListItem) {
			let value = jsonObject;
			jsonSelector.forEach(propertyName => value = value[propertyName]);
			chrome.runtime.sendMessage({
				copyPropertyPath: true,
				path: jsonPath,
				value: typeof value == "object" ? JSON.stringify(value) : value
			});
		} else {
			chrome.runtime.sendMessage({
				copyPropertyPath: true,
				path: "",
				value: typeof jsonObject == "object" ? JSON.stringify(jsonObject) : jsonObject
			});
		}
	}
}

function getParentListItem(element) {
	if (element.tagName != "LI") {
		while (element && element.tagName != "LI") {
			element = element.parentNode;
		}
	}
	if (element && element.tagName == "LI") {
		return element;
	}
}

function copyText(value) {
	const command = "copy";
	document.addEventListener(command, listener);
	document.execCommand(command);
	document.removeEventListener(command, listener);

	function listener(event) {
		event.clipboardData.setData("text/plain", value);
		event.preventDefault();
	}
}<commit_msg>add constants<commit_after>/* global window, document, chrome, location, history, top */

const CLASS_COLLAPSED = "collapsed";
const CLASS_HOVERED = "hovered";
const CLASS_SELECTED = "selected";
const TAG_LIST_ITEM = "LI";

let collapserElements, statusElement, jsonObject, jsonSelector, jsonPath, selectedListItem, hoveredListItem, originalBody;
chrome.runtime.onMessage.addListener(message => {
	if (message.copyText) {
		copyText(message.value);
	}
});
if (document.body && (document.body.childNodes[0] && document.body.childNodes[0].tagName == "PRE" || document.body.children.length == 0)) {
	const child = document.body.children.length ? document.body.childNodes[0] : document.body;
	const data = extractData(child.innerText);
	if (data) {
		originalBody = document.body.cloneNode(true);
		chrome.runtime.sendMessage({ init: true }, options => processData(data, options));
	}
}

function extractData(rawText) {
	const text = rawText.trim();
	let tokens;
	if (test(text)) {
		return {
			text: rawText,
			offset: 0
		};
	} else {
		tokens = text.match(/^([^\s(]*)\s*\(([\s\S]*)\)\s*;?$/);
		if (tokens && tokens[1] && tokens[2]) {
			if (test(tokens[2].trim())) {
				return {
					fnName: tokens[1],
					text: tokens[2],
					offset: rawText.indexOf(tokens[2])
				};
			}
		}
	}

	function test(text) {
		return ((text.charAt(0) == "[" && text.charAt(text.length - 1) == "]") || (text.charAt(0) == "{" && text.charAt(text.length - 1) == "}"));
	}
}

function processData(data, options) {
	if ((window == top || options.injectInFrame) && data && data.text) {
		const json = data.text;
		chrome.runtime.sendMessage({
			jsonToHTML: true,
			json,
			fnName: data.fnName,
			offset: data.offset
		}, result => {
			if (result.html) {
				displayUI(result.theme, result.html);
			}
			if (result.error) {
				displayError(result.error, result.loc, result.offset);
			}
		});
		try {
			jsonObject = JSON.parse(json);
		} catch (error) {
			// ignored
		}
	}
}

function displayError(error, loc, offset) {
	const link = document.createElement("link");
	const pre = document.body.firstChild.firstChild;
	const text = pre.textContent.substring(offset);
	const range = document.createRange();
	const imgError = document.createElement("img");
	const content = document.createElement("div");
	const errorPosition = document.createElement("span");
	const container = document.createElement("div");
	const closeButton = document.createElement("div");
	const ranges = [];
	let startRange = 0, indexRange = 0;
	link.rel = "stylesheet";
	link.type = "text/css";
	link.href = chrome.runtime.getURL("css/content-error.css");
	document.head.appendChild(link);
	while (indexRange != -1) {
		indexRange = text.indexOf("\n", startRange);
		ranges.push(startRange);
		startRange = indexRange + 1;
	}
	startRange = ranges[loc.first_line - 1] + loc.first_column + offset;
	const endRange = ranges[loc.last_line - 1] + loc.last_column + offset;
	range.setStart(pre, startRange);
	if (startRange == endRange - 1) {
		range.setEnd(pre, startRange);
	} else {
		range.setEnd(pre, endRange);
	}
	errorPosition.className = "error-position";
	errorPosition.id = "error-position";
	range.surroundContents(errorPosition);
	imgError.src = chrome.runtime.getURL("resources/error-icon.gif");
	errorPosition.insertBefore(imgError, errorPosition.firstChild);
	content.className = "content";
	closeButton.className = "close-error";
	closeButton.onclick = () => content.parentElement.removeChild(content);
	content.textContent = error;
	content.appendChild(closeButton);
	container.className = "container";
	container.appendChild(content);
	errorPosition.parentNode.insertBefore(container, errorPosition.nextSibling);
	location.hash = "error-position";
	history.replaceState({}, "", "#");
}

function displayUI(theme, html) {
	const baseStyleElement = document.createElement("link");
	const userStyleElement = document.createElement("style");
	const copyPathElement = document.createElement("div");
	const toolboxElement = document.createElement("div");
	const expandElement = document.createElement("span");
	const viewSourceElement = document.createElement("a");
	const reduceElement = document.createElement("span");
	statusElement = document.createElement("div");
	baseStyleElement.rel = "stylesheet";
	baseStyleElement.type = "text/css";
	baseStyleElement.href = chrome.runtime.getURL("css/jsonvue-core.css");
	document.head.appendChild(baseStyleElement);
	userStyleElement.appendChild(document.createTextNode(theme));
	document.head.appendChild(userStyleElement);
	document.body.innerHTML = html;
	collapserElements = document.querySelectorAll("#json .collapsible .collapsible");
	statusElement.className = "status";
	copyPathElement.className = "copy-path";
	statusElement.appendChild(copyPathElement);
	document.body.appendChild(statusElement);
	toolboxElement.className = "toolbox";
	expandElement.title = "expand all";
	expandElement.innerText = "+";
	viewSourceElement.title = "view source";
	viewSourceElement.innerText = "view source";
	reduceElement.title = "reduce all";
	reduceElement.innerText = "-";
	toolboxElement.appendChild(expandElement);
	toolboxElement.appendChild(viewSourceElement);
	toolboxElement.appendChild(reduceElement);
	document.body.appendChild(toolboxElement);
	document.body.addEventListener("click", onToggle, false);
	document.body.addEventListener("mouseover", onMouseMove, false);
	document.body.addEventListener("click", onMouseClick, false);
	document.body.addEventListener("contextmenu", onContextMenu, false);
	expandElement.addEventListener("click", onExpandAll, false);
	viewSourceElement.addEventListener("click", onViewSource, false);
	reduceElement.addEventListener("click", onCollapseAll, false);
	copyPathElement.addEventListener("click", event => {
		if (event.isTrusted) {
			chrome.runtime.sendMessage({
				copyPropertyPath: true,
				path: statusElement.innerText
			});
		}
	}, false);
}

function onToggle(event) {
	const target = event.target;
	if (target.className == "collapser") {
		const collapsed = target.parentNode.getElementsByClassName("collapsible")[0];
		collapsed.parentNode.classList.toggle(CLASS_COLLAPSED);
	}
}

function onExpandAll() {
	collapserElements.forEach(collapsed => collapsed.parentNode.classList.remove(CLASS_COLLAPSED));
}

function onCollapseAll() {
	collapserElements.forEach(collapsed => collapsed.parentNode.classList.add(CLASS_COLLAPSED));
}

function onViewSource() {
	document.body.replaceWith(originalBody);
}

function onMouseMove(event) {
	if (event.isTrusted) {
		jsonPath = "";
		let element = getParentListItem(event.target);
		if (element) {
			jsonSelector = [];
			if (hoveredListItem) {
				hoveredListItem.firstChild.classList.remove(CLASS_HOVERED);
			}
			hoveredListItem = element;
			element.firstChild.classList.add(CLASS_HOVERED);
			do {
				if (element.parentNode.classList.contains("array")) {
					const index = [].indexOf.call(element.parentNode.children, element);
					jsonPath = "[" + index + "]" + jsonPath;
					jsonSelector.unshift(index);
				}
				if (element.parentNode.classList.contains("obj")) {
					const key = element.firstChild.firstChild.innerText;
					jsonPath = "." + key + jsonPath;
					jsonSelector.unshift(key);
				}
				element = element.parentNode.parentNode.parentNode;
			} while (element.tagName == TAG_LIST_ITEM);
			if (jsonPath.charAt(0) == ".") {
				jsonPath = jsonPath.substring(1);
			}
			statusElement.innerText = jsonPath;
		} else if (hoveredListItem) {
			hoveredListItem.firstChild.classList.remove(CLASS_HOVERED);
			hoveredListItem = null;
			statusElement.innerText = "";
			jsonSelector = [];
		}
	}
}

function onMouseClick(event) {
	if (selectedListItem) {
		selectedListItem.firstChild.classList.remove(CLASS_SELECTED);
	}
	selectedListItem = getParentListItem(event.target);
	if (selectedListItem) {
		selectedListItem.firstChild.classList.add(CLASS_SELECTED);
	}
}

function onContextMenu(event) {
	if (event.isTrusted) {
		const currentListItem = getParentListItem(event.target);
		if (currentListItem) {
			let value = jsonObject;
			jsonSelector.forEach(propertyName => value = value[propertyName]);
			chrome.runtime.sendMessage({
				copyPropertyPath: true,
				path: jsonPath,
				value: typeof value == "object" ? JSON.stringify(value) : value
			});
		} else {
			chrome.runtime.sendMessage({
				copyPropertyPath: true,
				path: "",
				value: typeof jsonObject == "object" ? JSON.stringify(jsonObject) : jsonObject
			});
		}
	}
}

function getParentListItem(element) {
	if (element.tagName != TAG_LIST_ITEM) {
		while (element && element.tagName != TAG_LIST_ITEM) {
			element = element.parentNode;
		}
	}
	if (element && element.tagName == TAG_LIST_ITEM) {
		return element;
	}
}

function copyText(value) {
	const command = "copy";
	document.addEventListener(command, listener);
	document.execCommand(command);
	document.removeEventListener(command, listener);

	function listener(event) {
		event.clipboardData.setData("text/plain", value);
		event.preventDefault();
	}
}<|endoftext|>