Use webpack

This change adds webpack as the main tool used while developing the
extension. The extension has been minimally refactored so it works with
webpack, with the intention of refactoring it even further in follow-up
CLs in order to improve the file/folder structure of the project and its
readibility.

Bug: translateselectedtext:5
Change-Id: I89d7422e38fdaf46661c96527c51aa4436ad8056
diff --git a/src/background.js b/src/background.js
index 1770c14..286ec97 100644
--- a/src/background.js
+++ b/src/background.js
@@ -1,3 +1,5 @@
+import {convertLanguages, isoLangs} from './common/consts.js';
+
 var array_elements = [], translator_tab = null, translator_window = null;
 
 function isEmpty(obj) {
diff --git a/src/js/common.js b/src/common/consts.js
similarity index 98%
rename from src/js/common.js
rename to src/common/consts.js
index 45410ba..7b1ef78 100644
--- a/src/js/common.js
+++ b/src/common/consts.js
@@ -1,4 +1,4 @@
-var isoLangs = {
+export const isoLangs = {
   'af': {'name': 'Afrikaans', 'nativeName': 'Afrikaans'},
   'ak': {'name': 'Twi', 'nativeName': 'Akan'},
   'am': {'name': 'Amharic', 'nativeName': 'አማርኛ'},
@@ -136,7 +136,7 @@
 
 // Some languages were incorrectly set. This map serves as a conversion between
 // the previous wrong languages and the correct code.
-var convertLanguages = {
+export const convertLanguages = {
   'jv': 'jw',
   'zh': 'zh-CN',
 };
diff --git a/src/js/sortable.js b/src/js/sortable.js
deleted file mode 100644
index 524e118..0000000
--- a/src/js/sortable.js
+++ /dev/null
@@ -1,783 +0,0 @@
-/**!
- * Sortable
- * @author	RubaXa   <trash@rubaxa.org>
- * @license MIT
- */
-
-
-(function (factory){
-	"use strict";
-
-	if( typeof define === "function" && define.amd ){
-		define(factory);
-	}
-	else if( typeof module != "undefined" && typeof module.exports != "undefined" ){
-		module.exports = factory();
-	}
-	else {
-		window["Sortable"] = factory();
-	}
-})(function (){
-	"use strict";
-
-	var
-		  dragEl
-		, ghostEl
-		, cloneEl
-		, rootEl
-		, nextEl
-
-		, lastEl
-		, lastCSS
-
-		, activeGroup
-
-		, tapEvt
-		, touchEvt
-
-		, expando = 'Sortable' + (new Date).getTime()
-
-		, win = window
-		, document = win.document
-		, parseInt = win.parseInt
-		, supportIEdnd = !!document.createElement('div').dragDrop
-
-		, _silent = false
-
-		, _dispatchEvent = function (rootEl, name, targetEl, fromEl) {
-			var evt = document.createEvent('Event');
-
-			evt.initEvent(name, true, true);
-			evt.item = targetEl || rootEl;
-			evt.from = fromEl || rootEl;
-
-			rootEl.dispatchEvent(evt);
-		}
-
-		, _customEvents = 'onAdd onUpdate onRemove onStart onEnd onFilter onSort'.split(' ')
-
-		, noop = function (){}
-		, slice = [].slice
-
-		, touchDragOverListeners = []
-	;
-
-
-
-	/**
-	 * @class  Sortable
-	 * @param  {HTMLElement}  el
-	 * @param  {Object}       [options]
-	 */
-	function Sortable(el, options){
-		this.el = el; // root element
-		this.options = options = (options || {});
-
-
-		// Default options
-		var defaults = {
-			group: Math.random(),
-			sort: true,
-			store: null,
-			handle: null,
-			draggable: el.children[0] && el.children[0].nodeName || (/[uo]l/i.test(el.nodeName) ? 'li' : '*'),
-			ghostClass: 'sortable-ghost',
-			ignore: 'a, img',
-			filter: null,
-			animation: 0
-		};
-
-
-		// Set default options
-		for (var name in defaults) {
-			!(name in options) && (options[name] = defaults[name]);
-		}
-
-
-		if (!options.group.name) {
-			options.group = { name: options.group };
-		}
-
-
-		['pull', 'put'].forEach(function (key) {
-			if (!(key in options.group)) {
-				options.group[key] = true;
-			}
-		});
-
-
-		// Define events
-		_customEvents.forEach(function (name) {
-			options[name] = _bind(this, options[name] || noop);
-			_on(el, name.substr(2).toLowerCase(), options[name]);
-		}, this);
-
-
-		// Export group name
-		el[expando] = options.group.name;
-
-
-		// Bind all private methods
-		for( var fn in this ){
-			if( fn.charAt(0) === '_' ){
-				this[fn] = _bind(this, this[fn]);
-			}
-		}
-
-
-		// Bind events
-		_on(el, 'mousedown', this._onTapStart);
-		_on(el, 'touchstart', this._onTapStart);
-		supportIEdnd && _on(el, 'selectstart', this._onTapStart);
-
-		_on(el, 'dragover', this._onDragOver);
-		_on(el, 'dragenter', this._onDragOver);
-
-		touchDragOverListeners.push(this._onDragOver);
-
-		// Restore sorting
-		options.store && this.sort(options.store.get(this));
-	}
-
-
-	Sortable.prototype = /** @lends Sortable.prototype */ {
-		constructor: Sortable,
-
-
-		_applyEffects: function (){
-			_toggleClass(dragEl, this.options.ghostClass, true);
-		},
-
-
-		_onTapStart: function (evt/**Event|TouchEvent*/){
-			var
-				  touch = evt.touches && evt.touches[0]
-				, target = (touch || evt).target
-				, options =  this.options
-				, el = this.el
-				, filter = options.filter
-			;
-
-			if( evt.type === 'mousedown' && evt.button !== 0 ) {
-				return; // only left button
-			}
-
-			// Check filter
-			if( typeof filter === 'function' ){
-				if( filter.call(this, target, this) ){
-					_dispatchEvent(el, 'filter', target);
-					return; // cancel dnd
-				}
-			}
-			else if( filter ){
-				filter = filter.split(',').filter(function (criteria) {
-					return _closest(target, criteria.trim(), el);
-				});
-
-				if (filter.length) {
-					_dispatchEvent(el, 'filter', target);
-					return; // cancel dnd
-				}
-			}
-
-			if( options.handle ){
-				target = _closest(target, options.handle, el);
-			}
-
-			target = _closest(target, options.draggable, el);
-
-			// IE 9 Support
-			if( target && evt.type == 'selectstart' ){
-				if( target.tagName != 'A' && target.tagName != 'IMG'){
-					target.dragDrop();
-				}
-			}
-
-			if( target && !dragEl && (target.parentNode === el) ){
-				tapEvt = evt;
-
-				rootEl = this.el;
-				dragEl = target;
-				nextEl = dragEl.nextSibling;
-				activeGroup = this.options.group;
-
-				dragEl.draggable = true;
-
-				// Disable "draggable"
-				options.ignore.split(',').forEach(function (criteria) {
-					_find(target, criteria.trim(), _disableDraggable);
-				});
-
-				if( touch ){
-					// Touch device support
-					tapEvt = {
-						  target:  target
-						, clientX: touch.clientX
-						, clientY: touch.clientY
-					};
-
-					this._onDragStart(tapEvt, true);
-					evt.preventDefault();
-				}
-
-				_on(document, 'mouseup', this._onDrop);
-				_on(document, 'touchend', this._onDrop);
-				_on(document, 'touchcancel', this._onDrop);
-
-				_on(this.el, 'dragstart', this._onDragStart);
-				_on(this.el, 'dragend', this._onDrop);
-				_on(document, 'dragover', _globalDragOver);
-
-
-				try {
-					if( document.selection ){
-						document.selection.empty();
-					} else {
-						window.getSelection().removeAllRanges()
-					}
-				} catch (err){ }
-
-
-				_dispatchEvent(dragEl, 'start');
-
-
-				cloneEl = dragEl.cloneNode(true);
-				_css(cloneEl, 'display', 'none');
-				rootEl.insertBefore(cloneEl, dragEl);
-			}
-		},
-
-		_emulateDragOver: function (){
-			if( touchEvt ){
-				_css(ghostEl, 'display', 'none');
-
-				var
-					  target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY)
-					, parent = target
-					, groupName = this.options.group.name
-					, i = touchDragOverListeners.length
-				;
-
-				if( parent ){
-					do {
-						if( parent[expando] === groupName ){
-							while( i-- ){
-								touchDragOverListeners[i]({
-									clientX: touchEvt.clientX,
-									clientY: touchEvt.clientY,
-									target: target,
-									rootEl: parent
-								});
-							}
-							break;
-						}
-
-						target = parent; // store last element
-					}
-					while( parent = parent.parentNode );
-				}
-
-				_css(ghostEl, 'display', '');
-			}
-		},
-
-
-		_onTouchMove: function (evt/**TouchEvent*/){
-			if( tapEvt ){
-				var
-					  touch = evt.touches[0]
-					, dx = touch.clientX - tapEvt.clientX
-					, dy = touch.clientY - tapEvt.clientY
-					, translate3d = 'translate3d(' + dx + 'px,' + dy + 'px,0)'
-				;
-
-				touchEvt = touch;
-
-				_css(ghostEl, 'webkitTransform', translate3d);
-				_css(ghostEl, 'mozTransform', translate3d);
-				_css(ghostEl, 'msTransform', translate3d);
-				_css(ghostEl, 'transform', translate3d);
-
-				evt.preventDefault();
-			}
-		},
-
-
-		_onDragStart: function (evt/**Event*/, isTouch/**Boolean*/){
-			var dataTransfer = evt.dataTransfer;
-
-			this._offUpEvents();
-
-			if( isTouch ){
-				var
-					  rect = dragEl.getBoundingClientRect()
-					, css = _css(dragEl)
-					, ghostRect
-				;
-
-				ghostEl = dragEl.cloneNode(true);
-
-				_css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
-				_css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
-				_css(ghostEl, 'width', rect.width);
-				_css(ghostEl, 'height', rect.height);
-				_css(ghostEl, 'opacity', '0.8');
-				_css(ghostEl, 'position', 'fixed');
-				_css(ghostEl, 'zIndex', '100000');
-
-				rootEl.appendChild(ghostEl);
-
-				// Fixing dimensions.
-				ghostRect = ghostEl.getBoundingClientRect();
-				_css(ghostEl, 'width', rect.width*2 - ghostRect.width);
-				_css(ghostEl, 'height', rect.height*2 - ghostRect.height);
-
-				// Bind touch events
-				_on(document, 'touchmove', this._onTouchMove);
-				_on(document, 'touchend', this._onDrop);
-				_on(document, 'touchcancel', this._onDrop);
-
-				this._loopId = setInterval(this._emulateDragOver, 150);
-			}
-			else {
-				dataTransfer.effectAllowed = 'move';
-				dataTransfer.setData('Text', dragEl.textContent);
-
-				_on(document, 'drop', this._onDrop);
-			}
-
-			setTimeout(this._applyEffects);
-		},
-
-
-		_onDragOver: function (evt/**Event*/){
-			var el = this.el,
-				target,
-				dragRect,
-				revert,
-				options = this.options,
-				group = options.group,
-				groupPut = group.put,
-				isOwner = (activeGroup === group);
-
-			if( !_silent &&
-				(activeGroup.name === group.name || groupPut && groupPut.indexOf && groupPut.indexOf(activeGroup.name) > -1) &&
-				(isOwner && (options.sort || (revert = !rootEl.contains(dragEl))) || groupPut && activeGroup.pull) &&
-				(evt.rootEl === void 0 || evt.rootEl === this.el)
-			){
-				target = _closest(evt.target, this.options.draggable, el);
-				dragRect = dragEl.getBoundingClientRect();
-
-				if ((activeGroup.pull == 'clone') && (cloneEl.state !== isOwner)) {
-					_css(cloneEl, 'display', isOwner ? 'none' : '');
-					!isOwner && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl);
-					cloneEl.state = isOwner;
-				}
-
-				if (revert) {
-					rootEl.insertBefore(dragEl, cloneEl);
-					return;
-				}
-
-				if( (el.children.length === 0) || (el.children[0] === ghostEl) ||
-					(el === evt.target) && _ghostInBottom(el, evt)
-				){
-					target && (targetRect = target.getBoundingClientRect());
-
-					el.appendChild(dragEl);
-					this._animate(dragRect, dragEl);
-					target && this._animate(targetRect, target);
-				}
-				else if( target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0) ){
-					if( lastEl !== target ){
-						lastEl = target;
-						lastCSS = _css(target);
-					}
-
-
-					var   targetRect = target.getBoundingClientRect()
-						, width = targetRect.right - targetRect.left
-						, height = targetRect.bottom - targetRect.top
-						, floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display)
-						, isWide = (target.offsetWidth > dragEl.offsetWidth)
-						, isLong = (target.offsetHeight > dragEl.offsetHeight)
-						, halfway = (floating ? (evt.clientX - targetRect.left)/width : (evt.clientY - targetRect.top)/height) > .5
-						, nextSibling = target.nextElementSibling
-						, after
-					;
-
-					_silent = true;
-					setTimeout(_unsilent, 30);
-
-					if( floating ){
-						after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide
-					} else {
-						after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
-					}
-
-					if( after && !nextSibling ){
-						el.appendChild(dragEl);
-					} else {
-						target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
-					}
-					
-					this._animate(dragRect, dragEl);
-					this._animate(targetRect, target);
-				}
-			}
-		},
-
-		_animate: function (prevRect, target) {
-			var ms = this.options.animation;
-
-			if (ms) {
-				var currentRect = target.getBoundingClientRect();
-
-				_css(target, 'transition', 'none');
-				_css(target, 'transform', 'translate3d('
-					+ (prevRect.left - currentRect.left) + 'px,'
-					+ (prevRect.top - currentRect.top) + 'px,0)'
-				);
-
-				target.offsetWidth; // repaint
-
-				_css(target, 'transition', 'all ' + ms + 'ms');
-				_css(target, 'transform', 'translate3d(0,0,0)');
-
-				clearTimeout(target.animated);
-				target.animated = setTimeout(function () {
-					_css(target, 'transition', '');
-					target.animated = false;
-				}, ms);
-			}
-		},
-
-		_offUpEvents: function () {
-			_off(document, 'mouseup', this._onDrop);
-			_off(document, 'touchmove', this._onTouchMove);
-			_off(document, 'touchend', this._onDrop);
-			_off(document, 'touchcancel', this._onDrop);
-		},
-
-		_onDrop: function (evt/**Event*/){
-			clearInterval(this._loopId);
-
-			// Unbind events
-			_off(document, 'drop', this._onDrop);
-			_off(document, 'dragover', _globalDragOver);
-
-			_off(this.el, 'dragend', this._onDrop);
-			_off(this.el, 'dragstart', this._onDragStart);
-			_off(this.el, 'selectstart', this._onTapStart);
-
-			this._offUpEvents();
-
-			if( evt ){
-				evt.preventDefault();
-				evt.stopPropagation();
-
-				cloneEl.parentNode.removeChild(cloneEl);
-				ghostEl && ghostEl.parentNode.removeChild(ghostEl);
-
-				if( dragEl ){
-					_disableDraggable(dragEl);
-					_toggleClass(dragEl, this.options.ghostClass, false);
-
-					if( !rootEl.contains(dragEl) ){
-						_dispatchEvent(dragEl, 'sort');
-						_dispatchEvent(rootEl, 'sort');
-
-						// Add event
-						_dispatchEvent(dragEl, 'add', dragEl, rootEl);
-
-						// Remove event
-						_dispatchEvent(rootEl, 'remove', dragEl);
-					}
-					else if( dragEl.nextSibling !== nextEl ){
-						// Update event
-						_dispatchEvent(dragEl, 'update');
-						_dispatchEvent(dragEl, 'sort');
-					}
-
-					_dispatchEvent(rootEl, 'end');
-				}
-
-				// Set NULL
-				rootEl =
-				dragEl =
-				ghostEl =
-				nextEl =
-				cloneEl =
-
-				tapEvt =
-				touchEvt =
-
-				lastEl =
-				lastCSS =
-
-				activeGroup = null;
-
-				// Save sorting
-				this.options.store && this.options.store.set(this);
-			}
-		},
-
-
-		/**
-		 * Serializes the item into an array of string.
-		 * @returns {String[]}
-		 */
-		toArray: function () {
-			var order = [],
-				el,
-				children = this.el.children,
-				i = 0,
-				n = children.length
-			;
-
-			for (; i < n; i++) {
-				el = children[i];
-				if (_closest(el, this.options.draggable, this.el)) {
-					order.push(el.getAttribute('data-id') || _generateId(el));
-				}
-			}
-
-			return order;
-		},
-
-
-		/**
-		 * Sorts the elements according to the array.
-		 * @param  {String[]}  order  order of the items
-		 */
-		sort: function (order) {
-			var items = {}, rootEl = this.el;
-
-			this.toArray().forEach(function (id, i) {
-				var el = rootEl.children[i];
-
-				if (_closest(el, this.options.draggable, rootEl)) {
-					items[id] = el;
-				}
-			}, this);
-
-
-			order.forEach(function (id) {
-				if (items[id]) {
-					rootEl.removeChild(items[id]);
-					rootEl.appendChild(items[id]);
-				}
-			});
-		},
-
-
-		/**
-		 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
-		 * @param   {HTMLElement}  el
-		 * @param   {String}       [selector]  default: `options.draggable`
-		 * @returns {HTMLElement|null}
-		 */
-		closest: function (el, selector) {
-			return _closest(el, selector || this.options.draggable, this.el);
-		},
-
-
-		/**
-		 * Destroy
-		 */
-		destroy: function () {
-			var el = this.el, options = this.options;
-
-			_customEvents.forEach(function (name) {
-				_off(el, name.substr(2).toLowerCase(), options[name]);
-			});
-
-			_off(el, 'mousedown', this._onTapStart);
-			_off(el, 'touchstart', this._onTapStart);
-			_off(el, 'selectstart', this._onTapStart);
-
-			_off(el, 'dragover', this._onDragOver);
-			_off(el, 'dragenter', this._onDragOver);
-
-			//remove draggable attributes
-			Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function(el) {
-				el.removeAttribute('draggable');
-			});
-
-			touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
-
-			this._onDrop();
-
-			this.el = null;
-		}
-	};
-
-
-	function _bind(ctx, fn){
-		var args = slice.call(arguments, 2);
-		return	fn.bind ? fn.bind.apply(fn, [ctx].concat(args)) : function (){
-			return fn.apply(ctx, args.concat(slice.call(arguments)));
-		};
-	}
-
-
-	function _closest(el, selector, ctx){
-		if( selector === '*' ){
-			return el;
-		}
-		else if( el ){
-			ctx = ctx || document;
-			selector = selector.split('.');
-
-			var
-				  tag = selector.shift().toUpperCase()
-				, re = new RegExp('\\s('+selector.join('|')+')\\s', 'g')
-			;
-
-			do {
-				if(
-					   (tag === '' || el.nodeName == tag)
-					&& (!selector.length || ((' '+el.className+' ').match(re) || []).length == selector.length)
-				){
-					return	el;
-				}
-			}
-			while( el !== ctx && (el = el.parentNode) );
-		}
-
-		return	null;
-	}
-
-
-	function _globalDragOver(evt){
-		evt.dataTransfer.dropEffect = 'move';
-		evt.preventDefault();
-	}
-
-
-	function _on(el, event, fn){
-		el.addEventListener(event, fn, false);
-	}
-
-
-	function _off(el, event, fn){
-		el.removeEventListener(event, fn, false);
-	}
-
-
-	function _toggleClass(el, name, state){
-		if( el ){
-			if( el.classList ){
-				el.classList[state ? 'add' : 'remove'](name);
-			}
-			else {
-				var className = (' '+el.className+' ').replace(/\s+/g, ' ').replace(' '+name+' ', '');
-				el.className = className + (state ? ' '+name : '')
-			}
-		}
-	}
-
-
-	function _css(el, prop, val){
-		var style = el && el.style;
-
-		if( style ){
-			if( val === void 0 ){
-				if( document.defaultView && document.defaultView.getComputedStyle ){
-					val = document.defaultView.getComputedStyle(el, '');
-				}
-				else if( el.currentStyle ){
-					val	= el.currentStyle;
-				}
-
-				return prop === void 0 ? val : val[prop];
-			}
-			else {
-				if (!(prop in style)) {
-					prop = '-webkit-' + prop;
-				}
-
-				style[prop] = val + (typeof val === 'string' ? '' : 'px');
-			}
-		}
-	}
-
-
-	function _find(ctx, tagName, iterator){
-		if( ctx ){
-			var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
-			if( iterator ){
-				for( ; i < n; i++ ){
-					iterator(list[i], i);
-				}
-			}
-			return	list;
-		}
-		return	[];
-	}
-
-
-	function _disableDraggable(el){
-		return el.draggable = false;
-	}
-
-
-	function _unsilent(){
-		_silent = false;
-	}
-
-
-	function _ghostInBottom(el, evt){
-		var last = el.lastElementChild.getBoundingClientRect();
-		return evt.clientY - (last.top + last.height) > 5; // min delta
-	}
-
-
-	/**
-	 * Generate id
-	 * @param   {HTMLElement} el
-	 * @returns {String}
-	 * @private
-	 */
-	function _generateId(el) {
-		var str = el.tagName + el.className + el.src + el.href + el.textContent,
-			i = str.length,
-			sum = 0
-		;
-
-		while (i--) {
-			sum += str.charCodeAt(i);
-		}
-
-		return sum.toString(36);
-	}
-
-
-	// Export utils
-	Sortable.utils = {
-		on: _on,
-		off: _off,
-		css: _css,
-		find: _find,
-		bind: _bind,
-		closest: _closest,
-		toggleClass: _toggleClass,
-		dispatchEvent: _dispatchEvent
-	};
-
-
-	Sortable.version = '0.6.0';
-
-
-	/**
-	 * Create sortable instance
-	 * @param {HTMLElement}  el
-	 * @param {Object}      [options]
-	 */
-	Sortable.create = function (el, options) {
-		return new Sortable(el, options)
-	};
-
-	// Export
-	return Sortable;
-});
diff --git a/src/js/options.js b/src/options/options.js
similarity index 98%
rename from src/js/options.js
rename to src/options/options.js
index 9fc10df..1d47da6 100644
--- a/src/js/options.js
+++ b/src/options/options.js
@@ -1,3 +1,9 @@
+import Sortable from 'sortablejs/modular/sortable.core.esm.js';
+
+import {isoLangs} from '../common/consts.js';
+
+let sortable;
+
 function $(selector) {
   return document.querySelector(selector);
 }
diff --git a/src/LICENSE b/src/static/LICENSE
similarity index 100%
rename from src/LICENSE
rename to src/static/LICENSE
diff --git a/src/_locales/README.md b/src/static/_locales/README.md
similarity index 100%
rename from src/_locales/README.md
rename to src/static/_locales/README.md
diff --git a/src/_locales/am/messages.json b/src/static/_locales/am/messages.json
similarity index 100%
rename from src/_locales/am/messages.json
rename to src/static/_locales/am/messages.json
diff --git a/src/_locales/ar/messages.json b/src/static/_locales/ar/messages.json
similarity index 100%
rename from src/_locales/ar/messages.json
rename to src/static/_locales/ar/messages.json
diff --git a/src/_locales/bg/messages.json b/src/static/_locales/bg/messages.json
similarity index 100%
rename from src/_locales/bg/messages.json
rename to src/static/_locales/bg/messages.json
diff --git a/src/_locales/bn/messages.json b/src/static/_locales/bn/messages.json
similarity index 100%
rename from src/_locales/bn/messages.json
rename to src/static/_locales/bn/messages.json
diff --git a/src/_locales/ca/messages.json b/src/static/_locales/ca/messages.json
similarity index 100%
rename from src/_locales/ca/messages.json
rename to src/static/_locales/ca/messages.json
diff --git a/src/_locales/cs/messages.json b/src/static/_locales/cs/messages.json
similarity index 100%
rename from src/_locales/cs/messages.json
rename to src/static/_locales/cs/messages.json
diff --git a/src/_locales/de/messages.json b/src/static/_locales/de/messages.json
similarity index 100%
rename from src/_locales/de/messages.json
rename to src/static/_locales/de/messages.json
diff --git a/src/_locales/en/messages.json b/src/static/_locales/en/messages.json
similarity index 100%
rename from src/_locales/en/messages.json
rename to src/static/_locales/en/messages.json
diff --git a/src/_locales/es/messages.json b/src/static/_locales/es/messages.json
similarity index 100%
rename from src/_locales/es/messages.json
rename to src/static/_locales/es/messages.json
diff --git a/src/_locales/et/messages.json b/src/static/_locales/et/messages.json
similarity index 100%
rename from src/_locales/et/messages.json
rename to src/static/_locales/et/messages.json
diff --git a/src/_locales/fa/messages.json b/src/static/_locales/fa/messages.json
similarity index 100%
rename from src/_locales/fa/messages.json
rename to src/static/_locales/fa/messages.json
diff --git a/src/_locales/fil/messages.json b/src/static/_locales/fil/messages.json
similarity index 100%
rename from src/_locales/fil/messages.json
rename to src/static/_locales/fil/messages.json
diff --git a/src/_locales/fr/messages.json b/src/static/_locales/fr/messages.json
similarity index 100%
rename from src/_locales/fr/messages.json
rename to src/static/_locales/fr/messages.json
diff --git a/src/_locales/hi/messages.json b/src/static/_locales/hi/messages.json
similarity index 100%
rename from src/_locales/hi/messages.json
rename to src/static/_locales/hi/messages.json
diff --git a/src/_locales/hr/messages.json b/src/static/_locales/hr/messages.json
similarity index 100%
rename from src/_locales/hr/messages.json
rename to src/static/_locales/hr/messages.json
diff --git a/src/_locales/hu/messages.json b/src/static/_locales/hu/messages.json
similarity index 100%
rename from src/_locales/hu/messages.json
rename to src/static/_locales/hu/messages.json
diff --git a/src/_locales/id/messages.json b/src/static/_locales/id/messages.json
similarity index 100%
rename from src/_locales/id/messages.json
rename to src/static/_locales/id/messages.json
diff --git a/src/_locales/it/messages.json b/src/static/_locales/it/messages.json
similarity index 100%
rename from src/_locales/it/messages.json
rename to src/static/_locales/it/messages.json
diff --git a/src/_locales/nl/messages.json b/src/static/_locales/nl/messages.json
similarity index 100%
rename from src/_locales/nl/messages.json
rename to src/static/_locales/nl/messages.json
diff --git a/src/_locales/pl/messages.json b/src/static/_locales/pl/messages.json
similarity index 100%
rename from src/_locales/pl/messages.json
rename to src/static/_locales/pl/messages.json
diff --git a/src/_locales/pt_BR/messages.json b/src/static/_locales/pt_BR/messages.json
similarity index 100%
rename from src/_locales/pt_BR/messages.json
rename to src/static/_locales/pt_BR/messages.json
diff --git a/src/_locales/pt_PT/messages.json b/src/static/_locales/pt_PT/messages.json
similarity index 100%
rename from src/_locales/pt_PT/messages.json
rename to src/static/_locales/pt_PT/messages.json
diff --git a/src/_locales/ro/messages.json b/src/static/_locales/ro/messages.json
similarity index 100%
rename from src/_locales/ro/messages.json
rename to src/static/_locales/ro/messages.json
diff --git a/src/_locales/ru/messages.json b/src/static/_locales/ru/messages.json
similarity index 100%
rename from src/_locales/ru/messages.json
rename to src/static/_locales/ru/messages.json
diff --git a/src/_locales/sk/messages.json b/src/static/_locales/sk/messages.json
similarity index 100%
rename from src/_locales/sk/messages.json
rename to src/static/_locales/sk/messages.json
diff --git a/src/_locales/sl/messages.json b/src/static/_locales/sl/messages.json
similarity index 100%
rename from src/_locales/sl/messages.json
rename to src/static/_locales/sl/messages.json
diff --git a/src/_locales/tr/messages.json b/src/static/_locales/tr/messages.json
similarity index 100%
rename from src/_locales/tr/messages.json
rename to src/static/_locales/tr/messages.json
diff --git a/src/_locales/uk/messages.json b/src/static/_locales/uk/messages.json
similarity index 100%
rename from src/_locales/uk/messages.json
rename to src/static/_locales/uk/messages.json
diff --git a/src/_locales/zh_CN/messages.json b/src/static/_locales/zh_CN/messages.json
similarity index 100%
rename from src/_locales/zh_CN/messages.json
rename to src/static/_locales/zh_CN/messages.json
diff --git a/src/_locales/zh_TW/messages.json b/src/static/_locales/zh_TW/messages.json
similarity index 100%
rename from src/_locales/zh_TW/messages.json
rename to src/static/_locales/zh_TW/messages.json
diff --git a/src/css/options.css b/src/static/css/options.css
similarity index 100%
rename from src/css/options.css
rename to src/static/css/options.css
diff --git a/src/css/widgets.css b/src/static/css/widgets.css
similarity index 100%
rename from src/css/widgets.css
rename to src/static/css/widgets.css
diff --git a/src/json/credits.json b/src/static/json/credits.json
similarity index 100%
rename from src/json/credits.json
rename to src/static/json/credits.json
diff --git a/src/json/i18n-credits.json b/src/static/json/i18n-credits.json
similarity index 100%
rename from src/json/i18n-credits.json
rename to src/static/json/i18n-credits.json
diff --git a/src/options.html b/src/static/options.html
similarity index 96%
rename from src/options.html
rename to src/static/options.html
index 5ef8a20..fa82672 100644
--- a/src/options.html
+++ b/src/static/options.html
@@ -65,8 +65,7 @@
     </div>
   </dialog>
 
-  <script src="js/common.js"></script>
-  <script src="js/options.js"></script>
+  <script src="options.bundle.js"></script>
   <script src="js/sortable.js"></script>
 </body>